001
002package io.vrap.rmf.base.client;
003
004import java.net.MalformedURLException;
005import java.net.URI;
006import java.net.URL;
007import java.nio.charset.StandardCharsets;
008import java.util.HashMap;
009import java.util.Map;
010import java.util.Optional;
011
012import org.apache.commons.lang3.builder.EqualsBuilder;
013import org.apache.commons.lang3.builder.HashCodeBuilder;
014import org.apache.commons.lang3.builder.ToStringBuilder;
015
016public class ApiHttpRequest extends Base implements ContextAware<ApiHttpRequest> {
017
018    private ApiHttpMethod method;
019    private URI uri;
020    private ApiHttpHeaders headers;
021    private byte[] body;
022
023    private Map<Object, Object> contextMap = new HashMap<>();
024
025    public ApiHttpRequest() {
026    }
027
028    public ApiHttpRequest(final ApiHttpMethod method, final URI uri, final ApiHttpHeaders headers, final byte[] body,
029            final Map<Object, Object> contextMap) {
030        this.method = method;
031        this.uri = uri;
032        this.headers = headers;
033        this.body = body;
034        this.contextMap = contextMap;
035    }
036
037    public ApiHttpRequest(final ApiHttpMethod method, final URI uri, final ApiHttpHeaders headers, final byte[] body) {
038        this.method = method;
039        this.uri = uri;
040        this.headers = headers;
041        this.body = body;
042    }
043
044    public ApiHttpRequest(final ApiHttpRequest r) {
045        this.method = r.method;
046        this.uri = r.uri;
047        this.headers = r.headers;
048        this.body = r.body;
049        this.contextMap = r.contextMap;
050    }
051
052    public Map<Object, Object> getContextMap() {
053        return contextMap;
054    }
055
056    public ApiHttpRequest withContextMap(final Map<Object, Object> contextMap) {
057        final ApiHttpRequest request = copy();
058        request.contextMap = new HashMap<>(contextMap);
059
060        return request;
061    }
062
063    @SuppressWarnings("unchecked")
064    public <T> T getContext(Class<T> key) {
065        return (T) contextMap.get(key);
066    }
067
068    public <T> ApiHttpRequest addContext(T value) {
069        final ApiHttpRequest request = copy();
070        final Map<Object, Object> contextMap = new HashMap<>(request.contextMap);
071        contextMap.put(value.getClass(), value);
072        if (value instanceof ClassReferenceContext) {
073            contextMap.put(((ClassReferenceContext) value).classReference(), value);
074        }
075
076        request.contextMap = contextMap;
077
078        return request;
079    }
080
081    public Object getContext(Object key) {
082        return contextMap.get(key);
083    }
084
085    public ApiHttpRequest addContext(Object key, Object value) {
086        final ApiHttpRequest request = copy();
087        final Map<Object, Object> contextMap = new HashMap<>(request.contextMap);
088        contextMap.put(key, value);
089        request.contextMap = contextMap;
090
091        return request;
092    }
093
094    public ApiHttpMethod getMethod() {
095        return method;
096    }
097
098    public ApiHttpRequest withMethod(final ApiHttpMethod method) {
099        ApiHttpRequest request = copy();
100        request.method = method;
101
102        return request;
103    }
104
105    public ApiHttpHeaders getHeaders() {
106        if (headers == null) {
107            this.headers = new ApiHttpHeaders();
108        }
109        return headers;
110    }
111
112    public ApiHttpRequest addHeader(final String key, final String value) {
113        ApiHttpRequest request = copy();
114        request.headers = getHeaders().addHeader(key, value);
115
116        return request;
117    }
118
119    public ApiHttpRequest withHeaders(final ApiHttpHeaders headers) {
120        ApiHttpRequest request = copy();
121        request.headers = headers;
122        return request;
123    }
124
125    public ApiHttpRequest withHeader(final String key, final String value) {
126        ApiHttpRequest request = copy();
127        request.headers = getHeaders().withHeader(key, value);
128
129        return request;
130    }
131
132    public ApiHttpRequest withoutHeader(final String key) {
133        ApiHttpRequest request = copy();
134        request.headers = getHeaders().withoutHeader(key);
135
136        return request;
137    }
138
139    public byte[] getBody() {
140        return body;
141    }
142
143    public ApiHttpRequest withBody(final byte[] body) {
144        ApiHttpRequest request = copy();
145        request.body = body;
146        return request;
147    }
148
149    public ApiHttpRequest withBody(final String body) {
150        ApiHttpRequest request = copy();
151        if (body == null) {
152            request.body = null;
153        }
154        else {
155            request.body = body.getBytes(StandardCharsets.UTF_8);
156        }
157
158        return request;
159    }
160
161    public URI getUri() {
162        return uri;
163    }
164
165    public URL getUrl() {
166        try {
167            return uri.toURL();
168        }
169        catch (MalformedURLException e) {
170            throw new IllegalStateException("Malformed URI", e);
171        }
172    }
173
174    public ApiHttpRequest withUri(final String uri) {
175        ApiHttpRequest request = copy();
176        request.uri = URI.create(uri);
177        return request;
178    }
179
180    public ApiHttpRequest withUri(final URI uri) {
181        ApiHttpRequest request = copy();
182        request.uri = uri;
183
184        return request;
185    }
186
187    public ApiHttpRequest resolve(final URI baseUri) {
188        return withUri(baseUri.resolve(this.uri));
189    }
190
191    @Override
192    public String toString() {
193        return new ToStringBuilder(this).append("method", method)
194                .append("uri", "\"" + uri + "\"")
195                .append("headers", headers)
196                .append("textInterpretedBody", getSecuredBody())
197                .toString();
198    }
199
200    public String getSecuredBody() {
201        return Optional.ofNullable(body)
202                .map(b -> tryToFilter(new String(b, StandardCharsets.UTF_8)))
203                .orElse("empty body");
204    }
205
206    static String tryToFilter(final String input) {
207        return input.replaceAll("(\"\\w*([Pp]ass|access_token|refresh_token)\\w*\"):\"[^\"]*\"",
208            "$1:\"**removed from output**\"");
209    }
210
211    private ApiHttpRequest copy() {
212        return new ApiHttpRequest(this);
213    }
214
215    @Override
216    public boolean equals(Object o) {
217        if (this == o)
218            return true;
219
220        if (o == null || getClass() != o.getClass())
221            return false;
222
223        ApiHttpRequest request = (ApiHttpRequest) o;
224
225        return new EqualsBuilder().append(method, request.method)
226                .append(uri, request.uri)
227                .append(headers, request.headers)
228                .append(body, request.body)
229                .append(contextMap, request.contextMap)
230                .isEquals();
231    }
232
233    @Override
234    public int hashCode() {
235        return new HashCodeBuilder(17, 37).append(method)
236                .append(uri)
237                .append(headers)
238                .append(body)
239                .append(contextMap)
240                .toHashCode();
241    }
242}