001
002package io.vrap.rmf.base.client;
003
004import java.net.URI;
005import java.util.HashMap;
006import java.util.Map;
007import java.util.Optional;
008import java.util.concurrent.CompletableFuture;
009import java.util.function.Consumer;
010
011import com.fasterxml.jackson.core.type.TypeReference;
012import com.fasterxml.jackson.databind.JavaType;
013
014public class ContextApiHttpClientImpl extends AutoCloseableService implements ContextApiHttpClient {
015    private final ApiHttpClient client;
016
017    private final boolean closeHttpClient;
018
019    private Map<Object, Object> contextMap;
020
021    private final Consumer<ContextAware<ContextApiHttpClient>> consumer;
022
023    public ContextApiHttpClientImpl(final ApiHttpClient client) {
024        this(client, new HashMap<>(), null);
025    }
026
027    public ContextApiHttpClientImpl(final ApiHttpClient client, final Map<Object, Object> contextMap) {
028        this(client, contextMap, null);
029    }
030
031    public ContextApiHttpClientImpl(final ApiHttpClient client, final Map<Object, Object> contextMap,
032            final Consumer<ContextAware<ContextApiHttpClient>> consumer) {
033        this(client, contextMap, consumer, true);
034    }
035
036    public ContextApiHttpClientImpl(final ApiHttpClient client, final boolean closeHttpClient) {
037        this(client, new HashMap<>(), null, closeHttpClient);
038    }
039
040    public ContextApiHttpClientImpl(final ApiHttpClient client, final Map<Object, Object> contextMap,
041            final boolean closeHttpClient) {
042        this(client, contextMap, null, closeHttpClient);
043    }
044
045    public ContextApiHttpClientImpl(final ApiHttpClient client, final Map<Object, Object> contextMap,
046            final Consumer<ContextAware<ContextApiHttpClient>> consumer, final boolean closeHttpClient) {
047        this.client = client;
048        this.contextMap = contextMap;
049        this.consumer = consumer;
050        this.closeHttpClient = closeHttpClient;
051    }
052
053    public ContextApiHttpClientImpl(final ContextApiHttpClientImpl c) {
054        this.client = c.client;
055        this.contextMap = c.contextMap;
056        this.consumer = c.consumer;
057        this.closeHttpClient = c.closeHttpClient;
058    }
059
060    public Map<Object, Object> getContextMap() {
061        return contextMap;
062    }
063
064    public ContextApiHttpClient withContextMap(final Map<Object, Object> contextMap) {
065        final ContextApiHttpClientImpl client = copy();
066        client.contextMap = new HashMap<>(contextMap);
067
068        return client;
069    }
070
071    @SuppressWarnings("unchecked")
072    public <T> T getContext(Class<T> key) {
073        return (T) contextMap.get(key);
074    }
075
076    public <T> ContextApiHttpClient addContext(final T value) {
077        final ContextApiHttpClientImpl client = copy();
078        final Map<Object, Object> contextMap = new HashMap<>(client.contextMap);
079        contextMap.put(value.getClass(), value);
080        if (value instanceof ClassReferenceContext) {
081            contextMap.put(((ClassReferenceContext) value).classReference(), value);
082        }
083        client.contextMap = contextMap;
084
085        return client;
086    }
087
088    public Object getContext(final Object key) {
089        return contextMap.get(key);
090    }
091
092    public ContextApiHttpClient addContext(final Object key, final Object value) {
093        final ContextApiHttpClientImpl client = copy();
094        final Map<Object, Object> contextMap = new HashMap<>(client.contextMap);
095        contextMap.put(key, value);
096        client.contextMap = contextMap;
097
098        return client;
099    }
100
101    private ContextApiHttpClientImpl copy() {
102        return new ContextApiHttpClientImpl(this);
103    }
104
105    private void restoreContext() {
106        Optional.ofNullable(consumer).ifPresent(c -> c.accept(this));
107    }
108
109    @Override
110    public <O> CompletableFuture<ApiHttpResponse<O>> execute(final ApiHttpRequest request, final Class<O> outputType) {
111        restoreContext();
112        return client.execute(request.withContextMap(contextMap), outputType);
113    }
114
115    @Override
116    public <O> CompletableFuture<ApiHttpResponse<O>> execute(final ApiHttpRequest request,
117            final TypeReference<O> outputType) {
118        restoreContext();
119        return client.execute(request.withContextMap(contextMap), outputType);
120    }
121
122    @Override
123    public <O> CompletableFuture<ApiHttpResponse<O>> execute(final ApiHttpRequest request, final JavaType outputType) {
124        restoreContext();
125        return client.execute(request.withContextMap(contextMap), outputType);
126    }
127
128    @Override
129    public <O> CompletableFuture<ApiHttpResponse<O>> execute(final ClientRequestCommand<O> method) {
130        restoreContext();
131        return method.execute(this);
132    }
133
134    @Override
135    public ResponseSerializer getSerializerService() {
136        return client.getSerializerService();
137    }
138
139    @Override
140    public URI getBaseUri() {
141        return client.getBaseUri();
142    }
143
144    @Override
145    public CompletableFuture<ApiHttpResponse<byte[]>> execute(final ApiHttpRequest request) {
146        restoreContext();
147        return client.execute(request.withContextMap(contextMap));
148    }
149
150    @Override
151    protected void internalClose() {
152        if (closeHttpClient) {
153            closeQuietly(client);
154        }
155        contextMap.values().forEach(o -> {
156            if (o instanceof AutoCloseable) {
157                closeQuietly((AutoCloseable) o);
158            }
159        });
160    }
161}