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

com.arextest.schedule.client.HttpWepServiceApiClient Maven / Gradle / Ivy

There is a newer version: 2.0.4
Show newest version
package com.arextest.schedule.client;

import static com.arextest.schedule.common.CommonConstant.URL;
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;

import com.arextest.schedule.utils.SSLUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.retry.RetryPolicy;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.ExceptionClassifierRetryPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

/**
 * @author jmo
 * @since 2021/9/15
 */
@Component
@Slf4j
public final class HttpWepServiceApiClient {

  private RestTemplate restTemplate;
  private RetryTemplate retryTemplate;
  @Resource
  private ZstdJacksonMessageConverter zstdJacksonMessageConverter;
  @Resource
  private ObjectMapper objectMapper;
  @Value("${arex.connect.time.out}")
  private int connectTimeOut;
  @Value("${arex.read.time.out}")
  private int readTimeOut;
  @Value("${arex.retry.max.attempts}")
  private int maxAttempts;
  @Value("${arex.retry.back.off.period}")
  private int backOffPeriod;
  @Value("${arex.client.https.cert.disable:#{false}}")
  private boolean disableCertCheck;

  @Autowired(required = false)
  private List clientHttpRequestInterceptors;
  private static final String ZSTD_JSON_CONTENT_TYPE = "application/zstd-json;charset=UTF-8";

  @PostConstruct
  private void initTemplate() {
    initRestTemplate();
    initRetryTemplate();
    if (disableCertCheck) {
      SSLUtils.disableSSLVerification();
    }
  }

  private void initRestTemplate() {
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setConnectTimeout(connectTimeOut);
    requestFactory.setReadTimeout(readTimeOut);
    final int initialCapacity = 10;
    List> httpMessageConverterList = new ArrayList<>(initialCapacity);
    httpMessageConverterList.add(zstdJacksonMessageConverter);
    httpMessageConverterList.add(new ByteArrayHttpMessageConverter());
    httpMessageConverterList.add(new StringHttpMessageConverter());
    httpMessageConverterList.add(new ResourceHttpMessageConverter());
    httpMessageConverterList.add(new SourceHttpMessageConverter<>());
    httpMessageConverterList.add(new AllEncompassingFormHttpMessageConverter());

    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(
        objectMapper);
    converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
    httpMessageConverterList.add(converter);
    this.restTemplate = new RestTemplate(httpMessageConverterList);
    this.restTemplate.setRequestFactory(requestFactory);
    if (CollectionUtils.isNotEmpty(clientHttpRequestInterceptors)) {
      restTemplate.setInterceptors(clientHttpRequestInterceptors);
    }
  }

  private void initRetryTemplate() {
    retryTemplate = new RetryTemplate();

    // Create an Retry Policy that will retry on specific exceptions, up to maxAttempts times
    setRetryPolicy();
    // Create an FixedBackOffPolicy that will set the retry interval
    setBackOffPolicy();
    // Add retry listener
    registerRetryListener();
  }

  private void setBackOffPolicy() {
    FixedBackOffPolicy backoffPolicy = new FixedBackOffPolicy();
    backoffPolicy.setBackOffPeriod(backOffPeriod);
    retryTemplate.setBackOffPolicy(backoffPolicy);
  }

  private void setRetryPolicy() {
    // Create a SimpleRetryPolicy that will retry up to maxAttempts times
    SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy(maxAttempts);

    // Create an ExceptionClassifierRetryPolicy that will retry on specific exceptions, up to maxAttempts times
    ExceptionClassifierRetryPolicy exceptionClassifierRetryPolicy = new ExceptionClassifierRetryPolicy();

    Map, RetryPolicy> policyMap = Maps.newHashMapWithExpectedSize(3);
    policyMap.put(SocketException.class, simpleRetryPolicy);
    policyMap.put(SocketTimeoutException.class, simpleRetryPolicy);
    policyMap.put(ResourceAccessException.class, simpleRetryPolicy);
    exceptionClassifierRetryPolicy.setPolicyMap(policyMap);

    retryTemplate.setRetryPolicy(exceptionClassifierRetryPolicy);
  }

  private void registerRetryListener() {
    retryTemplate.registerListener(new RetryListener() {
      @Override
      public  boolean open(RetryContext context,
          RetryCallback callback) {
        return true;
      }

      @Override
      public  void close(RetryContext context, RetryCallback callback,
          Throwable throwable) {
      }

      @Override
      public  void onError(RetryContext context,
          RetryCallback callback, Throwable throwable) {
        LOGGER.warn("Retry url: {}, count: {}, error message: {}", context.getAttribute(URL),
            context.getRetryCount(),
            throwable.getMessage());
      }
    });
  }

  public  TResponse get(String url, Map urlVariables,
      Class responseType) {
    try {
      return restTemplate.getForObject(url, responseType, urlVariables);
    } catch (Exception e) {
      return null;
    }
  }

  public  ResponseEntity get(String url, Map urlVariables,
      ParameterizedTypeReference responseType) {
    try {
      return restTemplate.exchange(url, HttpMethod.GET, null, responseType, urlVariables);
    } catch (Exception e) {
      return null;
    }
  }

  public  ResponseEntity retryGet(String url, Map urlVariables,
      ParameterizedTypeReference responseType) {
    try {
      return retryTemplate.execute(retryCallback -> {
        retryCallback.setAttribute(URL, url);
        return restTemplate.exchange(url, HttpMethod.GET, null, responseType, urlVariables);
      });
    } catch (Exception e) {
      return null;
    }
  }

  public  TResponse get(String url, Map urlVariables,
      MultiValueMap headers, Class responseType) {
    try {
      HttpEntity request = new HttpEntity<>(headers);
      return restTemplate.exchange(url, HttpMethod.GET, request, responseType, urlVariables)
          .getBody();
    } catch (Exception e) {
      return null;
    }
  }

  public  TResponse jsonPost(String url, TRequest request,
      Class responseType) {
    try {
      return restTemplate.postForObject(url, wrapJsonContentType(request), responseType);
    } catch (Exception e) {
      return null;
    }
  }

  public  TResponse jsonPost(String url, TRequest request,
      Class responseType,
      Map headers) {
    try {

      return restTemplate.postForObject(url, wrapJsonContentType(request, headers), responseType);
    } catch (Exception e) {
      return null;
    }
  }

  public  TResponse retryJsonPost(String url, TRequest request,
      Class responseType) {
    try {
      return retryTemplate.execute(retryCallback -> {
        retryCallback.setAttribute(URL, url);
        return restTemplate.postForObject(url, wrapJsonContentType(request), responseType);
      });
    } catch (Exception e) {
      return null;
    }
  }

  public  TResponse retryJsonPost(String url, TRequest request,
      Class responseType, Map headers) {
    try {
      return retryTemplate.execute(retryCallback -> {
        retryCallback.setAttribute(URL, url);
        return restTemplate.postForObject(url, wrapJsonContentType(request, headers), responseType);
      });
    } catch (Exception e) {
      return null;
    }
  }

  public  ResponseEntity retryJsonPost(String url, TRequest request,
      ParameterizedTypeReference responseType) {
    try {
      return retryTemplate.execute(retryCallback -> {
        retryCallback.setAttribute(URL, url);
        return restTemplate.exchange(url, HttpMethod.POST, wrapJsonContentType(request),
            responseType);
      });
    } catch (Exception e) {
      return null;
    }
  }

  public  TResponse retryZstdJsonPost(String url, TRequest request,
      Class responseType) {
    Map headers = Maps.newHashMapWithExpectedSize(1);
    headers.put(HttpHeaders.CONTENT_TYPE, ZSTD_JSON_CONTENT_TYPE);

    try {
      return retryTemplate.execute(retryCallback -> {
        retryCallback.setAttribute(URL, url);
        return restTemplate.postForObject(url, wrapJsonContentType(request, headers), responseType);
      });
    } catch (Exception e) {
      return null;
    }
  }

  @SuppressWarnings("unchecked")
  private  HttpEntity wrapJsonContentType(TRequest request) {
    HttpEntity httpJsonEntity;
    if (request instanceof HttpEntity) {
      httpJsonEntity = (HttpEntity) request;
    } else {
      HttpHeaders headers = new HttpHeaders();
      headers.setContentType(MediaType.APPLICATION_JSON);
      httpJsonEntity = new HttpEntity<>(request, headers);
    }
    return httpJsonEntity;
  }

  @SuppressWarnings("unchecked")
  private  HttpEntity wrapJsonContentType(TRequest request,
      Map extraHeaders) {
    HttpEntity httpJsonEntity;
    if (request instanceof HttpEntity) {
      httpJsonEntity = (HttpEntity) request;
    } else {
      HttpHeaders headers = new HttpHeaders();
      if (!extraHeaders.containsKey(CONTENT_TYPE)) {
        headers.setContentType(MediaType.APPLICATION_JSON);
      }
      headers.setAll(extraHeaders);
      httpJsonEntity = new HttpEntity<>(request, headers);
    }
    return httpJsonEntity;
  }

  /**
   * When restTemplate sends a replay request, it needs to pass the URI object to avoid the url
   * encode parameter parsing exception.
   */
  public  ResponseEntity exchange(String url, HttpMethod method,
      HttpEntity requestEntity,
      Class responseType) throws RestClientException {
    return restTemplate.exchange(URI.create(url), method, requestEntity, responseType);
  }

  public  ResponseEntity jsonPostWithThrow(String url,
      HttpEntity request,
      Class responseType) throws RestClientException {
    return restTemplate.postForEntity(url, wrapJsonContentType(request), responseType);

  }

  public  ResponseEntity retryJsonPostWithThrow(String url,
      HttpEntity request,
      Class responseType) throws RestClientException {
    return retryTemplate.execute(retryCallback -> {
      retryCallback.setAttribute(URL, url);
      return restTemplate.postForEntity(url, wrapJsonContentType(request), responseType);
    });
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy