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

com.ifengxue.http.executor.Request Maven / Gradle / Ivy

/*
 * Copyright 2019 https://www.ifengxue.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.ifengxue.http.executor;

import com.ifengxue.http.annotation.Header;
import com.ifengxue.http.annotation.HttpMethod;
import com.ifengxue.http.collection.MultiMap;
import com.ifengxue.http.contract.CallbackHandler;
import io.mikael.urlbuilder.UrlBuilder;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.Getter;
import lombok.ToString;
import lombok.experimental.Delegate;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;

@ToString
@SuppressWarnings("unused")
public class Request implements RequestContext {

  private static final Pattern PATH_VARIABLE_PATTERN = Pattern.compile("\\{(.*?)}");
  /**
   * 请求URL
   */
  @Getter
  private String url;
  /**
   * 请求方法
   */
  @Getter
  private String method;
  /**
   * query parameter names
   *
   * @see com.ifengxue.http.annotation.QueryParam
   */
  @Getter
  private Set queryParameterNames;
  /**
   * 参数列表
   */
  @Getter
  private Map parameterMap;
  /**
   * 请求body
   */
  private Object body;
  /**
   * 请求头
   */
  @Getter
  private Map headerMap;

  /**
   * callback
   */
  @Getter
  private CallbackHandler callbackHandler;

  @Delegate
  private RequestContext requestContext = new SimpleRequestContext();

  private Request() {
  }

  /**
   * 替换请求URL
   *
   * @param newUrl 新URL
   */
  public Request replaceUrl(String newUrl) {
    this.url = newUrl;
    return this;
  }

  /**
   * 添加请求头
   *
   * @param name 请求头名称
   * @param value 请求头值
   */
  public Request addHeader(String name, String value) {
    Objects.requireNonNull(headerMap).put(name, value);
    return this;
  }

  /**
   * 移除请求头
   *
   * @param name 请求头名称
   */
  public Request removeHeader(String name) {
    Objects.requireNonNull(headerMap).remove(name);
    return this;
  }

  /**
   * 检查是否包含指定请求头
   *
   * @param name 请求头名称
   */
  public boolean containsHeader(String name) {
    return Optional.ofNullable(headerMap).map(m -> m.containsKey(name)).orElse(false);
  }

  /**
   * 添加请求参数
   *
   * @param name 请求参数名称
   * @param value 参数值
   */
  @SuppressWarnings("unchecked")
  public Request addParameter(String name, Object value) {
    Map map = Objects.requireNonNull(parameterMap);
    if (!map.containsKey(name)) {
      map.put(name, value);
    } else {
      Object value0 = map.get(name);
      if (value0 instanceof Collection) {
        if (value instanceof Collection) {
          ((Collection) value0).addAll((Collection) value);
        } else {
          ((Collection) value0).add(value);
        }
      } else {
        List paramArray = new LinkedList<>();
        paramArray.add(value0);
        if (value instanceof Collection) {
          paramArray.addAll((Collection) value);
        } else {
          paramArray.add(value);
        }
        map.put(name, paramArray);
      }
    }
    return this;
  }

  /**
   * 移除请求参数
   *
   * @param name 参数名称
   */
  public Request removeParameter(String name) {
    Objects.requireNonNull(parameterMap).remove(name);
    return this;
  }

  /**
   * 获取请求body
   */
  @SuppressWarnings("unchecked")
  public  T getBody() {
    return (T) body;
  }

  public static class Builder {

    private final Request request = new Request();
    private URL prefixUrl;
    private String suffixUrl;

    private Builder() {
      request.parameterMap = new HashMap<>();
      request.headerMap = new HashMap<>();
      request.queryParameterNames = new HashSet<>();
    }

    public static Builder newBuilder(String method) {
      Builder builder = new Builder();
      builder.request.method = method;
      return builder;
    }

    public static Builder newGetBuilder() {
      return newBuilder(HttpMethod.GET.name());
    }

    public static Builder newPostBuilder() {
      return newBuilder(HttpMethod.POST.name());
    }

    public static Builder newPutBuilder() {
      return newBuilder(HttpMethod.PUT.name());
    }

    public static Builder newPatchBuilder() {
      return newBuilder(HttpMethod.PATCH.name());
    }

    public static Builder newDeleteBuilder() {
      return newBuilder(HttpMethod.DELETE.name());
    }

    public static Builder newHeadBuilder() {
      return newBuilder(HttpMethod.HEAD.name());
    }

    public Builder setPrefixUrl(URL prefixUrl) {
      this.prefixUrl = prefixUrl;
      return this;
    }

    public Builder setSuffixUrl(String suffixUrl) {
      this.suffixUrl = suffixUrl;
      return this;
    }

    public Builder addParameter(String name, Object value) {
      request.addParameter(name, value);
      return this;
    }

    public Builder addParameters(MultiMap multiMap) {
      multiMap.forEach(request::addParameter);
      return this;
    }

    public  Builder setBody(T body) {
      request.body = body;
      return this;
    }

    public Builder addQueryParameterNames(Set queryParameterNames) {
      request.queryParameterNames.addAll(queryParameterNames);
      return this;
    }

    public Builder addQueryParameterNames(String... queryParameterNames) {
      request.queryParameterNames.addAll(Arrays.asList(queryParameterNames));
      return this;
    }

    public Builder addHeader(String name, String value) {
      request.addHeader(name, value);
      return this;
    }

    public Builder addHeaders(Map headerMap) {
      headerMap.forEach(request::addHeader);
      return this;
    }

    public Builder addHeaders(Header[] headers) {
      for (Header header : headers) {
        request.addHeader(header.name(), header.value());
      }
      return this;
    }

    public Builder setCallbackHandler(CallbackHandler callbackHandler) {
      request.callbackHandler = callbackHandler;
      return this;
    }

    public Request build() {
      if (StringUtils.isBlank(request.method)) {
        throw new IllegalArgumentException("must set the http request method");
      }
      String targetUrl = Optional.ofNullable(prefixUrl).map(URL::toString).orElse("");
      if (StringUtils.isNotBlank(suffixUrl)) {
        if (StringUtils.isNotBlank(targetUrl) && targetUrl.endsWith("/")) {
          // 移除结尾后缀
          targetUrl = targetUrl.substring(0, targetUrl.length() - 1);
        }
        if (StringUtils.isBlank(targetUrl)) {
          targetUrl = suffixUrl;
        } else {
          if (suffixUrl.startsWith("/")) {
            targetUrl += suffixUrl;
          } else {
            targetUrl += "/" + suffixUrl;
          }
        }
      }
      if (StringUtils.isBlank(targetUrl)) {
        throw new IllegalStateException(String.format("Invalid prefix url %s or suffix url %s", prefixUrl, suffixUrl));
      }
      // 解析路径参数
      Matcher matcher = PATH_VARIABLE_PATTERN.matcher(targetUrl);
      Set pathVariableNames = new HashSet<>();
      while (matcher.find()) {
        String pathVariableName = matcher.group(1);
        String value = Optional.ofNullable(request.parameterMap.get(pathVariableName))
            .map(Object::toString)
            .orElseThrow(() -> new IllegalStateException("cannot find a value matching '" + pathVariableName + "'"));
        targetUrl = targetUrl.replace("{" + pathVariableName + "}", value);
        pathVariableNames.add(pathVariableName);
      }
      // 移除parameter map 中的路径参数
      pathVariableNames.forEach(k -> request.parameterMap.remove(k));
      if (!request.getQueryParameterNames().isEmpty()) {
        UrlBuilder urlBuilder = UrlBuilder.fromString(targetUrl, StandardCharsets.UTF_8);
        for (String queryParameterName : request.getQueryParameterNames()) {
          Object value = request.getParameterMap().getOrDefault(queryParameterName, "");
          for (NameValuePair nameValuePair : ParameterUtil.createNameValueParis(queryParameterName, value)) {
            urlBuilder = urlBuilder
                .addParameter(nameValuePair.getName(), StringUtils.trimToEmpty(nameValuePair.getValue()));
          }
          // 移除parameter map 中的查询参数
          request.getParameterMap().remove(queryParameterName);
        }
        targetUrl = urlBuilder.toUrl().toString();
      }
      request.url = targetUrl;
      return request;
    }
  }
}