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

com.jianggujin.http.support.JMethodHolder Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2018 jianggujin (www.jianggujin.com).
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jianggujin.http.support;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.Proxy;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import org.w3c.dom.Document;

import com.jianggujin.http.core.JHttpException;
import com.jianggujin.http.core.JMethod;
import com.jianggujin.http.core.JRequest;
import com.jianggujin.http.core.JRequestBodyResolver;
import com.jianggujin.http.core.JResponse;
import com.jianggujin.http.core.JSSLContextFactory;
import com.jianggujin.http.response.JByteBufferResponse;
import com.jianggujin.http.response.JByteResponse;
import com.jianggujin.http.response.JFileResponse;
import com.jianggujin.http.response.JNoBodyResponse;
import com.jianggujin.http.response.JTextResponse;
import com.jianggujin.http.response.JXMLDomResponse;
import com.jianggujin.http.support.annotation.JApiRequest;
import com.jianggujin.http.support.annotation.JApiRequestBodyResolver;
import com.jianggujin.http.support.annotation.JApiResponseCreator;
import com.jianggujin.http.support.annotation.JCookie;
import com.jianggujin.http.support.annotation.JHeader;
import com.jianggujin.http.support.annotation.JPathParam;
import com.jianggujin.http.support.annotation.JRequestBody;
import com.jianggujin.http.support.annotation.JRequestParam;
import com.jianggujin.http.util.JDataUtils;
import com.jianggujin.http.util.JKeyVal;

/**
 * API方法数据持有类
 * 
 * @author jianggujin
 *
 */
public class JMethodHolder {
    private static final int NOT_SET_POS = -1;
    private String url;
    private JApiRequestBodyResolver requestBodyResolver;
    private JApiResponseCreator responseCreator;
    private Map cookies;
    private Map headers;
    private Map requestParams;
    private JApiRequest apiRequest;
    private Method method;
    private Class returnClass;

    private int responseIndex = NOT_SET_POS;
    private int proxyIndex = NOT_SET_POS;
    private int sslContextFactoryIndex = NOT_SET_POS;
    private int requestBodyResolverIndex = NOT_SET_POS;
    private int methodIndex = NOT_SET_POS;
    private int[] keyValIndexs = {};
    private JAnnotationHolder[] headerHolders = {};
    private JAnnotationHolder[] cookieHolders = {};
    private JAnnotationHolder[] requestParamHolders = {};
    private JAnnotationHolder[] pathParamHolders = {};
    private JAnnotationHolder requestBodyHolder = null;

    protected JMethodHolder(String baseUrl, JApiRequestBodyResolver requestBodyResolver,
            JApiResponseCreator responseCreator, Map cookies, Map headers,
            Map requestParams, Method method)
            throws JHttpException, InstantiationException, IllegalAccessException {
        this.method = method;
        this.apiRequest = method.getAnnotation(JApiRequest.class);
        if (apiRequest == null) {
            throw new JHttpException("target method not api.");
        }
        this.url = getUrl(baseUrl);
        JApiRequestBodyResolver methodResolver = method.getAnnotation(JApiRequestBodyResolver.class);
        this.requestBodyResolver = methodResolver != null ? methodResolver : requestBodyResolver;
        JApiResponseCreator methodCreator = method.getAnnotation(JApiResponseCreator.class);
        this.responseCreator = methodCreator != null ? methodCreator : responseCreator;
        this.cookies = mixin(cookies, JApiInvocationHandler.getCookies(method.getAnnotation(JCookie.class)));
        this.headers = mixin(headers, JApiInvocationHandler.getHeaders(method.getAnnotation(JHeader.class)));
        this.requestParams = mixin(requestParams,
                JApiInvocationHandler.getRequestParams(method.getAnnotation(JRequestParam.class)));
        this.returnClass = method.getReturnType();
        this.parseMethodParameter(method);
    }

    /**
     * 获得请求地址
     * 
     * @param baseUrl
     * @return
     */
    private String getUrl(String baseUrl) {
        String urlPath = apiRequest.value();
        String url = null;
        if (baseUrl == null) {
            url = urlPath;
        } else {
            url = baseUrl + urlPath;
        }
        return url;
    }

    /**
     * 解析方法参数
     * 
     * @param request
     */
    private void parseMethodParameter(Method method) {
        int pCount = method.getParameterCount();
        if (pCount > 0) {
            Class[] pTypes = method.getParameterTypes();
            Annotation[][] pAnnos = method.getParameterAnnotations();
            int pos = 0;
            for (Class pType : pTypes) {
                if (JResponse.class.isAssignableFrom(pType)) {
                    responseIndex = pos;
                } else if (Proxy.class.isAssignableFrom(pType)) {
                    proxyIndex = pos;
                } else if (JSSLContextFactory.class.isAssignableFrom(pType)) {
                    sslContextFactoryIndex = pos;
                } else if (JRequestBodyResolver.class.isAssignableFrom(pType)) {
                    responseIndex = pos;
                } else if (JMethod.class.isAssignableFrom(pType)) {
                    methodIndex = pos;
                } else if (JKeyVal.class.isAssignableFrom(pType)) {
                    keyValIndexs = push(keyValIndexs, pos);
                } else {
                    parseAnnotation(pType, pAnnos[pos], pos);
                }
                pos++;
            }
        }

    }

    /**
     * 解析方法参数注解
     * 
     * @param pType
     * @param annotations
     * @param pos
     * @return
     * @throws IOException
     */
    private void parseAnnotation(Class pType, Annotation[] annotations, int pos) {
        if (annotations == null) {
            return;
        }
        for (Annotation annotation : annotations) {
            if (annotation instanceof JHeader) {// 处理请求头
                JHeader header = (JHeader) annotation;
                JAnnotationHolder holder = parseAnnotation(header.value(), header.required(), pType, pos, "header");
                this.headerHolders = push(this.headerHolders, holder);
            }
            if (annotation instanceof JPathParam) {// 处理路径参数
                JPathParam pathParam = (JPathParam) annotation;
                JAnnotationHolder holder = parseAnnotation(pathParam.value(), pathParam.required(), pType, pos,
                        "pathParam");
                this.pathParamHolders = push(this.pathParamHolders, holder);
            }
            if (annotation instanceof JRequestBody) {// 处理请求体
                JRequestBody requestBody = (JRequestBody) annotation;
                this.requestBodyHolder = new JAnnotationHolder(true, null, requestBody.required(), pos);
            }
            if (annotation instanceof JRequestParam) {// 处理请求参数
                JRequestParam requestParam = (JRequestParam) annotation;
                JAnnotationHolder holder = parseAnnotation(requestParam.value(), requestParam.required(), pType, pos,
                        "requestParam");
                this.requestParamHolders = push(this.requestParamHolders, holder);
            }
            if (annotation instanceof JCookie) {// 处理Cookie
                JCookie header = (JCookie) annotation;
                JAnnotationHolder holder = parseAnnotation(header.value(), header.required(), pType, pos, "cookie");
                this.cookieHolders = push(this.cookieHolders, holder);
            }
        }
    }

    /**
     * 解析方法参数注解
     * 
     * @param value
     * @param required
     * @param pType
     * @param pos
     * @param annType
     * @return
     */
    private JAnnotationHolder parseAnnotation(String value, boolean required, Class pType, int pos, String annType) {
        JAnnotationHolder holder = null;
        if (String.class.equals(pType)) {
            if (JDataUtils.isEmpty(value)) {
                throw new IllegalArgumentException("method " + annType + " annotation, value must not be empty.");
            }
            holder = new JAnnotationHolder(true, value, required, pos);
        } else if (Map.class.isAssignableFrom(pType)) {// Map
            holder = new JAnnotationHolder(false, value, required, pos);
        } else {
            throw new IllegalArgumentException("method " + annType + " annotation parameter type not support.");
        }
        return holder;
    }

    /**
     * 执行请求
     * 
     * @param args
     * @return
     * @throws JHttpException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public Object invoke(Object[] args) throws InstantiationException, IllegalAccessException, JHttpException {
        JRequest request = JRequest.create((URL) null).method(apiRequest.method()).ignoreError(apiRequest.ignoreError())
                .charset(apiRequest.charset()).forceHasBody(apiRequest.forceHasBody()).timeout(apiRequest.timeout())
                .cookie(cookies).header(headers).data(requestParams);
        if (this.requestBodyResolver != null) {
            JRequestBodyResolver resolver = JApiInvocationHandler.getRequestBodyResolver(this.requestBodyResolver);
            if (resolver != null) {
                request.requestBodyResolver();
            }
        }
        initRequestWithMethodParameter(request, args);

        request.url(buildUrl(args));

        // 处理默认响应
        JResponse response = request.response();
        // 判断是否需要设置响应对象
        autoSetResponse(request);

        response = request.execute().response();
        // 处理方法实际的返回数据
        if (response != null) {
            Object result = response.getData();
            if (result != null && returnClass.isAssignableFrom(result.getClass())) {
                return result;
            }
            if (returnClass.isAssignableFrom(response.getClass())) {
                return response;
            }
        }
        return null;
    }

    /**
     * 根据方法参数初始化请求对象
     * 
     * @param request
     * @param args
     */
    @SuppressWarnings("unchecked")
    private void initRequestWithMethodParameter(JRequest request, Object[] args) {
        if (responseIndex != NOT_SET_POS) {
            request.response((JResponse) args[responseIndex]);
        }
        if (proxyIndex != NOT_SET_POS) {
            request.proxy((Proxy) args[proxyIndex]);
        }
        if (sslContextFactoryIndex != NOT_SET_POS) {
            request.sslContextFactory((JSSLContextFactory) args[sslContextFactoryIndex]);
        }
        if (requestBodyResolverIndex != NOT_SET_POS) {
            request.requestBodyResolver((JRequestBodyResolver) args[requestBodyResolverIndex]);
        }
        if (methodIndex != NOT_SET_POS) {
            request.method((JMethod) args[methodIndex]);
        }
        for (int pos : keyValIndexs) {
            request.data((JKeyVal) args[pos]);
        }
        for (JAnnotationHolder holder : headerHolders) {
            if (holder.isSingle()) {
                if (holder.isRequired() && args[holder.getPos()] == null) {
                    throw new IllegalArgumentException("method header annotation requried parameter must not be null.");
                }
                request.header(holder.getName(), (String) args[holder.getPos()]);
            } else {
                request.header((Map) args[holder.getPos()]);
            }
        }
        for (JAnnotationHolder holder : cookieHolders) {
            if (holder.isSingle()) {
                if (holder.isRequired() && args[holder.getPos()] == null) {
                    throw new IllegalArgumentException("method cookie annotation requried parameter must not be null.");
                }
                request.cookie(holder.getName(), (String) args[holder.getPos()]);
            } else {
                request.cookie((Map) args[holder.getPos()]);
            }
        }
        for (JAnnotationHolder holder : requestParamHolders) {
            if (holder.isSingle()) {
                if (holder.isRequired() && args[holder.getPos()] == null) {
                    throw new IllegalArgumentException(
                            "method requestParam annotation requried parameter must not be null.");
                }
                request.data(holder.getName(), (String) args[holder.getPos()]);
            } else {
                request.data((Map) args[holder.getPos()]);
            }
        }
        if (requestBodyHolder != null) {
            if (requestBodyHolder.isRequired() && args[requestBodyHolder.getPos()] == null) {
                throw new IllegalArgumentException(
                        "method requestBody annotation requried parameter must not be null.");
            }
            request.requestBody(args[requestBodyHolder.getPos()]);
        }
    }

    /**
     * 构建请求地址
     * 
     * @param args
     * @return
     */
    @SuppressWarnings("unchecked")
    private String buildUrl(Object[] args) {
        // 存在路径参数,需要处理
        if (pathParamHolders.length > 0) {
            Map pathParams = new HashMap();
            for (JAnnotationHolder holder : pathParamHolders) {
                if (holder.isSingle()) {
                    if (holder.isRequired() && args[holder.getPos()] == null) {
                        throw new IllegalArgumentException(
                                "method pathParam annotation requried parameter must not be null.");
                    }
                    pathParams.put(holder.getName(), (String) args[holder.getPos()]);
                } else {
                    pathParams.putAll((Map) args[holder.getPos()]);
                }
            }
            return JDataUtils.resolveDynamicPropnames(url, pathParams, "{", "}");
        } else {
            return url;
        }
    }

    /**
     * 自动设置响应对象
     * 
     * @param request
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws JHttpException
     */
    private void autoSetResponse(JRequest request)
            throws InstantiationException, IllegalAccessException, JHttpException {
        JResponse response = request.response();
        // 未设置响应对象
        if (response == null) {
            if (this.responseCreator != null) {
                JResponseCreator creator = JApiInvocationHandler.getResponseCreator(this.responseCreator);
                if (creator != null) {
                    response = creator.create(request, method);
                }
            } else if (String.class.equals(returnClass)) {
                response = new JTextResponse();
            } else if (byte[].class.equals(returnClass)) {
                response = new JByteResponse();
            } else if (ByteBuffer.class.equals(returnClass)) {
                response = new JByteBufferResponse();
            } else if (File.class.equals(returnClass)) {
                response = new JFileResponse();
            } else if (Document.class.equals(returnClass)) {
                response = new JXMLDomResponse();
            } else {
                response = new JNoBodyResponse();
            }
            request.response(response);
        }
    }

    private static int[] push(int[] is, int i) {
        int len = is.length;
        int[] tmp = new int[len + 1];
        System.arraycopy(is, 0, tmp, 0, len);
        tmp[len] = i;
        return tmp;
    }

    private static JAnnotationHolder[] push(JAnnotationHolder[] hs, JAnnotationHolder holder) {
        int len = hs.length;
        JAnnotationHolder[] tmp = new JAnnotationHolder[len + 1];
        System.arraycopy(hs, 0, tmp, 0, len);
        tmp[len] = holder;
        return tmp;
    }

    /**
     * 混合两个Map
     * 
     * @param map1
     * @param map2
     * @return
     */
    private static Map mixin(Map map1, Map map2) {
        if (map1 == null) {
            return map2;
        }
        if (map2 == null) {
            return map1;
        }
        map1.putAll(map2);
        return map1;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy