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

io.camunda.common.http.DefaultHttpClient Maven / Gradle / Ivy

There is a newer version: 8.5.15
Show newest version
package io.camunda.common.http;

import com.google.common.reflect.TypeToken;
import io.camunda.common.auth.Authentication;
import io.camunda.common.auth.Product;
import io.camunda.common.exception.SdkException;
import io.camunda.common.json.JsonMapper;
import io.camunda.common.json.SdkObjectMapper;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.hc.client5.http.classic.methods.HttpDelete;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** Default Http Client powered by Apache HttpClient */
public class DefaultHttpClient implements HttpClient {

  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
  private final Map, String>> productMap;
  private final CloseableHttpClient httpClient;
  private final Authentication authentication;
  private final JsonMapper jsonMapper;
  private String host = "";
  private String basePath = "";

  public DefaultHttpClient(Authentication authentication) {
    this.authentication = authentication;
    this.httpClient = HttpClients.createSystem();
    this.jsonMapper = new SdkObjectMapper();
    this.productMap = new HashMap<>();
  }

  public DefaultHttpClient(
      Authentication authentication,
      CloseableHttpClient httpClient,
      JsonMapper jsonMapper,
      Map, String>> productMap) {
    this.authentication = authentication;
    this.httpClient = httpClient;
    this.jsonMapper = jsonMapper;
    this.productMap = productMap;
  }

  @Override
  public void init(String host, String basePath) {
    this.host = host;
    this.basePath = basePath;
  }

  @Override
  public void loadMap(Product product, Map, String> map) {
    this.productMap.put(product, map);
  }

  @Override
  public  T get(Class responseType, Long key) {
    return get(responseType, String.valueOf(key));
  }

  @Override
  public  T get(Class responseType, String id) {
    String url = host + basePath + retrievePath(responseType) + "/" + id;
    HttpGet httpGet = new HttpGet(url);
    retrieveToken(responseType).forEach(httpGet::addHeader);
    T resp;
    try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
      resp = parseAndRetry(response, responseType);
    } catch (Exception e) {
      LOG.error(
          "Failed GET with responseType {}, id {} due to {}", responseType, id, e.getMessage());
      throw new SdkException(e);
    }

    return resp;
  }

  @Override
  public  T get(
      Class responseType, Class parameterType, TypeToken selector, Long key) {
    return get(responseType, parameterType, selector, String.valueOf(key));
  }

  private  T get(
      Class responseType, Class parameterType, TypeToken selector, String id) {
    String resourcePath = retrievePath(selector.getClass());
    if (resourcePath.contains("{key}")) {
      resourcePath = resourcePath.replace("{key}", String.valueOf(id));
    } else {
      resourcePath = resourcePath + "/" + id;
    }
    String url = host + basePath + resourcePath;
    HttpGet httpGet = new HttpGet(url);
    retrieveToken(selector.getClass()).forEach(httpGet::addHeader);
    T resp;
    try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
      resp = parseAndRetry(response, responseType, parameterType, selector);
    } catch (Exception e) {
      LOG.error(
          "Failed GET with responseType {}, parameterType {}, selector {}, id {} due to {}",
          responseType,
          parameterType,
          selector,
          id,
          e.getMessage());
      throw new SdkException(e);
    }
    return resp;
  }

  @Override
  public  String getXml(Class selector, Long key) {
    String url = host + basePath + retrievePath(selector) + "/" + key + "/xml";
    HttpGet httpGet = new HttpGet(url);
    retrieveToken(selector).forEach(httpGet::addHeader);
    String xml;
    try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
      xml = parseXMLAndRetry(response, selector);
    } catch (Exception e) {
      LOG.error("Failed GET with selector {}, key {} due to {}", selector, key, e.getMessage());
      throw new SdkException(e);
    }
    return xml;
  }

  @Override
  public  T post(
      Class responseType, Class parameterType, TypeToken selector, U body) {
    String url = host + basePath + retrievePath(selector.getClass());
    HttpPost httpPost = new HttpPost(url);
    httpPost.addHeader("Content-Type", "application/json");
    retrieveToken(selector.getClass()).forEach(httpPost::addHeader);
    T resp;
    String data = jsonMapper.toJson(body);
    httpPost.setEntity(new StringEntity(data));
    try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
      resp = parseAndRetry(response, responseType, parameterType, selector);
    } catch (Exception e) {
      LOG.error(
          "Failed POST with responseType {}, parameterType {}, selector {}, body {} due to {}",
          responseType,
          parameterType,
          selector,
          body,
          e.getMessage());
      throw new SdkException(e);
    }
    return resp;
  }

  @Override
  public  T delete(Class responseType, Class selector, Long key) {
    String resourcePath = retrievePath(selector) + "/" + key;
    String url = host + basePath + resourcePath;
    HttpDelete httpDelete = new HttpDelete(url);
    retrieveToken(selector).forEach(httpDelete::addHeader);
    T resp = null;
    try (CloseableHttpResponse response = httpClient.execute(httpDelete)) {
      resp = parseAndRetry(response, responseType, selector);
    } catch (Exception e) {
      LOG.error(
          "Failed DELETE with responseType {}, selector {}, key {}, due to {}",
          responseType,
          selector,
          key,
          e.getMessage());
      throw new SdkException(e);
    }
    return resp;
  }

  private  String retrievePath(Class clazz) {
    AtomicReference path = new AtomicReference<>();
    productMap.forEach(
        (product, map) -> {
          if (map.containsKey(clazz)) {
            path.set(map.get(clazz));
          }
        });
    return path.get();
  }

  private  List retrieveToken(Class clazz) {
    AtomicReference currentProduct = new AtomicReference<>();
    productMap.forEach(
        (product, map) -> {
          if (map.containsKey(clazz)) {
            currentProduct.set(product);
          }
        });
    Map tokens = authentication.getTokenHeader(currentProduct.get());
    return tokens.entrySet().stream()
        .map(keyValueHeader -> new BasicHeader(keyValueHeader.getKey(), keyValueHeader.getValue()))
        .toList();
  }

  private  Product getProduct(Class clazz) {
    AtomicReference currentProduct = new AtomicReference<>();
    productMap.forEach(
        (product, map) -> {
          if (map.containsKey(clazz)) {
            currentProduct.set(product);
          }
        });
    return currentProduct.get();
  }

  // TODO: Refactor duplicate code parseAndRetry()

  private  String parseXMLAndRetry(CloseableHttpResponse response, Class selector)
      throws IOException {
    String resp;
    if (200 <= response.getCode() && response.getCode() <= 299) {
      resp =
          new String(
              Java8Utils.readAllBytes(response.getEntity().getContent()), StandardCharsets.UTF_8);
    } else {
      if (response.getCode() == HttpStatus.SC_UNAUTHORIZED
          || response.getCode() == HttpStatus.SC_FORBIDDEN) {
        authentication.resetToken(getProduct(selector.getClass()));
      }
      throw new SdkException("Response not successful: " + response.getCode());
    }
    return resp;
  }

  private  T parseAndRetry(CloseableHttpResponse response, Class responseType)
      throws IOException {
    T resp;
    if (200 <= response.getCode() && response.getCode() <= 299) {
      HttpEntity entity = response.getEntity();
      String tmp = new String(Java8Utils.readAllBytes(entity.getContent()), StandardCharsets.UTF_8);
      resp = jsonMapper.fromJson(tmp, responseType);
      EntityUtils.consume(entity);
    } else {
      if (response.getCode() == HttpStatus.SC_UNAUTHORIZED
          || response.getCode() == HttpStatus.SC_FORBIDDEN) {
        authentication.resetToken(getProduct(responseType.getClass()));
        // TODO: Add capability to auto retry the existing request
      }
      throw new SdkException("Response not successful: " + response.getCode());
    }
    return resp;
  }

  private  T parseAndRetry(
      CloseableHttpResponse response, Class responseType, Class selector) throws IOException {
    T resp;
    if (200 <= response.getCode() && response.getCode() <= 299) {
      HttpEntity entity = response.getEntity();
      String tmp = new String(Java8Utils.readAllBytes(entity.getContent()), StandardCharsets.UTF_8);
      resp = jsonMapper.fromJson(tmp, responseType);
      EntityUtils.consume(entity);
    } else {
      if (response.getCode() == HttpStatus.SC_UNAUTHORIZED
          || response.getCode() == HttpStatus.SC_FORBIDDEN) {
        authentication.resetToken(getProduct(selector.getClass()));
      }
      throw new SdkException("Response not successful: " + response.getCode());
    }
    return resp;
  }

  private  T parseAndRetry(
      CloseableHttpResponse response,
      Class responseType,
      Class parameterType,
      TypeToken selector)
      throws IOException {
    T resp;
    if (200 <= response.getCode() && response.getCode() <= 299) {
      HttpEntity entity = response.getEntity();
      String tmp = new String(Java8Utils.readAllBytes(entity.getContent()), StandardCharsets.UTF_8);
      resp = jsonMapper.fromJson(tmp, responseType, parameterType);
      EntityUtils.consume(entity);
    } else {
      if (response.getCode() == HttpStatus.SC_UNAUTHORIZED
          || response.getCode() == HttpStatus.SC_FORBIDDEN) {
        authentication.resetToken(getProduct(selector.getClass()));
      }
      throw new SdkException("Response not successful: " + response.getCode());
    }
    return resp;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy