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

com.aventstack.chaintest.http.ChainTestApiClient Maven / Gradle / Ivy

The newest version!
package com.aventstack.chaintest.http;

import com.aventstack.chaintest.conf.Configuration;
import com.aventstack.chaintest.domain.ChainTestEntity;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

public class ChainTestApiClient {

    private static final Logger log = LoggerFactory.getLogger(ChainTestApiClient.class);

    private static final Duration DEFAULT_REQUEST_TIMEOUT = Duration.ofSeconds(30);
    private static final HttpMethod DEFAULT_HTTP_METHOD = HttpMethod.POST;
    public static final String PROPERTY_SERVER_URL = "chaintest.generator.chainlp.host.url";
    public static final String CLIENT_REQUEST_TIMEOUT = "chaintest.generator.chainlp.client.request-timeout-s";
    public static final String CLIENT_EXPECT_CONTINUE = "chaintest.generator.chainlp.client.expect-continue";
    public static final String CLIENT_MAX_RETRIES = "chaintest.generator.chainlp.client.max-retries";
    public static final String CLIENT_RETRY_INTERVAL = "chaintest.generator.chainlp.client.retry-interval-ms";
    public static final String CLIENT_THROW_AFTER_RETRY_ATTEMPTS_EXCEEDED = "chaintest.generator.chainlp.client.throw-after-retry-attempts-exceeded";

    private static final String API_VERSION = "/api/v1/";

    private final HttpClient _httpClient;
    private final ObjectMapper _mapper;
    private final URI _baseURI;
    private final HttpRetryHandler _retryHandler;

    private Configuration _config;
    private Duration _requestTimeout;
    private String _serverURL;
    private boolean _expectContinue;

    public ChainTestApiClient() throws IOException {
        final Builder builder = builder().defaultBuilder();
        _httpClient = builder.httpClient;
        _mapper = builder.objectMapper;
        _requestTimeout = builder.timeout;
        loadConfig();
        _baseURI = URI.create(_serverURL).resolve(API_VERSION);
        _retryHandler = new HttpRetryHandler(this, _config.getConfig());
    }

    public void loadConfig() throws IOException {
        _config = new Configuration();
        _config.load();

        final Map config = _config.getConfig();
        _serverURL = config.get(PROPERTY_SERVER_URL);
        if (null == _serverURL || _serverURL.isBlank()) {
            throw new IllegalStateException("ChainTest endpoint was not provided by property " + PROPERTY_SERVER_URL +
                    ". No such property was found in classpath resources or system env");
        }

        final String timeout = config.get(CLIENT_REQUEST_TIMEOUT);
        if (null != timeout && timeout.matches("\\d+")) {
            _requestTimeout = Duration.ofSeconds(Integer.parseInt(timeout));
        }

        final String expectContinue = config.get(CLIENT_EXPECT_CONTINUE);
        _expectContinue = Boolean.parseBoolean(expectContinue);
    }

    public ChainTestApiClient(final Configuration conf) {
        _config = conf;
        final Builder builder = builder().defaultBuilder();
        _httpClient = builder.httpClient;
        _mapper = builder.objectMapper;
        _requestTimeout = builder.timeout;
        _baseURI = URI.create(_serverURL).resolve(API_VERSION);
        _retryHandler = new HttpRetryHandler(this, _config.getConfig());
    }

    public ChainTestApiClient(final Builder builder) {
        if (null == builder.uri) {
            throw new IllegalArgumentException("Missing argument: uri");
        }
        _httpClient = null == builder.httpClient
                ? HttpClient.newHttpClient() : builder.httpClient;
        _mapper = null == builder.objectMapper
                ? new ObjectMapper() : builder.objectMapper;
        _requestTimeout = null == builder.timeout
                ? DEFAULT_REQUEST_TIMEOUT : builder.timeout;
        _baseURI = builder.uri;
        _expectContinue = builder.expectContinue;
        final int maxRetryAttempts = builder.maxRetryAttempts == -1
                ? HttpRetryHandler.MAX_RETRY_ATTEMPTS : builder.maxRetryAttempts;
        final long retryIntervalMs = builder.retryIntervalMs == -1L
                ? HttpRetryHandler.RETRY_INTERVAL : builder.retryIntervalMs;
        _retryHandler = new HttpRetryHandler(this, maxRetryAttempts, retryIntervalMs, builder.throwAfterMaxRetryAttempts);
    }

    public ChainTestApiClient(final URI uri, final boolean loadExternalConfig) throws IOException {
        this(builder().defaultBuilder().withURI(uri));
        if (loadExternalConfig) {
            loadConfig();
        }
    }

    public ChainTestApiClient(final URI uri) {
        this(builder().defaultBuilder().withURI(uri));
    }

    public ChainTestApiClient(final String url, final boolean loadExternalConfig) throws IOException {
        this(URI.create(url), loadExternalConfig);
    }

    public ChainTestApiClient(final String url) {
        this(builder().defaultBuilder().withURI(URI.create(url)));
    }

    public Configuration config() {
        return _config;
    }

    public ObjectMapper objectMapper() {
        return _mapper;
    }

    public HttpRetryHandler retryHandler() {
        return _retryHandler;
    }

    public static Builder builder() {
        return new Builder();
    }

    public  HttpResponse send(final T entity, final HttpMethod method)
            throws IOException, InterruptedException {
        final HttpRequest request = createRequest(entity, method);
        return _httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    }

