<commit_before>package com.dtflys.forest.reflection;

import com.dtflys.forest.annotation.BaseLifeCycle;
import com.dtflys.forest.annotation.MethodLifeCycle;
import com.dtflys.forest.annotation.ParamLifeCycle;
import com.dtflys.forest.annotation.RequestAttributes;
import com.dtflys.forest.backend.ContentType;
import com.dtflys.forest.callback.OnError;
import com.dtflys.forest.callback.OnLoadCookie;
import com.dtflys.forest.callback.OnProgress;
import com.dtflys.forest.callback.OnSaveCookie;
import com.dtflys.forest.callback.OnSuccess;
import com.dtflys.forest.config.ForestConfiguration;
import com.dtflys.forest.config.VariableScope;
import com.dtflys.forest.converter.ForestConverter;
import com.dtflys.forest.converter.json.ForestJsonConverter;
import com.dtflys.forest.exceptions.ForestInterceptorDefineException;
import com.dtflys.forest.exceptions.ForestRuntimeException;
import com.dtflys.forest.filter.Filter;
import com.dtflys.forest.http.ForestQueryParameter;
import com.dtflys.forest.http.ForestRequest;
import com.dtflys.forest.http.ForestRequestType;
import com.dtflys.forest.http.ObjectRequestBody;
import com.dtflys.forest.http.StringRequestBody;
import com.dtflys.forest.interceptor.Interceptor;
import com.dtflys.forest.interceptor.InterceptorAttributes;
import com.dtflys.forest.interceptor.InterceptorFactory;
import com.dtflys.forest.lifecycles.BaseAnnotationLifeCycle;
import com.dtflys.forest.lifecycles.MethodAnnotationLifeCycle;
import com.dtflys.forest.lifecycles.ParameterAnnotationLifeCycle;
import com.dtflys.forest.lifecycles.method.RequestLifeCycle;
import com.dtflys.forest.logging.DefaultLogHandler;
import com.dtflys.forest.logging.LogConfiguration;
import com.dtflys.forest.logging.ForestLogHandler;
import com.dtflys.forest.mapping.MappingParameter;
import com.dtflys.forest.mapping.MappingTemplate;
import com.dtflys.forest.mapping.MappingVariable;
import com.dtflys.forest.mapping.SubVariableScope;
import com.dtflys.forest.multipart.ForestMultipart;
import com.dtflys.forest.multipart.ForestMultipartFactory;
import com.dtflys.forest.proxy.InterfaceProxyHandler;
import com.dtflys.forest.retryer.Retryer;
import com.dtflys.forest.ssl.SSLKeyStore;
import com.dtflys.forest.utils.ForestDataType;
import com.dtflys.forest.utils.NameUtils;
import com.dtflys.forest.utils.ReflectUtils;
import com.dtflys.forest.utils.RequestNameValue;
import com.dtflys.forest.utils.StringUtils;
import com.dtflys.forest.utils.URLUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;

import static com.dtflys.forest.mapping.MappingParameter.*;

/**
 * 通过代理调用的实际执行的方法对象
 * @author gongjun
 * @since 2016-05-03
 */
public class ForestMethod<T> implements VariableScope {

    private final InterfaceProxyHandler interfaceProxyHandler;
    private final ForestConfiguration configuration;
    private InterceptorFactory interceptorFactory;
    private final Method method;
    private String[] methodNameItems;
    private Class returnClass;
    private Type returnType;
    private MetaRequest metaRequest;
    private MappingTemplate baseUrlTemplate;
    private MappingTemplate urlTemplate;
    private MappingTemplate typeTemplate;
    private MappingTemplate dataTypeTemplate;
    private Integer baseTimeout = null;
    private Integer timeout = null;
    private MappingTemplate sslProtocolTemplate;
    private Class baseRetryerClass = null;
    private Integer baseRetryCount = null;
    private Long baseMaxRetryInterval;
    private Integer retryCount = null;
    private long maxRetryInterval;
    private MappingTemplate baseEncodeTemplate = null;
    private MappingTemplate encodeTemplate = null;
    private MappingTemplate charsetTemplate = null;
    private MappingTemplate baseContentTypeTemplate;
    private MappingTemplate baseUserAgentTemplate;
    private MappingTemplate baseCharsetTemplate;
    private MappingTemplate baseSslProtocolTemplate;
    private MappingTemplate contentTypeTemplate;
    private MappingTemplate userAgentTemplate;
    private long progressStep = -1;
    private ForestConverter decoder = null;
    private MappingTemplate sslKeyStoreId;
    private MappingTemplate[] dataTemplateArray;
    private MappingTemplate[] headerTemplateArray;
    private MappingParameter[] parameterTemplateArray;
    private List<MappingParameter> namedParameters = new ArrayList<>();
    private List<ForestMultipartFactory> multipartFactories = new ArrayList<>();
    private Map<String, MappingVariable> variables = new HashMap<>();
    private MappingParameter onSuccessParameter = null;
    private MappingParameter onErrorParameter = null;
    private MappingParameter onProgressParameter = null;
    private MappingParameter onLoadCookieParameter = null;
    private MappingParameter onSaveCookieParameter = null;
    private List<Interceptor> globalInterceptorList;
    private List<Interceptor> baseInterceptorList;
    private List<Interceptor> interceptorList;
    private List<InterceptorAttributes> interceptorAttributesList;
    private Type onSuccessClassGenericType = null;
    private Class retryerClass = null;
    private boolean async = false;
    private boolean logEnabled = true;
    private boolean logRequest = true;
    private boolean logResponseStatus = true;
    private boolean logResponseContent = false;
    private ForestLogHandler logHandler = new DefaultLogHandler();
    private LogConfiguration logConfiguration = null;

    public ForestMethod(InterfaceProxyHandler interfaceProxyHandler, ForestConfiguration configuration, Method method) {
        this.interfaceProxyHandler = interfaceProxyHandler;
        this.configuration = configuration;
        this.method = method;
        this.interceptorFactory = configuration.getInterceptorFactory();
        this.methodNameItems = NameUtils.splitCamelName(method.getName());
        processBaseProperties();
        processMethodAnnotations();
    }

    @Override
    public ForestConfiguration getConfiguration() {
        return configuration;
    }


    @Override
    public Object getVariableValue(String name) {
        Object value = configuration.getVariableValue(name);
        return value;
    }

    public MappingTemplate makeTemplate(String text) {
        return new MappingTemplate(text, this);
    }


    public Class getReturnClass() {
        return returnClass;
    }


    @Override
    public MappingVariable getVariable(String name) {
        return variables.get(name);
    }

    private void processBaseProperties() {
        MetaRequest baseMetaRequest = interfaceProxyHandler.getBaseMetaRequest();
        String baseUrl = baseMetaRequest.getUrl();
        if (StringUtils.isNotBlank(baseUrl)) {
            baseUrlTemplate = makeTemplate(baseUrl);
        }
        String baseContentEncoding = baseMetaRequest.getContentEncoding();
        if (StringUtils.isNotBlank(baseContentEncoding)) {
            baseEncodeTemplate = makeTemplate(baseContentEncoding);
        }
        String baseContentType = baseMetaRequest.getContentType();
        if (StringUtils.isNotBlank(baseContentType)) {
            baseContentTypeTemplate = makeTemplate(baseContentType);
        }
        String baseUserAgent = baseMetaRequest.getUserAgent();
        if (StringUtils.isNotBlank(baseUserAgent)) {
            baseUserAgentTemplate = makeTemplate(baseUserAgent);
        }
        String baseCharset = baseMetaRequest.getCharset();
        if (StringUtils.isNotBlank(baseCharset)) {
            baseCharsetTemplate = makeTemplate(baseCharset);
        }
        String baseSslProtocol = baseMetaRequest.getSslProtocol();
        if (StringUtils.isNotBlank(baseSslProtocol)) {
            baseSslProtocolTemplate = makeTemplate(baseSslProtocol);
        }
        baseTimeout = baseMetaRequest.getTimeout();
        baseRetryerClass = baseMetaRequest.getRetryer();
        baseRetryCount = baseMetaRequest.getRetryCount();
        baseMaxRetryInterval = baseMetaRequest.getMaxRetryInterval();

        List<Class> globalInterceptorClasses = configuration.getInterceptors();
        if (globalInterceptorClasses != null && globalInterceptorClasses.size() > 0) {
            globalInterceptorList = new LinkedList<>();
            for (Class clazz : globalInterceptorClasses) {
                if (!Interceptor.class.isAssignableFrom(clazz) || clazz.isInterface()) {
                    throw new ForestRuntimeException("Class [" + clazz.getName() + "] is not a implement of [" +
                            Interceptor.class.getName() + "] interface.");
                }
                Interceptor interceptor = interceptorFactory.getInterceptor(clazz);
                globalInterceptorList.add(interceptor);
            }
        }

        Class[] baseInterceptorClasses = baseMetaRequest.getInterceptor();
        if (baseInterceptorClasses != null && baseInterceptorClasses.length > 0) {
            baseInterceptorList = new LinkedList<>();
            for (int cidx = 0, len = baseInterceptorClasses.length; cidx < len; cidx++) {
                Class clazz = baseInterceptorClasses[cidx];
                if (!Interceptor.class.isAssignableFrom(clazz) || clazz.isInterface()) {
                    throw new ForestRuntimeException("Class [" + clazz.getName() + "] is not a implement of [" +
                            Interceptor.class.getName() + "] interface.");
                }
                Interceptor interceptor = interceptorFactory.getInterceptor(clazz);
                baseInterceptorList.add(interceptor);
            }
        }

        List<Annotation> baseAnnotationList = interfaceProxyHandler.getBaseAnnotations();
        Map<Annotation, Class> baseAnnMap = new HashMap<>(baseAnnotationList.size());
        for (Annotation annotation : baseAnnotationList) {
            Class interceptorClass = getAnnotationLifeCycleClass(annotation);
            baseAnnMap.put(annotation, interceptorClass);
        }
        addMetaRequestAnnotations(baseAnnMap);
    }

    private <T extends Interceptor> T addInterceptor(Class<T> interceptorClass) {
        if (interceptorList == null) {
            interceptorList = new LinkedList<>();
        }
        if (!Interceptor.class.isAssignableFrom(interceptorClass) || interceptorClass.isInterface()) {
            throw new ForestRuntimeException("Class [" + interceptorClass.getName() + "] is not a implement of [" +
                    Interceptor.class.getName() + "] interface.");
        }
        T interceptor = interceptorFactory.getInterceptor(interceptorClass);
        interceptorList.add(interceptor);
        return interceptor;
    }


    private Class getAnnotationLifeCycleClass(Annotation annotation) {
        Class<? extends Annotation> annType = annotation.annotationType();
        Class<? extends MethodAnnotationLifeCycle> interceptorClass = null;
        MethodLifeCycle methodLifeCycleAnn = annType.getAnnotation(MethodLifeCycle.class);
        if (methodLifeCycleAnn == null) {
            BaseLifeCycle baseLifeCycle = annType.getAnnotation(BaseLifeCycle.class);
            if (baseLifeCycle != null) {
                Class<? extends BaseAnnotationLifeCycle> baseAnnLifeCycleClass = baseLifeCycle.value();
                if (baseAnnLifeCycleClass != null) {
                    if (MethodAnnotationLifeCycle.class.isAssignableFrom(baseAnnLifeCycleClass)) {
                        interceptorClass = (Class<? extends MethodAnnotationLifeCycle>) baseAnnLifeCycleClass;
                    } else {
                        return baseAnnLifeCycleClass;
                    }
                }
            }
        }
        if (methodLifeCycleAnn != null || interceptorClass != null) {
            if (interceptorClass == null) {
                interceptorClass = methodLifeCycleAnn.value();
                if (!Interceptor.class.isAssignableFrom(interceptorClass)) {
                    throw new ForestInterceptorDefineException(interceptorClass);
                }
            }
        }

        return interceptorClass;
    }

    /**
     * 添加元请求注释表
     * @param annMap 请求注释表
     */
    private void addMetaRequestAnnotations(Map<Annotation, Class> annMap) {
        for (Map.Entry<Annotation, Class> entry : annMap.entrySet()) {
            addMetaRequestAnnotation(entry.getKey(), entry.getValue());
        }
    }

    /**
     * 添加元请求注释
     * @param annotation 注解
     * @param interceptorClass 拦截器类
     */
    private void addMetaRequestAnnotation(Annotation annotation, Class interceptorClass) {
        Class<? extends Annotation> annType = annotation.annotationType();
        RequestAttributes requestAttributesAnn = annType.getAnnotation(RequestAttributes.class);
        if (requestAttributesAnn != null) {
            Map<String, Object> attrTemplates = ReflectUtils.getAttributesFromAnnotation(annotation);
            for (String key : attrTemplates.keySet()) {
                Object value = attrTemplates.get(key);
                if (value instanceof CharSequence) {
                    MappingTemplate template = makeTemplate(value.toString());
                    attrTemplates.put(key, template);
                } else if (String[].class.isAssignableFrom(value.getClass())) {
                    String[] stringArray = (String[]) value;
                    int len = stringArray.length;
                    MappingTemplate[] templates = new MappingTemplate[stringArray.length];
                    for (int i = 0; i < len; i++) {
                        String item = stringArray[i];
                        MappingTemplate template = makeTemplate(item);
                        templates[i] = template;
                    }
                    attrTemplates.put(key, templates);
                }
            }

            InterceptorAttributes attributes = new InterceptorAttributes(interceptorClass, attrTemplates);
            if (interceptorAttributesList == null) {
                interceptorAttributesList = new LinkedList<>();
            }
            interceptorAttributesList.add(attributes);
        }
        Interceptor interceptor = addInterceptor(interceptorClass);
        if (interceptor instanceof MethodAnnotationLifeCycle) {
            MethodAnnotationLifeCycle lifeCycle = (MethodAnnotationLifeCycle) interceptor;
            lifeCycle.onMethodInitialized(this, annotation);
        }
    }


    public void setMetaRequest(MetaRequest metaRequest) {
        if (metaRequest != null && this.metaRequest != null) {
            throw new ForestRuntimeException("[Forest] annotation \""
                    + metaRequest.getRequestAnnotation().annotationType().getName() + "\" can not be added on method \""
                    + method.getName() + "\", because a similar annotation \""
                    + metaRequest.getRequestAnnotation().annotationType().getName() + "\" has already been attached to this method.");
        }
        this.metaRequest = metaRequest;
    }

    /**
     * 获取Forest方法对应的Java原生方法
     * @return Java原生方法，{@link java.lang.reflect.Method}类实例
     */
    public Method getMethod() {
        return method;
    }

    /**
     * 获取方法名
     * @return 方法名字符串
     */
    public String getMethodName() {
        return method.getName();
    }

    /**
     * 获取元请求信息
     * @return 元请求对象，{@link MetaRequest}类实例
     */
    public MetaRequest getMetaRequest() {
        return metaRequest;
    }


    /**
     * 处理方法上的注解列表
     */
    private void processMethodAnnotations() {
        Annotation[] annotations = method.getAnnotations();
        Map<Annotation, Class> requestAnns = new LinkedHashMap();
        Map<Annotation, Class> methodAnns = new LinkedHashMap<>();

        // 对注解分类
        for (int i = 0; i < annotations.length; i++) {
            Annotation ann = annotations[i];
            Class interceptorClass = getAnnotationLifeCycleClass(ann);
            if (interceptorClass == null) {
                continue;
            }
            if (RequestLifeCycle.class.isAssignableFrom(interceptorClass)) {
                requestAnns.put(ann, interceptorClass);
            } else {
                methodAnns.put(ann, interceptorClass);
            }
        }

        // 先添加请求类注解
        addMetaRequestAnnotations(requestAnns);

        // 再添加普通方法类注解
        addMetaRequestAnnotations(methodAnns);

        // 处理请求元信息
        if (this.metaRequest != null) {
            processMetaRequest(this.metaRequest);
        }

        returnClass = method.getReturnType();
    }

    private void processMetaRequest(MetaRequest metaRequest) {
        Class[] paramTypes = method.getParameterTypes();
        Type[] genericParamTypes = method.getGenericParameterTypes();
        Annotation[][] paramAnns = method.getParameterAnnotations();
        Parameter[] parameters = method.getParameters();

        parameterTemplateArray = new MappingParameter[paramTypes.length];
        processParameters(parameters, genericParamTypes, paramAnns);

        urlTemplate = makeTemplate(metaRequest.getUrl());
        typeTemplate = makeTemplate(metaRequest.getType());
        dataTypeTemplate = makeTemplate(metaRequest.getDataType());
        if (StringUtils.isNotEmpty(metaRequest.getContentType())) {
            contentTypeTemplate = makeTemplate(metaRequest.getContentType());
        }
        if (StringUtils.isNotEmpty(metaRequest.getUserAgent())) {
            userAgentTemplate = makeTemplate(metaRequest.getUserAgent());
        }
        sslKeyStoreId = makeTemplate(metaRequest.getKeyStore());
        if (StringUtils.isNotEmpty(metaRequest.getContentEncoding())) {
            encodeTemplate = makeTemplate(metaRequest.getContentEncoding());
        }
        charsetTemplate = makeTemplate(metaRequest.getCharset());
        sslProtocolTemplate = makeTemplate(metaRequest.getSslProtocol());
        progressStep = metaRequest.getProgressStep();
        async = metaRequest.isAsync();
        retryerClass = metaRequest.getRetryer();
        Class decoderClass = metaRequest.getDecoder();
        String[] dataArray = metaRequest.getData();
        String[] headerArray = metaRequest.getHeaders();
        int tout = metaRequest.getTimeout();
        if (tout > 0) {
            timeout = tout;
        }
        int rtnum = metaRequest.getRetryCount();
        if (rtnum > 0) {
            retryCount = rtnum;
        }
        maxRetryInterval = metaRequest.getMaxRetryInterval();
        logEnabled = configuration.isLogEnabled();
        if (!logEnabled) {
            logEnabled = metaRequest.isLogEnabled();
        }
        logRequest = configuration.isLogRequest();
        logResponseStatus = configuration.isLogResponseStatus();
        logResponseContent = configuration.isLogResponseContent();
        logHandler = configuration.getLogHandler();

        LogConfiguration metaLogConfiguration = metaRequest.getLogConfiguration();
        if (metaLogConfiguration != null) {
            logEnabled = metaLogConfiguration.isLogEnabled();
            logRequest = metaLogConfiguration.isLogRequest();
            logResponseStatus = metaLogConfiguration.isLogResponseStatus();
            logResponseContent = metaLogConfiguration.isLogResponseContent();
            logHandler = metaLogConfiguration.getLogHandler();
        }

        logConfiguration = new LogConfiguration();
        logConfiguration.setLogEnabled(logEnabled);
        logConfiguration.setLogRequest(logRequest);
        logConfiguration.setLogResponseStatus(logResponseStatus);
        logConfiguration.setLogResponseContent(logResponseContent);
        logConfiguration.setLogHandler(logHandler);


        dataTemplateArray = new MappingTemplate[dataArray.length];
        for (int j = 0; j < dataArray.length; j++) {
            String data = dataArray[j];
            MappingTemplate dataTemplate = makeTemplate(data);
            dataTemplateArray[j] = dataTemplate;
        }

        headerTemplateArray = new MappingTemplate[headerArray.length];
        for (int j = 0; j < headerArray.length; j++) {
            String header = headerArray[j];
            MappingTemplate headerTemplate = makeTemplate(header);
            headerTemplateArray[j] = headerTemplate;
        }

        Class[] interceptorClasses = metaRequest.getInterceptor();
        if (interceptorClasses != null && interceptorClasses.length > 0) {
            for (int cidx = 0, len = interceptorClasses.length; cidx < len; cidx++) {
                Class interceptorClass = interceptorClasses[cidx];
                addInterceptor(interceptorClass);
            }
        }


        if (decoderClass != null && ForestConverter.class.isAssignableFrom(decoderClass)) {
            try {
                this.decoder = (ForestConverter) decoderClass.newInstance();
            } catch (InstantiationException e) {
                throw new ForestRuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new ForestRuntimeException(e);
            }
        }

    }

    /**
     * 处理参数列表
     * @param parameters 参数数组，{@link Parameter}类数组实例
     * @param genericParamTypes 参数类型数组
     * @param paramAnns 参数注解的二维数组
     */
    private void processParameters(Parameter[] parameters, Type[] genericParamTypes, Annotation[][] paramAnns) {
        for (int i = 0; i < parameters.length; i++) {
            Parameter param = parameters[i];
            Class paramType = param.getType();
            Annotation[] anns = paramAnns[i];
            MappingParameter parameter = new MappingParameter(paramType);
            parameter.setIndex(i);
            parameter.setName(param.getName());
            parameterTemplateArray[i] = parameter;
            if (OnSuccess.class.isAssignableFrom(paramType)) {
                onSuccessParameter = parameter;
                Type genType = genericParamTypes[i];
                onSuccessClassGenericType = getGenericClassOrType(genType, 0);
            } else if (OnError.class.isAssignableFrom(paramType)) {
                onErrorParameter = parameter;
            } else if (OnProgress.class.isAssignableFrom(paramType)) {
                onProgressParameter = parameter;
            } else if (OnSaveCookie.class.isAssignableFrom(paramType)) {
                onSaveCookieParameter = parameter;
            } else if (OnLoadCookie.class.isAssignableFrom(paramType)) {
                onLoadCookieParameter = parameter;
            }
            processParameterAnnotation(parameter, anns);
        }
    }

    /**
     * 处理参数的注解
     * @param parameter 方法参数-字符串模板解析对象，{@link MappingParameter}类实例
     * @param anns 方法参数注解的二维数组
     */
    private void processParameterAnnotation(MappingParameter parameter, Annotation[] anns) {
        for (int i = 0; i < anns.length; i++) {
            Annotation ann = anns[i];
            Class annType = ann.annotationType();
            ParamLifeCycle paramLifeCycleAnn = (ParamLifeCycle) annType.getAnnotation(ParamLifeCycle.class);
            if (paramLifeCycleAnn != null) {
                Class<? extends ParameterAnnotationLifeCycle> interceptorClass = paramLifeCycleAnn.value();
                if (!Interceptor.class.isAssignableFrom(interceptorClass)) {
                    throw new ForestInterceptorDefineException(interceptorClass);
                }
                ParameterAnnotationLifeCycle lifeCycle = addInterceptor(interceptorClass);
                lifeCycle.onParameterInitialized(this, parameter, ann);
            }
        }
    }

    /**
     * 添加命名参数
     * @param parameter 方法参数-字符串模板解析对象，{@link MappingParameter}类实例
     */
    public void addNamedParameter(MappingParameter parameter) {
        namedParameters.add(parameter);
    }

    /**
     * 添加变量
     * @param name 变量名
     * @param variable 变量对象，{@link MappingVariable}类实例
     */
    public void addVariable(String name, MappingVariable variable) {
        variables.put(name, variable);
    }

    /**
     * 添加Forest文件上传用的Mutlipart工厂
     * @param multipartFactory Forest文件上传用的Mutlipart工厂，{@link ForestMultipartFactory}类实例
     */
    public void addMultipartFactory(ForestMultipartFactory multipartFactory) {
        multipartFactories.add(multipartFactory);
    }

    /**
     * 处理参数的过滤器
     * @param parameter 方法参数-字符串模板解析对象，{@link MappingParameter}类实例
     * @param filterName 过滤器名称
     */
    public void processParameterFilter(MappingParameter parameter, String filterName) {
        if (StringUtils.isNotEmpty(filterName)) {
            String[] filterNameArray = filterName.split(",");
            for (String name : filterNameArray) {
                Filter filter = configuration.newFilterInstance(name);
                parameter.addFilter(filter);
            }
        }
    }

    /**
     * 给请求设置重试策略
     * @param retryerClass 重试策略类型
     * @param request Forest请求对象，{@link ForestRequest}类实例
     */
    private void setRetryerToRequest(Class retryerClass, ForestRequest request) {
        try {
            Constructor constructor = retryerClass.getConstructor(ForestRequest.class);
            Retryer retryer = (Retryer) constructor.newInstance(request);
            request.setRetryer(retryer);
        } catch (NoSuchMethodException e) {
            throw new ForestRuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new ForestRuntimeException(e);
        } catch (InstantiationException e) {
            throw new ForestRuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new ForestRuntimeException(e);
        }
    }

    /**
     * 获得最终的请求类型
     * @param args 调用本对象对应方法时传入的参数数组
     * @return 请求类型，{@link ForestRequestType}枚举实例
     */
    private ForestRequestType type(Object[] args) {
        String renderedType = typeTemplate.render(args);
        if (StringUtils.isBlank(renderedType)) {
            String typeFromName = methodNameItems[0];
            ForestRequestType type = ForestRequestType.findType(typeFromName);
            if (type != null) {
                return type;
            }
            return ForestRequestType.GET;
        }
        ForestRequestType type = ForestRequestType.findType(renderedType);
        if (type != null) {
            return type;
        }
        throw new ForestRuntimeException("Http request type \"" + renderedType + "\" is not be supported.");
    }

