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

io.vrap.rmf.base.client.ApiMethod Maven / Gradle / Ivy

There is a newer version: 17.17.0
Show newest version

package io.vrap.rmf.base.client;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Nullable;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public abstract class ApiMethod, TResult> extends Base
        implements RequestCommand, ClientRequestCommand, CreateHttpRequestCommand {

    public static class ParamEntry extends Base implements Map.Entry {
        protected final K key;
        protected V value;

        public ParamEntry(final K key) {
            this.key = key;
        }

        public ParamEntry(final K key, final V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public K getKey() {
            return key;
        }

        @Override
        public V getValue() {
            return value;
        }

        @Override
        public V setValue(final V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        public String toUriString() {
            try {
                return key + "=" + URLEncoder.encode(value.toString(), StandardCharsets.UTF_8.toString());
            }
            catch (UnsupportedEncodingException e) {
                throw new EncodingException(e);
            }
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;

            if (o == null || getClass() != o.getClass())
                return false;

            ParamEntry that = (ParamEntry) o;

            return new EqualsBuilder().append(key, that.key).append(value, that.value).isEquals();
        }

        @Override
        public int hashCode() {
            return new HashCodeBuilder(17, 37).append(key).append(value).toHashCode();
        }
    }

    private Function httpRequestDecorator = Function.identity();
    private ApiHttpHeaders headers = new ApiHttpHeaders();
    private List> queryParams = new ArrayList<>();
    private final ApiHttpClient apiHttpClient;

    protected ApiHttpClient apiHttpClient() {
        return apiHttpClient;
    }

    public ApiMethod(final ApiHttpClient apiHttpClient) {
        this.apiHttpClient = apiHttpClient;
    }

    public ApiMethod(final ApiHttpClient apiHttpClient, ApiHttpHeaders headers,
            List> queryParams) {
        this.apiHttpClient = apiHttpClient;
        this.headers = headers;
        this.queryParams = new ArrayList<>(queryParams);
    }

    public ApiMethod(final ApiMethod apiMethod) {
        this.apiHttpClient = apiMethod.apiHttpClient;
        this.headers = new ApiHttpHeaders(apiMethod.headers);
        this.queryParams = new ArrayList<>(apiMethod.queryParams);
        this.httpRequestDecorator = apiMethod.httpRequestDecorator;
    }

    /**
     * adds a header with the specified value
     * @param key header name
     * @param value header value
     * @return T
     */
    public T addHeader(final String key, final String value) {
        final T c = copy();
        ((ApiMethod) c).headers = ((ApiMethod) c).headers.addHeader(key, value);
        return c;
    }

    /**
     * removes the specified header
     * @param key header name
     * @return T
     */
    public T withoutHeader(final String key) {
        final T c = copy();
        ((ApiMethod) c).headers = ((ApiMethod) c).headers.withoutHeader(key);
        return c;
    }

    /**
     * set the header with the specified value
     * @param key header name
     * @param value header value
     * @return T
     */
    public T withHeader(final String key, final String value) {
        final T c = copy();
        ((ApiMethod) c).headers = ((ApiMethod) c).headers.withHeader(key, value);
        return c;
    }

    /**
     * set the headers
     * @param headers
     * @return
     */
    public T withHeaders(final ApiHttpHeaders headers) {
        final T c = copy();
        ((ApiMethod) c).headers = ((ApiMethod) c).headers = headers;
        return c;
    }

    /**
     * set specific content type
     * @param contentType
     * @return
     */
    public T contentType(final String contentType) {
        final T c = copy();
        ((ApiMethod) c).headers = ((ApiMethod) c).headers
                .withHeader(ApiHttpHeaders.CONTENT_TYPE, contentType);

        return c;
    }

    public ApiHttpHeaders getHeaders() {
        return this.headers;
    }

    /**
     * add an additional query parameter
     * @param key query parameter name
     * @param value query parameter value
     * @param  value type
     * @return T
     */
    public  T addQueryParam(final String key, final V value) {
        final T c = copy();
        ((ApiMethod) c).queryParams.add(new ParamEntry<>(key, value.toString()));
        return c;
    }

    /**
     * set the query parameter with the specified value
     * @param key query parameter name
     * @param value query parameter value
     * @param  value type
     * @return T
     */
    public  T withQueryParam(final String key, final V value) {
        return withoutQueryParam(key).addQueryParam(key, value);
    }

    /**
     * removes the specified query parameter
     * @param key query parameter name
     * @return T
     */
    public T withoutQueryParam(final String key) {
        final T c = copy();
        ((ApiMethod) c).queryParams = ((ApiMethod) c).queryParams.stream()
                .filter(e -> !e.getKey().equalsIgnoreCase(key))
                .collect(Collectors.toList());
        return c;
    }

    /**
     * set the query parameters
     * @param queryParams list of query parameters
     * @return T
     */
    public T withQueryParams(final List> queryParams) {
        final T c = copy();
        ((ApiMethod) c).queryParams = queryParams;
        return c;
    }

    /**
     * add the query parameters
     * @param queryParams list of query parameters
     * @return T
     */
    public T addQueryParams(final List> queryParams) {
        final T c = copy();

        ((ApiMethod) c).queryParams.addAll(queryParams);
        return c;
    }

    public List> getQueryParams() {
        return new ArrayList<>(this.queryParams);
    }

    public List getQueryParam(final String key) {
        return this.queryParams.stream().filter(e -> e.key.equals(key)).map(e -> e.value).collect(Collectors.toList());
    }

    public List getQueryParamUriStrings() {
        return this.queryParams.stream().map(ParamEntry::toUriString).collect(Collectors.toList());
    }

    public String getQueryParamUriString() {
        return this.queryParams.stream().map(ParamEntry::toUriString).collect(Collectors.joining("&"));
    }

    @Nullable
    public String getFirstQueryParam(final String key) {
        return this.queryParams.stream()
                .filter(e -> e.getKey().equals(key))
                .map(Map.Entry::getValue)
                .findFirst()
                .orElse(null);
    }

    protected abstract T copy();

    protected abstract ApiHttpRequest buildHttpRequest();

    public ApiHttpRequest createHttpRequest() {
        return httpRequestDecorator.apply(this.buildHttpRequest());
    }

    public CompletableFuture> execute() {
        return execute(apiHttpClient());
    }

    public abstract CompletableFuture> execute(final ApiHttpClient client);

    /**
     * allows to modify the HTTP request before it will be executed
     * @param op decorator function
     * @return the method itself
     */
    public T withHttpRequest(Function op) {
        final T c = copy();
        ((ApiMethod) c).httpRequestDecorator = httpRequestDecorator.andThen(op);
        return c;
    }

    /**
     * allows to provide a function to modify the ApiMethod itself
     * @param op decorator function
     * @return the method itself
     */
    public T with(Function op) {
        final T c = copy();
        return op.apply(c);
    }

    /**
     * allows to provide a function to modify the ApiMethod itself
     * @param op decorator function
     * @param arg decorator function argument
     * @param  the method type itself
     * @return the method itself
     */
    public  T with(BiFunction op, U arg) {
        final T c = copy();
        return op.apply(c, arg);
    }

    public  CompletableFuture> execute(final Class returnType) {
        return execute(apiHttpClient(), returnType);
    }

    public  CompletableFuture> execute(final ApiHttpClient client,
            final Class returnType) {
        return client.execute(this, returnType).toCompletableFuture();
    }

    public  CompletableFuture> execute(
            final TypeReference returnTypeReference) {
        return execute(apiHttpClient(), returnTypeReference);
    }

    public  CompletableFuture> execute(final ApiHttpClient client,
            final TypeReference returnTypeReference) {
        return client.execute(this, returnTypeReference).toCompletableFuture();
    }

    public  CompletableFuture> execute(final JavaType returnJavaType) {
        return execute(apiHttpClient(), returnJavaType);
    }

    public  CompletableFuture> execute(final ApiHttpClient client,
            final JavaType returnJavaType) {
        return client.execute(this, returnJavaType);
    }

    public ApiHttpResponse executeBlocking(final Duration timeout) {
        return executeBlocking(apiHttpClient(), timeout);
    }

    public abstract ApiHttpResponse executeBlocking(final ApiHttpClient client, final Duration timeout);

    public  ApiHttpResponse executeBlocking(final Class clazz) {
        return executeBlocking(apiHttpClient(), ApiHttpClient.DEFAULT_TIMEOUT, clazz);
    };

    public  ApiHttpResponse executeBlocking(final ApiHttpClient client, final Class clazz) {
        return executeBlocking(client, ApiHttpClient.DEFAULT_TIMEOUT, clazz);
    };

    public  ApiHttpResponse executeBlocking(final Duration timeout, final Class clazz) {
        return executeBlocking(apiHttpClient(), timeout, clazz);
    }

    public  ApiHttpResponse executeBlocking(final ApiHttpClient client, final Duration timeout,
            final Class clazz) {
        return client.executeBlocking(this, clazz, timeout);
    }

    public  ApiHttpResponse executeBlocking(final TypeReference typeReference) {
        return executeBlocking(apiHttpClient(), ApiHttpClient.DEFAULT_TIMEOUT, typeReference);
    }

    public  ApiHttpResponse executeBlocking(final ApiHttpClient client,
            final TypeReference typeReference) {
        return executeBlocking(client, ApiHttpClient.DEFAULT_TIMEOUT, typeReference);
    }

    public  ApiHttpResponse executeBlocking(final Duration timeout,
            final TypeReference typeReference) {
        return executeBlocking(apiHttpClient(), timeout, typeReference);
    }

    public  ApiHttpResponse executeBlocking(final ApiHttpClient client, final Duration timeout,
            TypeReference typeReference) {
        return client.executeBlocking(this, typeReference, timeout);
    }

    public  ApiHttpResponse executeBlocking(final JavaType javaType) {
        return executeBlocking(apiHttpClient(), ApiHttpClient.DEFAULT_TIMEOUT, javaType);
    }

    public  ApiHttpResponse executeBlocking(final ApiHttpClient client, final JavaType javaType) {
        return executeBlocking(apiHttpClient(), ApiHttpClient.DEFAULT_TIMEOUT, javaType);
    }

    public  ApiHttpResponse executeBlocking(final Duration timeout, final JavaType javaType) {
        return executeBlocking(apiHttpClient(), timeout, javaType);
    }

    public  ApiHttpResponse executeBlocking(final ApiHttpClient client, final Duration timeout,
            JavaType javaType) {
        return client.executeBlocking(this, javaType, timeout);
    }

    public CompletableFuture> send() {
        return apiHttpClient.send(this);
    }

    public ApiHttpResponse sendBlocking() {
        return sendBlocking(ApiHttpClient.DEFAULT_TIMEOUT);
    }

    public ApiHttpResponse sendBlocking(final Duration timeout) {
        return apiHttpClient.sendBlocking(this, timeout);
    }
}