001
002package io.vrap.rmf.base.client;
003
004import java.nio.charset.StandardCharsets;
005import java.util.HashMap;
006import java.util.Map;
007import java.util.Optional;
008
009import org.apache.commons.lang3.builder.EqualsBuilder;
010import org.apache.commons.lang3.builder.HashCodeBuilder;
011import org.apache.commons.lang3.builder.ToStringBuilder;
012
013public class ApiHttpResponse<U> extends Base implements ContextAware<ApiHttpResponse<U>> {
014
015    private int statusCode;
016    private ApiHttpHeaders headers;
017    private U body;
018    private String message;
019
020    private Map<Object, Object> contextMap = new HashMap<>();
021
022    public ApiHttpResponse(final int statusCode, final ApiHttpHeaders headers, final U body) {
023        this(statusCode, headers, body, null);
024    }
025
026    public ApiHttpResponse(final int statusCode, final ApiHttpHeaders headers, final U body, final String message) {
027        this.statusCode = statusCode;
028        this.headers = Optional.ofNullable(headers).orElse(new ApiHttpHeaders());
029        this.body = body;
030        this.message = message;
031    }
032
033    public ApiHttpResponse(final int statusCode, final ApiHttpHeaders headers, final U body, final String message,
034            final Map<Object, Object> contextMap) {
035        this.statusCode = statusCode;
036        this.headers = Optional.ofNullable(headers).orElse(new ApiHttpHeaders());
037        this.body = body;
038        this.message = message;
039        this.contextMap = contextMap;
040    }
041
042    public ApiHttpResponse(final ApiHttpResponse<U> response) {
043        this.statusCode = response.statusCode;
044        this.headers = response.headers;
045        this.body = response.body;
046        this.message = response.message;
047        this.contextMap = response.contextMap;
048    }
049
050    public Map<Object, Object> getContextMap() {
051        return contextMap;
052    }
053
054    public ApiHttpResponse<U> withContextMap(final Map<Object, Object> contextMap) {
055        ApiHttpResponse<U> response = copy();
056        response.contextMap = new HashMap<>(contextMap);
057
058        return response;
059    }
060
061    @SuppressWarnings("unchecked")
062    public <T> T getContext(Class<T> key) {
063        return (T) contextMap.get(key);
064    }
065
066    public <T> ApiHttpResponse<U> addContext(T value) {
067        ApiHttpResponse<U> response = copy();
068        Map<Object, Object> contextMap = new HashMap<>(response.contextMap);
069        contextMap.put(value.getClass(), value);
070        if (value instanceof ClassReferenceContext) {
071            contextMap.put(((ClassReferenceContext) value).classReference(), value);
072        }
073
074        response.contextMap = contextMap;
075
076        return response;
077    }
078
079    public Object getContext(Object key) {
080        return contextMap.get(key);
081    }
082
083    public ApiHttpResponse<U> addContext(Object key, Object value) {
084        ApiHttpResponse<U> response = copy();
085        Map<Object, Object> contextMap = new HashMap<>(response.contextMap);
086        contextMap.put(key, value);
087        response.contextMap = contextMap;
088
089        return response;
090    }
091
092    public int getStatusCode() {
093        return statusCode;
094    }
095
096    public ApiHttpResponse<U> withStatusCode(final int statusCode) {
097        ApiHttpResponse<U> response = copy();
098        response.statusCode = statusCode;
099
100        return response;
101    }
102
103    public ApiHttpHeaders getHeaders() {
104        return headers;
105    }
106
107    public ApiHttpResponse<U> withHeaders(final ApiHttpHeaders headers) {
108        ApiHttpResponse<U> response = copy();
109        response.headers = headers;
110
111        return response;
112    }
113
114    public U getBody() {
115        return body;
116    }
117
118    public ApiHttpResponse<U> withBody(final U body) {
119        ApiHttpResponse<U> response = copy();
120        response.body = body;
121
122        return response;
123    }
124
125    public String getMessage() {
126        return message;
127    }
128
129    public ApiHttpResponse<U> withMessage(final String message) {
130        ApiHttpResponse<U> response = copy();
131        response.message = message;
132
133        return response;
134    }
135
136    @Override
137    public String toString() {
138        return new ToStringBuilder(this).append("statusCode", statusCode)
139                .append("headers", headers)
140                .append("textInterpretedBody", getSecuredBody())
141                .toString();
142    }
143
144    static String tryToFilter(final String input) {
145        return input.replaceAll("(\"\\w*([Pp]ass|access_token|refresh_token)\\w*\"):\"[^\"]*\"",
146            "$1:\"**removed from output**\"");
147    }
148
149    public Optional<String> getBodyAsString() {
150        if (body instanceof byte[]) {
151            return Optional.of(body).map(b -> tryToFilter(new String((byte[]) b, StandardCharsets.UTF_8)));
152        }
153        else {
154            return Optional.ofNullable(body).map(Object::toString);
155        }
156    }
157
158    public String getSecuredBody() {
159        return getBodyAsString().orElse("empty body");
160    }
161
162    private ApiHttpResponse<U> copy() {
163        return new ApiHttpResponse<>(this);
164    }
165
166    @Override
167    public boolean equals(Object o) {
168        if (this == o)
169            return true;
170
171        if (o == null || getClass() != o.getClass())
172            return false;
173
174        ApiHttpResponse<?> response = (ApiHttpResponse<?>) o;
175
176        return new EqualsBuilder().append(statusCode, response.statusCode)
177                .append(headers, response.headers)
178                .append(body, response.body)
179                .append(message, response.message)
180                .append(contextMap, response.contextMap)
181                .isEquals();
182    }
183
184    @Override
185    public int hashCode() {
186        return new HashCodeBuilder(17, 37).append(statusCode)
187                .append(headers)
188                .append(body)
189                .append(message)
190                .append(contextMap)
191                .toHashCode();
192    }
193}