    public  HttpResponse send(final T entity) throws IOException, InterruptedException {
        return send(entity, DEFAULT_HTTP_METHOD);
    }

    public  HttpResponse send(final T entity, final Class clazz, final HttpMethod method)
            throws IOException, InterruptedException {
        final HttpRequest request = createRequest(entity, method);
        return _httpClient.send(request, new JsonMappedBodyHandler<>(clazz, _mapper));
    }

    public  HttpResponse send(final T entity, final Class clazz)
            throws IOException, InterruptedException {
        return send(entity, clazz, DEFAULT_HTTP_METHOD);
    }

    public  CompletableFuture> sendAsync(final T entity, final HttpMethod method)
            throws IOException {
        final HttpRequest request = createRequest(entity, method);
        return _httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
    }

    public  CompletableFuture> sendAsync(final T entity) throws IOException {
        return sendAsync(entity, DEFAULT_HTTP_METHOD);
    }

    public  CompletableFuture> sendAsync(final T entity, final Class clazz, final HttpMethod method)
            throws IOException {
        final HttpRequest request = createRequest(entity, method);
        return _httpClient.sendAsync(request, new JsonMappedBodyHandler<>(clazz, _mapper));
    }

    public  CompletableFuture> sendAsync(final T entity, final Class clazz)
            throws IOException {
        return sendAsync(entity, clazz, DEFAULT_HTTP_METHOD);
    }

    public HttpResponse send(final byte[] data, final HttpMethod method) throws IOException, InterruptedException {
        final HttpRequest request = createRequest(data, method);
        return _httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    }

    public HttpResponse send(final byte[] data) throws IOException, InterruptedException {
        return send(data, DEFAULT_HTTP_METHOD);
    }

    public CompletableFuture> sendAsync(final byte[] data, final HttpMethod method) {
        final HttpRequest request = createRequest(data, method);
        return _httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
    }

    public CompletableFuture> sendAsync(final byte[] data) {
        return sendAsync(data, DEFAULT_HTTP_METHOD);
    }

    private HttpRequest createRequest(final byte[] data, final HttpMethod method) {
        log.trace("Creating request with HTTPMethod.{}", method.getMethod());
        final URI uri = getURI("embeds");
        log.debug("Created request with byte array of length: {}", data.length);
        return HttpRequest.newBuilder()
                .uri(uri)
                .expectContinue(_expectContinue)
                .timeout(_requestTimeout)
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM)
                .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
                .method(method.getMethod(), HttpRequest.BodyPublishers.ofByteArray(data))
                .build();
    }

    private  HttpRequest createRequest(final T entity, final HttpMethod method) throws IOException {
        log.trace("Creating request for entity {} with HTTPMethod.{}", entity.getClass().getName(), method.getMethod());
        final URI uri = getURI(entity);
        final String requestBody = _mapper.writeValueAsString(entity);
        log.debug("Created request for entity {} with body: {}", entity.getClass().getSimpleName(), requestBody);
        return HttpRequest.newBuilder()
                .uri(uri)
                .expectContinue(_expectContinue)
                .timeout(_requestTimeout)
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
                .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
                .method(method.getMethod(), HttpRequest.BodyPublishers.ofString(requestBody))
                .build();
    }

    private  URI getURI(final T entity) {
        final String clz = entity.getClass().getSimpleName().toLowerCase();
        return _baseURI.resolve(clz + "s");
    }

    private  URI getURI(final String forPath) {
        return _baseURI.resolve(forPath);
    }

    public static final class Builder {

        private HttpClient httpClient;
        private ObjectMapper objectMapper;
        private Duration timeout;
        private URI uri;
        private boolean expectContinue;
        private int maxRetryAttempts = -1;
        private long retryIntervalMs = -1L;
        private boolean throwAfterMaxRetryAttempts = true;

        public Builder withHttpClient(final HttpClient client) {
            httpClient = client;
            return this;
        }

        public Builder withObjectMapper(final ObjectMapper mapper) {
            objectMapper = mapper;
            return this;
        }

        public Builder withRequestTimeout(final Duration duration) {
            timeout = duration;
            return this;
        }

        public Builder withURI(final URI uri) {
            this.uri = uri.resolve(API_VERSION);
            return this;
        }

        public Builder withURI(final String url) {
            withURI(URI.create(url));
            return this;
        }

        public Builder withExpectContinue(final boolean expectContinue) {
            this.expectContinue = expectContinue;
            return this;
        }

        public Builder withMaxHttpRetryAttempts(final int maxRetryAttempts) {
            this.maxRetryAttempts = maxRetryAttempts;
            return this;
        }

        public Builder withRetryIntervalMs(final long retryIntervalMs) {
            this.retryIntervalMs = retryIntervalMs;
            return this;
        }

        public Builder withThrowAfterMaxRetryAttempts(final boolean throwAfterMaxRetryAttempts) {
            this.throwAfterMaxRetryAttempts = throwAfterMaxRetryAttempts;
            return this;
        }

        public Builder defaultBuilder() {
            httpClient = HttpClient.newHttpClient();
            objectMapper = new ObjectMapper();
            timeout = DEFAULT_REQUEST_TIMEOUT;
            return this;
        }

        public ChainTestApiClient build() {
            return new ChainTestApiClient(this);
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy