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