    /**
     * 创建请求
     * @param args 调用本对象对应方法时传入的参数数组
     * @return Forest请求对象，{@link ForestRequest}类实例
     */
    private ForestRequest makeRequest(Object[] args) {
        MetaRequest baseMetaRequest = interfaceProxyHandler.getBaseMetaRequest();
        String baseUrl = null;
        if (baseUrlTemplate != null) {
            baseUrl = StringUtils.trimBegin(baseUrlTemplate.render(args));
        }
        String renderedUrl = urlTemplate.render(args);
        ForestRequestType type = type(args);
        String baseContentEncoding = null;
        if (baseEncodeTemplate != null) {
            baseContentEncoding = baseEncodeTemplate.render(args);
        }
        String contentEncoding = null;
        if (encodeTemplate != null) {
            contentEncoding = encodeTemplate.render(args);
        }

        String baseContentType = null;
        if (baseContentTypeTemplate != null) {
            baseContentType = baseContentTypeTemplate.render(args);
        }
        String baseUserAgent = null;
        if (baseUserAgentTemplate != null) {
            baseUserAgent = baseUserAgentTemplate.render(args);
        }
        String charset = null;
        String renderedCharset = charsetTemplate.render(args);
        if (StringUtils.isNotBlank(renderedCharset)) {
            charset = renderedCharset;
        } else if (baseCharsetTemplate != null) {
            charset = baseCharsetTemplate.render(args);
        } else if (StringUtils.isNotBlank(configuration.getCharset())) {
            charset = configuration.getCharset();
        } else {
            charset = "UTF-8";
        }

        String sslProtocol = null;
        String renderedSslProtocol = sslProtocolTemplate.render(args);
        if (StringUtils.isNotBlank(renderedSslProtocol)) {
            sslProtocol = renderedSslProtocol;
        } else if (baseSslProtocolTemplate != null) {
            sslProtocol = baseSslProtocolTemplate.render(args);
        } else {
            sslProtocol = configuration.getSslProtocol();
        }

        String renderedContentType = null;
        if (contentTypeTemplate != null) {
            renderedContentType = contentTypeTemplate.render(args).trim();
        }
        String renderedUserAgent = null;
        if (userAgentTemplate != null) {
            renderedUserAgent = userAgentTemplate.render(args).trim();
        }
        String newUrl = null;
        List<RequestNameValue> nameValueList = new ArrayList<>();
//        List<Object> bodyList = new ArrayList<>();
        String [] headerArray = baseMetaRequest.getHeaders();
        MappingTemplate[] baseHeaders = null;
        if (headerArray != null && headerArray.length > 0) {
            baseHeaders = new MappingTemplate[headerArray.length];
            for (int j = 0; j < baseHeaders.length; j++) {
                MappingTemplate header = new MappingTemplate(headerArray[j], this);
                baseHeaders[j] = header;
            }
        }

        renderedUrl = URLUtils.getValidURL(baseUrl, renderedUrl);

        // createExecutor and initialize http instance
        ForestRequest<T> request = new ForestRequest(configuration, this, args);
        request.setUrl(renderedUrl)
                .setType(type)
                .setCharset(charset)
                .setSslProtocol(sslProtocol)
                .setLogConfiguration(logConfiguration)
                .setAsync(async);

        if (StringUtils.isNotEmpty(renderedContentType)) {
            request.setContentType(renderedContentType);
        }

        if (StringUtils.isNotEmpty(contentEncoding)) {
            request.setContentEncoding(contentEncoding);
        }

        if (StringUtils.isNotEmpty(renderedUserAgent)) {
            request.setUserAgent(renderedUserAgent);
        }

        for (int i = 0; i < namedParameters.size(); i++) {
            MappingParameter parameter = namedParameters.get(i);
            if (parameter.isObjectProperties()) {
                int target = parameter.isUnknownTarget() ? type.getDefaultParamTarget() : parameter.getTarget();
                Object obj = args[parameter.getIndex()];
                if (parameter.isJsonParam()) {
                    String  json = "";
                    if (obj != null) {
                        ForestJsonConverter jsonConverter = configuration.getJsonConverter();
                        obj = parameter.getFilterChain().doFilter(configuration, obj);
                        json = jsonConverter.encodeToString(obj);
                    }
                    if (MappingParameter.isHeader(target)) {
                        request.addHeader(new RequestNameValue(parameter.getJsonParamName(), json, target));
                    } else {
                        nameValueList.add(new RequestNameValue(parameter.getJsonParamName(), json, target, parameter.getPartContentType()));
                    }
                }
                else if (!parameter.getFilterChain().isEmpty()) {
                    obj = parameter.getFilterChain().doFilter(configuration, obj);
                    if (obj != null) {
                        if (MappingParameter.isHeader(target)) {
                            request.addHeader(new RequestNameValue(null, obj, target));
                        } else if (MappingParameter.isQuery(target)) {
                            request.addQuery(obj.toString(), null);
                        } else if (MappingParameter.isBody(target)) {
                            if (obj instanceof CharSequence) {
                                request.addBody(new StringRequestBody(obj.toString()));
                            } else {
                                request.addBody(new ObjectRequestBody(obj));
                            }
                        } else {
                            nameValueList.add(new RequestNameValue(obj.toString(), target, parameter.getPartContentType()));
                        }
                    }
                }
                else if (obj instanceof CharSequence) {
                    if (MappingParameter.isQuery(target)) {
                        request.addQuery(ForestQueryParameter.createSimpleQueryParameter(obj));
                    } else if (MappingParameter.isBody(target)) {
                        request.addBody(new StringRequestBody(obj.toString()));
                    }
                }
                else if (obj instanceof Iterable
                        || obj.getClass().isArray()
                        || ReflectUtils.isPrimaryType(obj.getClass())) {
                    if (MappingParameter.isQuery(target)) {
                        if (parameter.isJsonParam()) {
                            request.addQuery(parameter.getName(), obj);
                        } else {
                            if (obj instanceof Iterable) {
                                for (Object subItem : (Iterable) obj) {
                                    if (subItem instanceof ForestQueryParameter) {
                                        request.addQuery((ForestQueryParameter) subItem);
                                    } else {
                                        request.addQuery(ForestQueryParameter.createSimpleQueryParameter(subItem));
                                    }
                                }<commit_msg>update: 设置defaultValue属性<commit_after>package com.dtflys.forest.reflection;

import com.dtflys.forest.annotation.BaseLifeCycle;
import com.dtflys.forest.annotation.MethodLifeCycle;
import com.dtflys.forest.annotation.ParamLifeCycle;
import com.dtflys.forest.annotation.RequestAttributes;
import com.dtflys.forest.backend.ContentType;
import com.dtflys.forest.callback.OnError;
import com.dtflys.forest.callback.OnLoadCookie;
import com.dtflys.forest.callback.OnProgress;
import com.dtflys.forest.callback.OnSaveCookie;
import com.dtflys.forest.callback.OnSuccess;
import com.dtflys.forest.config.ForestConfiguration;
import com.dtflys.forest.config.VariableScope;
import com.dtflys.forest.converter.ForestConverter;
import com.dtflys.forest.converter.json.ForestJsonConverter;
import com.dtflys.forest.exceptions.ForestInterceptorDefineException;
import com.dtflys.forest.exceptions.ForestRuntimeException;
import com.dtflys.forest.filter.Filter;
import com.dtflys.forest.http.ForestQueryParameter;
import com.dtflys.forest.http.ForestRequest;
import com.dtflys.forest.http.ForestRequestType;
import com.dtflys.forest.http.ObjectRequestBody;
import com.dtflys.forest.http.StringRequestBody;
import com.dtflys.forest.interceptor.Interceptor;
import com.dtflys.forest.interceptor.InterceptorAttributes;
import com.dtflys.forest.interceptor.InterceptorFactory;
import com.dtflys.forest.lifecycles.BaseAnnotationLifeCycle;
import com.dtflys.forest.lifecycles.MethodAnnotationLifeCycle;
import com.dtflys.forest.lifecycles.ParameterAnnotationLifeCycle;
import com.dtflys.forest.lifecycles.method.RequestLifeCycle;
import com.dtflys.forest.logging.DefaultLogHandler;
import com.dtflys.forest.logging.LogConfiguration;
import com.dtflys.forest.logging.ForestLogHandler;
import com.dtflys.forest.mapping.MappingParameter;
import com.dtflys.forest.mapping.MappingTemplate;
import com.dtflys.forest.mapping.MappingVariable;
import com.dtflys.forest.mapping.SubVariableScope;
import com.dtflys.forest.multipart.ForestMultipart;
import com.dtflys.forest.multipart.ForestMultipartFactory;
import com.dtflys.forest.proxy.InterfaceProxyHandler;
import com.dtflys.forest.retryer.Retryer;
import com.dtflys.forest.ssl.SSLKeyStore;
import com.dtflys.forest.utils.ForestDataType;
import com.dtflys.forest.utils.NameUtils;
import com.dtflys.forest.utils.ReflectUtils;
import com.dtflys.forest.utils.RequestNameValue;
import com.dtflys.forest.utils.StringUtils;
import com.dtflys.forest.utils.URLUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;

import static com.dtflys.forest.mapping.MappingParameter.*;

/**
 * 通过代理调用的实际执行的方法对象
 * @author gongjun
 * @since 2016-05-03
 */
public class ForestMethod<T> implements VariableScope {

    private final InterfaceProxyHandler interfaceProxyHandler;
    private final ForestConfiguration configuration;
    private InterceptorFactory interceptorFactory;
    private final Method method;
    private String[] methodNameItems;
    private Class returnClass;
    private Type returnType;
    private MetaRequest metaRequest;
    private MappingTemplate baseUrlTemplate;
    private MappingTemplate urlTemplate;
    private MappingTemplate typeTemplate;
    private MappingTemplate dataTypeTemplate;
    private Integer baseTimeout = null;
    private Integer timeout = null;
    private MappingTemplate sslProtocolTemplate;
    private Class baseRetryerClass = null;
    private Integer baseRetryCount = null;
    private Long baseMaxRetryInterval;
    private Integer retryCount = null;
    private long maxRetryInterval;
    private MappingTemplate baseEncodeTemplate = null;
    private MappingTemplate encodeTemplate = null;
    private MappingTemplate charsetTemplate = null;
    private MappingTemplate baseContentTypeTemplate;
    private MappingTemplate baseUserAgentTemplate;
    private MappingTemplate baseCharsetTemplate;
    private MappingTemplate baseSslProtocolTemplate;
    private MappingTemplate contentTypeTemplate;
    private MappingTemplate userAgentTemplate;
    private long progressStep = -1;
    private ForestConverter decoder = null;
    private MappingTemplate sslKeyStoreId;
    private MappingTemplate[] dataTemplateArray;
    private MappingTemplate[] headerTemplateArray;
    private MappingParameter[] parameterTemplateArray;
    private List<MappingParameter> namedParameters = new ArrayList<>();
    private List<ForestMultipartFactory> multipartFactories = new ArrayList<>();
    private Map<String, MappingVariable> variables = new HashMap<>();
    private MappingParameter onSuccessParameter = null;
    private MappingParameter onErrorParameter = null;
    private MappingParameter onProgressParameter = null;
    private MappingParameter onLoadCookieParameter = null;
    private MappingParameter onSaveCookieParameter = null;
    private List<Interceptor> globalInterceptorList;
    private List<Interceptor> baseInterceptorList;
    private List<Interceptor> interceptorList;
    private List<InterceptorAttributes> interceptorAttributesList;
    private Type onSuccessClassGenericType = null;
    private Class retryerClass = null;
    private boolean async = false;
    private boolean logEnabled = true;
    private boolean logRequest = true;
    private boolean logResponseStatus = true;
    private boolean logResponseContent = false;
    private ForestLogHandler logHandler = new DefaultLogHandler();
    private LogConfiguration logConfiguration = null;

    public ForestMethod(InterfaceProxyHandler interfaceProxyHandler, ForestConfiguration configuration, Method method) {
        this.interfaceProxyHandler = interfaceProxyHandler;
        this.configuration = configuration;
        this.method = method;
        this.interceptorFactory = configuration.getInterceptorFactory();
        this.methodNameItems = NameUtils.splitCamelName(method.getName());
        processBaseProperties();
        processMethodAnnotations();
    }

    @Override
    public ForestConfiguration getConfiguration() {
        return configuration;
    }


    @Override
    public Object getVariableValue(String name) {
        Object value = configuration.getVariableValue(name);
        return value;
    }

    public MappingTemplate makeTemplate(String text) {
        return new MappingTemplate(text, this);
    }


    public Class getReturnClass() {
        return returnClass;
    }


    @Override
    public MappingVariable getVariable(String name) {
        return variables.get(name);
    }

    private void processBaseProperties() {
        MetaRequest baseMetaRequest = interfaceProxyHandler.getBaseMetaRequest();
        String baseUrl = baseMetaRequest.getUrl();
        if (StringUtils.isNotBlank(baseUrl)) {
            baseUrlTemplate = makeTemplate(baseUrl);
        }
        String baseContentEncoding = baseMetaRequest.getContentEncoding();
        if (StringUtils.isNotBlank(baseContentEncoding)) {
            baseEncodeTemplate = makeTemplate(baseContentEncoding);
        }
        String baseContentType = baseMetaRequest.getContentType();
        if (StringUtils.isNotBlank(baseContentType)) {
            baseContentTypeTemplate = makeTemplate(baseContentType);
        }
        String baseUserAgent = baseMetaRequest.getUserAgent();
        if (StringUtils.isNotBlank(baseUserAgent)) {
            baseUserAgentTemplate = makeTemplate(baseUserAgent);
        }
        String baseCharset = baseMetaRequest.getCharset();
        if (StringUtils.isNotBlank(baseCharset)) {
            baseCharsetTemplate = makeTemplate(baseCharset);
        }
        String baseSslProtocol = baseMetaRequest.getSslProtocol();
        if (StringUtils.isNotBlank(baseSslProtocol)) {
            baseSslProtocolTemplate = makeTemplate(baseSslProtocol);
        }
        baseTimeout = baseMetaRequest.getTimeout();
        baseRetryerClass = baseMetaRequest.getRetryer();
        baseRetryCount = baseMetaRequest.getRetryCount();
        baseMaxRetryInterval = baseMetaRequest.getMaxRetryInterval();

        List<Class> globalInterceptorClasses = configuration.getInterceptors();
        if (globalInterceptorClasses != null && globalInterceptorClasses.size() > 0) {
            globalInterceptorList = new LinkedList<>();
            for (Class clazz : globalInterceptorClasses) {
                if (!Interceptor.class.isAssignableFrom(clazz) || clazz.isInterface()) {
                    throw new ForestRuntimeException("Class [" + clazz.getName() + "] is not a implement of [" +
                            Interceptor.class.getName() + "] interface.");
                }
                Interceptor interceptor = interceptorFactory.getInterceptor(clazz);
                globalInterceptorList.add(interceptor);
            }
        }

        Class[] baseInterceptorClasses = baseMetaRequest.getInterceptor();
        if (baseInterceptorClasses != null && baseInterceptorClasses.length > 0) {
            baseInterceptorList = new LinkedList<>();
            for (int cidx = 0, len = baseInterceptorClasses.length; cidx < len; cidx++) {
                Class clazz = baseInterceptorClasses[cidx];
                if (!Interceptor.class.isAssignableFrom(clazz) || clazz.isInterface()) {
                    throw new ForestRuntimeException("Class [" + clazz.getName() + "] is not a implement of [" +
                            Interceptor.class.getName() + "] interface.");
                }
                Interceptor interceptor = interceptorFactory.getInterceptor(clazz);
                baseInterceptorList.add(interceptor);
            }
        }

        List<Annotation> baseAnnotationList = interfaceProxyHandler.getBaseAnnotations();
        Map<Annotation, Class> baseAnnMap = new HashMap<>(baseAnnotationList.size());
        for (Annotation annotation : baseAnnotationList) {
            Class interceptorClass = getAnnotationLifeCycleClass(annotation);
            baseAnnMap.put(annotation, interceptorClass);
        }
        addMetaRequestAnnotations(baseAnnMap);
    }

    private <T extends Interceptor> T addInterceptor(Class<T> interceptorClass) {
        if (interceptorList == null) {
            interceptorList = new LinkedList<>();
        }
        if (!Interceptor.class.isAssignableFrom(interceptorClass) || interceptorClass.isInterface()) {
            throw new ForestRuntimeException("Class [" + interceptorClass.getName() + "] is not a implement of [" +
                    Interceptor.class.getName() + "] interface.");
        }
        T interceptor = interceptorFactory.getInterceptor(interceptorClass);
        interceptorList.add(interceptor);
        return interceptor;
    }


    private Class getAnnotationLifeCycleClass(Annotation annotation) {
        Class<? extends Annotation> annType = annotation.annotationType();
        Class<? extends MethodAnnotationLifeCycle> interceptorClass = null;
        MethodLifeCycle methodLifeCycleAnn = annType.getAnnotation(MethodLifeCycle.class);
        if (methodLifeCycleAnn == null) {
            BaseLifeCycle baseLifeCycle = annType.getAnnotation(BaseLifeCycle.class);
            if (baseLifeCycle != null) {
                Class<? extends BaseAnnotationLifeCycle> baseAnnLifeCycleClass = baseLifeCycle.value();
                if (baseAnnLifeCycleClass != null) {
                    if (MethodAnnotationLifeCycle.class.isAssignableFrom(baseAnnLifeCycleClass)) {
                        interceptorClass = (Class<? extends MethodAnnotationLifeCycle>) baseAnnLifeCycleClass;
                    } else {
                        return baseAnnLifeCycleClass;
                    }
                }
            }
        }
        if (methodLifeCycleAnn != null || interceptorClass != null) {
            if (interceptorClass == null) {
                interceptorClass = methodLifeCycleAnn.value();
                if (!Interceptor.class.isAssignableFrom(interceptorClass)) {
                    throw new ForestInterceptorDefineException(interceptorClass);
                }
            }
        }

        return interceptorClass;
    }

    /**
     * 添加元请求注释表
     * @param annMap 请求注释表
     */
    private void addMetaRequestAnnotations(Map<Annotation, Class> annMap) {
        for (Map.Entry<Annotation, Class> entry : annMap.entrySet()) {
            addMetaRequestAnnotation(entry.getKey(), entry.getValue());
        }
    }

    /**
     * 添加元请求注释
     * @param annotation 注解
     * @param interceptorClass 拦截器类
     */
    private void addMetaRequestAnnotation(Annotation annotation, Class interceptorClass) {
        Class<? extends Annotation> annType = annotation.annotationType();
        RequestAttributes requestAttributesAnn = annType.getAnnotation(RequestAttributes.class);
        if (requestAttributesAnn != null) {
            Map<String, Object> attrTemplates = ReflectUtils.getAttributesFromAnnotation(annotation);
            for (String key : attrTemplates.keySet()) {
                Object value = attrTemplates.get(key);
                if (value instanceof CharSequence) {
                    MappingTemplate template = makeTemplate(value.toString());
                    attrTemplates.put(key, template);
                } else if (String[].class.isAssignableFrom(value.getClass())) {
                    String[] stringArray = (String[]) value;
                    int len = stringArray.length;
                    MappingTemplate[] templates = new MappingTemplate[stringArray.length];
                    for (int i = 0; i < len; i++) {
                        String item = stringArray[i];
                        MappingTemplate template = makeTemplate(item);
                        templates[i] = template;
                    }
                    attrTemplates.put(key, templates);
                }
            }

            InterceptorAttributes attributes = new InterceptorAttributes(interceptorClass, attrTemplates);
            if (interceptorAttributesList == null) {
                interceptorAttributesList = new LinkedList<>();
            }
            interceptorAttributesList.add(attributes);
        }
        Interceptor interceptor = addInterceptor(interceptorClass);
        if (interceptor instanceof MethodAnnotationLifeCycle) {
            MethodAnnotationLifeCycle lifeCycle = (MethodAnnotationLifeCycle) interceptor;
            lifeCycle.onMethodInitialized(this, annotation);
        }
    }


    public void setMetaRequest(MetaRequest metaRequest) {
        if (metaRequest != null && this.metaRequest != null) {
            throw new ForestRuntimeException("[Forest] annotation \""
                    + metaRequest.getRequestAnnotation().annotationType().getName() + "\" can not be added on method \""
                    + method.getName() + "\", because a similar annotation \""
                    + metaRequest.getRequestAnnotation().annotationType().getName() + "\" has already been attached to this method.");
        }
        this.metaRequest = metaRequest;
    }

    /**
     * 获取Forest方法对应的Java原生方法
     * @return Java原生方法，{@link java.lang.reflect.Method}类实例
     */
    public Method getMethod() {
        return method;
    }

    /**
     * 获取方法名
     * @return 方法名字符串
     */
    public String getMethodName() {
        return method.getName();
    }

    /**
     * 获取元请求信息
     * @return 元请求对象，{@link MetaRequest}类实例
     */
    public MetaRequest getMetaRequest() {
        return metaRequest;
    }


    /**
     * 处理方法上的注解列表
     */
    private void processMethodAnnotations() {
        Annotation[] annotations = method.getAnnotations();
        Map<Annotation, Class> requestAnns = new LinkedHashMap();
        Map<Annotation, Class> methodAnns = new LinkedHashMap<>();

        // 对注解分类
        for (int i = 0; i < annotations.length; i++) {
            Annotation ann = annotations[i];
            Class interceptorClass = getAnnotationLifeCycleClass(ann);
            if (interceptorClass == null) {
                continue;
            }
            if (RequestLifeCycle.class.isAssignableFrom(interceptorClass)) {
                requestAnns.put(ann, interceptorClass);
            } else {
                methodAnns.put(ann, interceptorClass);
            }
        }

        // 先添加请求类注解
        addMetaRequestAnnotations(requestAnns);

        // 再添加普通方法类注解
        addMetaRequestAnnotations(methodAnns);

        // 处理请求元信息
        if (this.metaRequest != null) {
            processMetaRequest(this.metaRequest);
        }

        returnClass = method.getReturnType();
    }

    private void processMetaRequest(MetaRequest metaRequest) {
        Class[] paramTypes = method.getParameterTypes();
        Type[] genericParamTypes = method.getGenericParameterTypes();
        Annotation[][] paramAnns = method.getParameterAnnotations();
        Parameter[] parameters = method.getParameters();

        parameterTemplateArray = new MappingParameter[paramTypes.length];
        processParameters(parameters, genericParamTypes, paramAnns);

        urlTemplate = makeTemplate(metaRequest.getUrl());
        typeTemplate = makeTemplate(metaRequest.getType());
        dataTypeTemplate = makeTemplate(metaRequest.getDataType());
        if (StringUtils.isNotEmpty(metaRequest.getContentType())) {
            contentTypeTemplate = makeTemplate(metaRequest.getContentType());
        }
        if (StringUtils.isNotEmpty(metaRequest.getUserAgent())) {
            userAgentTemplate = makeTemplate(metaRequest.getUserAgent());
        }
        sslKeyStoreId = makeTemplate(metaRequest.getKeyStore());
        if (StringUtils.isNotEmpty(metaRequest.getContentEncoding())) {
            encodeTemplate = makeTemplate(metaRequest.getContentEncoding());
        }
        charsetTemplate = makeTemplate(metaRequest.getCharset());
        sslProtocolTemplate = makeTemplate(metaRequest.getSslProtocol());
        progressStep = metaRequest.getProgressStep();
        async = metaRequest.isAsync();
        retryerClass = metaRequest.getRetryer();
        Class decoderClass = metaRequest.getDecoder();
        String[] dataArray = metaRequest.getData();
        String[] headerArray = metaRequest.getHeaders();
        int tout = metaRequest.getTimeout();
        if (tout > 0) {
            timeout = tout;
        }
        int rtnum = metaRequest.getRetryCount();
        if (rtnum > 0) {
            retryCount = rtnum;
        }
        maxRetryInterval = metaRequest.getMaxRetryInterval();
        logEnabled = configuration.isLogEnabled();
        if (!logEnabled) {
            logEnabled = metaRequest.isLogEnabled();
        }
        logRequest = configuration.isLogRequest();
        logResponseStatus = configuration.isLogResponseStatus();
        logResponseContent = configuration.isLogResponseContent();
        logHandler = configuration.getLogHandler();

        LogConfiguration metaLogConfiguration = metaRequest.getLogConfiguration();
        if (metaLogConfiguration != null) {
            logEnabled = metaLogConfiguration.isLogEnabled();
            logRequest = metaLogConfiguration.isLogRequest();
            logResponseStatus = metaLogConfiguration.isLogResponseStatus();
            logResponseContent = metaLogConfiguration.isLogResponseContent();
            logHandler = metaLogConfiguration.getLogHandler();
        }

        logConfiguration = new LogConfiguration();
        logConfiguration.setLogEnabled(logEnabled);
        logConfiguration.setLogRequest(logRequest);
        logConfiguration.setLogResponseStatus(logResponseStatus);
        logConfiguration.setLogResponseContent(logResponseContent);
        logConfiguration.setLogHandler(logHandler);


        dataTemplateArray = new MappingTemplate[dataArray.length];
        for (int j = 0; j < dataArray.length; j++) {
            String data = dataArray[j];
            MappingTemplate dataTemplate = makeTemplate(data);
            dataTemplateArray[j] = dataTemplate;
        }

        headerTemplateArray = new MappingTemplate[headerArray.length];
        for (int j = 0; j < headerArray.length; j++) {
            String header = headerArray[j];
            MappingTemplate headerTemplate = makeTemplate(header);
            headerTemplateArray[j] = headerTemplate;
        }

        Class[] interceptorClasses = metaRequest.getInterceptor();
        if (interceptorClasses != null && interceptorClasses.length > 0) {
            for (int cidx = 0, len = interceptorClasses.length; cidx < len; cidx++) {
                Class interceptorClass = interceptorClasses[cidx];
                addInterceptor(interceptorClass);
            }
        }


        if (decoderClass != null && ForestConverter.class.isAssignableFrom(decoderClass)) {
            try {
                this.decoder = (ForestConverter) decoderClass.newInstance();
            } catch (InstantiationException e) {
                throw new ForestRuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new ForestRuntimeException(e);
            }
        }

    }

    /**
     * 处理参数列表
     * @param parameters 参数数组，{@link Parameter}类数组实例
     * @param genericParamTypes 参数类型数组
     * @param paramAnns 参数注解的二维数组
     */
    private void processParameters(Parameter[] parameters, Type[] genericParamTypes, Annotation[][] paramAnns) {
        for (int i = 0; i < parameters.length; i++) {
            Parameter param = parameters[i];
            Class paramType = param.getType();
            Annotation[] anns = paramAnns[i];
            MappingParameter parameter = new MappingParameter(paramType);
            parameter.setIndex(i);
            parameter.setName(param.getName());
            parameterTemplateArray[i] = parameter;
            if (OnSuccess.class.isAssignableFrom(paramType)) {
                onSuccessParameter = parameter;
                Type genType = genericParamTypes[i];
                onSuccessClassGenericType = getGenericClassOrType(genType, 0);
            } else if (OnError.class.isAssignableFrom(paramType)) {
                onErrorParameter = parameter;
            } else if (OnProgress.class.isAssignableFrom(paramType)) {
                onProgressParameter = parameter;
            } else if (OnSaveCookie.class.isAssignableFrom(paramType)) {
                onSaveCookieParameter = parameter;
            } else if (OnLoadCookie.class.isAssignableFrom(paramType)) {
                onLoadCookieParameter = parameter;
            }
            processParameterAnnotation(parameter, anns);
        }
    }

    /**
     * 处理参数的注解
     * @param parameter 方法参数-字符串模板解析对象，{@link MappingParameter}类实例
     * @param anns 方法参数注解的二维数组
     */
    private void processParameterAnnotation(MappingParameter parameter, Annotation[] anns) {
        for (int i = 0; i < anns.length; i++) {
            Annotation ann = anns[i];
            Class annType = ann.annotationType();
            ParamLifeCycle paramLifeCycleAnn = (ParamLifeCycle) annType.getAnnotation(ParamLifeCycle.class);
            if (paramLifeCycleAnn != null) {
                Class<? extends ParameterAnnotationLifeCycle> interceptorClass = paramLifeCycleAnn.value();
                if (!Interceptor.class.isAssignableFrom(interceptorClass)) {
                    throw new ForestInterceptorDefineException(interceptorClass);
                }
                ParameterAnnotationLifeCycle lifeCycle = addInterceptor(interceptorClass);
                lifeCycle.onParameterInitialized(this, parameter, ann);
            }
        }
    }

    /**
     * 添加命名参数
     * @param parameter 方法参数-字符串模板解析对象，{@link MappingParameter}类实例
     */
    public void addNamedParameter(MappingParameter parameter) {
        namedParameters.add(parameter);
    }

    /**
     * 添加变量
     * @param name 变量名
     * @param variable 变量对象，{@link MappingVariable}类实例
     */
    public void addVariable(String name, MappingVariable variable) {
        variables.put(name, variable);
    }

    /**
     * 添加Forest文件上传用的Mutlipart工厂
     * @param multipartFactory Forest文件上传用的Mutlipart工厂，{@link ForestMultipartFactory}类实例
     */
    public void addMultipartFactory(ForestMultipartFactory multipartFactory) {
        multipartFactories.add(multipartFactory);
    }

    /**
     * 处理参数的过滤器
     * @param parameter 方法参数-字符串模板解析对象，{@link MappingParameter}类实例
     * @param filterName 过滤器名称
     */
    public void processParameterFilter(MappingParameter parameter, String filterName) {
        if (StringUtils.isNotEmpty(filterName)) {
            String[] filterNameArray = filterName.split(",");
            for (String name : filterNameArray) {
                Filter filter = configuration.newFilterInstance(name);
                parameter.addFilter(filter);
            }
        }
    }

    /**
     * 给请求设置重试策略
     * @param retryerClass 重试策略类型
     * @param request Forest请求对象，{@link ForestRequest}类实例
     */
    private void setRetryerToRequest(Class retryerClass, ForestRequest request) {
        try {
            Constructor constructor = retryerClass.getConstructor(ForestRequest.class);
            Retryer retryer = (Retryer) constructor.newInstance(request);
            request.setRetryer(retryer);
        } catch (NoSuchMethodException e) {
            throw new ForestRuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new ForestRuntimeException(e);
        } catch (InstantiationException e) {
            throw new ForestRuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new ForestRuntimeException(e);
        }
    }

    /**
     * 获得最终的请求类型
     * @param args 调用本对象对应方法时传入的参数数组
     * @return 请求类型，{@link ForestRequestType}枚举实例
     */
    private ForestRequestType type(Object[] args) {
        String renderedType = typeTemplate.render(args);
        if (StringUtils.isBlank(renderedType)) {
            String typeFromName = methodNameItems[0];
            ForestRequestType type = ForestRequestType.findType(typeFromName);
            if (type != null) {
                return type;
            }
            return ForestRequestType.GET;
        }
        ForestRequestType type = ForestRequestType.findType(renderedType);
        if (type != null) {
            return type;
        }
        throw new ForestRuntimeException("Http request type \"" + renderedType + "\" is not be supported.");
    }

    /**
     * 创建请求
     * @param args 调用本对象对应方法时传入的参数数组
     * @return Forest请求对象，{@link ForestRequest}类实例
     */
    private ForestRequest makeRequest(Object[] args) {
        MetaRequest baseMetaRequest = interfaceProxyHandler.getBaseMetaRequest();
        String baseUrl = null;
        if (baseUrlTemplate != null) {
            baseUrl = StringUtils.trimBegin(baseUrlTemplate.render(args));
        }
        if (urlTemplate == null) {
            throw new ForestRuntimeException("request URL is empty");
        }
        String renderedUrl = urlTemplate.render(args);
        ForestRequestType type = type(args);
        String baseContentEncoding = null;
        if (baseEncodeTemplate != null) {
            baseContentEncoding = baseEncodeTemplate.render(args);
        }
        String contentEncoding = null;
        if (encodeTemplate != null) {
            contentEncoding = encodeTemplate.render(args);
        }

        String baseContentType = null;
        if (baseContentTypeTemplate != null) {
            baseContentType = baseContentTypeTemplate.render(args);
        }
        String baseUserAgent = null;
        if (baseUserAgentTemplate != null) {
            baseUserAgent = baseUserAgentTemplate.render(args);
        }
        String charset = null;
        String renderedCharset = charsetTemplate.render(args);
        if (StringUtils.isNotBlank(renderedCharset)) {
            charset = renderedCharset;
        } else if (baseCharsetTemplate != null) {
            charset = baseCharsetTemplate.render(args);
        } else if (StringUtils.isNotBlank(configuration.getCharset())) {
            charset = configuration.getCharset();
        } else {
            charset = "UTF-8";
        }

        String sslProtocol = null;
        String renderedSslProtocol = sslProtocolTemplate.render(args);
        if (StringUtils.isNotBlank(renderedSslProtocol)) {
            sslProtocol = renderedSslProtocol;
        } else if (baseSslProtocolTemplate != null) {
            sslProtocol = baseSslProtocolTemplate.render(args);
        } else {
            sslProtocol = configuration.getSslProtocol();
        }

        String renderedContentType = null;
        if (contentTypeTemplate != null) {
            renderedContentType = contentTypeTemplate.render(args).trim();
        }
        String renderedUserAgent = null;
        if (userAgentTemplate != null) {
            renderedUserAgent = userAgentTemplate.render(args).trim();
        }
        String newUrl = null;
        List<RequestNameValue> nameValueList = new ArrayList<>();
//        List<Object> bodyList = new ArrayList<>();
        String [] headerArray = baseMetaRequest.getHeaders();
        MappingTemplate[] baseHeaders = null;
        if (headerArray != null && headerArray.length > 0) {
            baseHeaders = new MappingTemplate[headerArray.length];
            for (int j = 0; j < baseHeaders.length; j++) {
                MappingTemplate header = new MappingTemplate(headerArray[j], this);
                baseHeaders[j] = header;
            }
        }

        renderedUrl = URLUtils.getValidURL(baseUrl, renderedUrl);

        // createExecutor and initialize http instance
        ForestRequest<T> request = new ForestRequest(configuration, this, args);
        request.setUrl(renderedUrl)
                .setType(type)
                .setCharset(charset)
                .setSslProtocol(sslProtocol)
                .setLogConfiguration(logConfiguration)
                .setAsync(async);

        if (StringUtils.isNotEmpty(renderedContentType)) {
            request.setContentType(renderedContentType);
        }

        if (StringUtils.isNotEmpty(contentEncoding)) {
            request.setContentEncoding(contentEncoding);
        }

        if (StringUtils.isNotEmpty(renderedUserAgent)) {
            request.setUserAgent(renderedUserAgent);
        }

        for (int i = 0; i < namedParameters.size(); i++) {
            MappingParameter parameter = namedParameters.get(i);
            if (parameter.isObjectProperties()) {
                int target = parameter.isUnknownTarget() ? type.getDefaultParamTarget() : parameter.getTarget();
                Object obj = args[parameter.getIndex()];
                if (parameter.isJsonParam()) {
                    String  json = "";
                    if (obj != null) {
                        ForestJsonConverter jsonConverter = configuration.getJsonConverter();
                        obj = parameter.getFilterChain().doFilter(configuration, obj);
                        json = jsonConverter.encodeToString(obj);
                    }
                    if (MappingParameter.isHeader(target)) {
                        request.addHeader(new RequestNameValue(parameter.getJsonParamName(), json, target)
                                .setDefaultValue(parameter.getDefaultValue()));
                    } else {
                        nameValueList.add(new RequestNameValue(parameter.getJsonParamName(), json, target, parameter.getPartContentType())
                                .setDefaultValue(parameter.getDefaultValue()));
                    }
                }
                else if (!parameter.getFilterChain().isEmpty()) {
                    obj = parameter.getFilterChain().doFilter(configuration, obj);
                    if (obj != null) {
                        if (MappingParameter.isHeader(target)) {
                            request.addHeader(new RequestNameValue(null, obj, target));
                        } else if (MappingParameter.isQuery(target)) {
                            request.addQuery(obj.toString(), null);
                        } else if (MappingParameter.isBody(target)) {
                            if (obj instanceof CharSequence) {
                                request.addBody(new StringRequestBody(obj.toString())
                                        .setDefaultValue(parameter.getDefaultValue()));
                            } else {
                                request.addBody(new ObjectRequestBody(obj)
                                        .setDefaultValue(parameter.getDefaultValue()));
                            }
                        } else {
                            nameValueList.add(new RequestNameValue(obj.toString(), target, parameter.getPartContentType())
                                    .setDefaultValue(parameter.getDefaultValue()));
                        }
                    }
                }
                else if (obj instanceof CharSequence) {
                    if (MappingParameter.isQuery(target)) {
                        request.addQuery(ForestQueryParameter.createSimpleQueryParameter(obj)
                                .setDefaultValue(parameter.getDefaultValue()));
                    } else if (MappingParameter.isBody(target)) {
                        request.addBody(new StringRequestBody(obj.toString())
                                .setDefaultValue(parameter.getDefaultValue()));
                    }
                }
                else if (obj instanceof Iterable
                        || obj.getClass().isArray()
                        || ReflectUtils.isPrimaryType(obj.getClass())) {
                    if (MappingParameter.isQuery(target)) {
                        if (parameter.isJsonParam()) {
                            request.addQuery(parameter.getName(), obj);
                        } else {
                            if (obj instanceof Iterable) {
                                for (Object subItem : (Iterable) obj) {
                                    if (subItem instanceof ForestQueryParameter) {
                                        request.addQuery((ForestQueryParameter) subItem);
                                    } else {
                                        request.addQuery(ForestQueryParameter.createSimpleQueryParameter(subItem));
                                    }
                                }
{'fraction_non_alphanumeric': 0.08903564373949703, 'fraction_numerical': 0.0008254960346708335, 'mean_word_length': 2.4564120853925715, 'pattern_counts': {'":': 0, '<': 99, '<?xml version=': 0, '>': 91, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 15, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4825474', 'n_tokens_mistral': 17479, 'n_tokens_neox': 17044, 'n_words': 3289}