Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.tambapps.http.hyperpoet.AbstractHttpPoet Maven / Gradle / Ivy
package com.tambapps.http.hyperpoet;
import com.tambapps.http.hyperpoet.interceptor.ConsolePrintingInterceptor;
import com.tambapps.http.hyperpoet.io.IoUtils;
import com.tambapps.http.hyperpoet.io.composer.Composers;
import com.tambapps.http.hyperpoet.io.json.JsonGenerator;
import com.tambapps.http.hyperpoet.io.parser.Parsers;
import com.tambapps.http.hyperpoet.url.MultivaluedQueryParamComposingType;
import com.tambapps.http.hyperpoet.url.QueryParamComposer;
import com.tambapps.http.hyperpoet.url.UrlBuilder;
import com.tambapps.http.hyperpoet.util.CachedResponseBody;
import com.tambapps.http.hyperpoet.util.ContentTypeMapFunction;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.BufferedSink;
import okio.Okio;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* The HTTP client
*/
@Getter
@Setter
public class AbstractHttpPoet {
@SneakyThrows
public static AbstractHttpPoet newPoet() {
return (AbstractHttpPoet) Class.forName("com.tambapps.http.hyperpoet.HttpPoet").getDeclaredConstructor().newInstance();
}
public static final int DEFAULT_HISTORY_LIMIT = 10;
private OkHttpClient okHttpClient;
private final Map headers = new HashMap<>();
private final Map params = new HashMap<>();
private final JsonGenerator jsonGenerator = new JsonGenerator();
private final Map, Function> queryParamConverters = new HashMap<>();
private final QueryParamComposer queryParamComposer = new QueryParamComposer(queryParamConverters, MultivaluedQueryParamComposingType.REPEAT);
private final ContentTypeMapFunction composers = Composers.getMap(jsonGenerator, queryParamComposer);
private final ContentTypeMapFunction parsers = Parsers.getMap();
private Function errorResponseHandler = ErrorResponseHandlers.throwResponseHandler();
protected Function onPreExecute;
protected Function onPostExecute;
private String baseUrl;
private ContentType contentType;
private ContentType acceptContentType;
private History history;
public AbstractHttpPoet() {
this("");
}
public AbstractHttpPoet(OkHttpClient client) {
this(client, "");
}
public AbstractHttpPoet(String baseUrl) {
this(new OkHttpClient(), baseUrl);
final DateTimeFormatter ldtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
Function localDateTimeFormatter = (o) -> ldtf.format((TemporalAccessor) o);
final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
Function dateTimeFormatter = (o) -> dtf.format((TemporalAccessor) o);
/*
jsonGenerator.addConverter(LocalDateTime.class, localDateTimeFormatter);
jsonGenerator.addConverter(LocalDate.class, dateTimeFormatter);
*/
queryParamConverters.put(LocalDateTime.class, localDateTimeFormatter);
queryParamConverters.put(LocalDate.class, dateTimeFormatter);
}
public AbstractHttpPoet(OkHttpClient okHttpClient, String baseUrl) {
this.okHttpClient = okHttpClient;
this.baseUrl = baseUrl != null ? baseUrl : "";
}
/**
* Add/Replace the given header with the given value
*
* @param key the header name
* @param value the header value
*/
public void putHeader(Object key, Object value) {
headers.put(String.valueOf(key), String.valueOf(value));
}
public void putHeader(List> header) {
if (header.size() != 2) {
throw new IllegalArgumentException("Argument should have two elements");
}
putHeader(header.get(0), header.get(1));
}
/**
* Removes a header
*
* @param key the name of the header
* @return the removed header or null if there wern't any
*/
public String removeHeader(String key) {
return headers.remove(key);
}
protected Object doRequest(Request request,
Object requestBody, boolean shouldSkipHistory,
ContentType acceptContentTypeOverride, Function parserOverride,
Function responseHandler) throws IOException {
if (onPreExecute != null) {
onPreExecute.apply(request);
}
try (Response response = okHttpClient.newCall(request).execute()) {
Response effectiveResponse = handleHistory(response, shouldSkipHistory, requestBody, acceptContentTypeOverride, parserOverride);
if (onPostExecute != null) {
onPostExecute.apply(effectiveResponse);
}
return responseHandler.apply(effectiveResponse);
}
}
protected Object doRequest(Request request,
Object requestBody, Boolean shouldSkipHistory, Boolean shouldPrint, Boolean shouldPrintRequestBody, Boolean shouldPrintResponseBody,
ContentType acceptContentTypeOverride, Function parserOverride) throws IOException {
getInterceptors().stream()
.filter(i -> i instanceof ConsolePrintingInterceptor)
.map(i -> (ConsolePrintingInterceptor) i)
.findFirst().ifPresent(printingInterceptor -> {
printingInterceptor.setShouldPrint(shouldPrint != null ? shouldPrint : true);
printingInterceptor.setShouldPrintRequestBody(shouldPrintRequestBody != null ? shouldPrintRequestBody : true);
printingInterceptor.setShouldPrintResponseBody(shouldPrintResponseBody != null ? shouldPrintResponseBody : true);
});
if (onPreExecute != null) {
onPreExecute.apply(request);
}
try (Response response = okHttpClient.newCall(request).execute()) {
Response effectiveResponse = handleHistory(response, shouldSkipHistory, requestBody, acceptContentTypeOverride, parserOverride);
if (onPostExecute != null) {
onPostExecute.apply(effectiveResponse);
}
return handleResponse(effectiveResponse, acceptContentTypeOverride, parserOverride);
}
}
protected Object handleResponse(Response response, ContentType acceptContentTypeOverride, Function parserOverride) {
if (!response.isSuccessful()) {
return handleErrorResponse(response);
} else {
return parseResponse(response, acceptContentTypeOverride, parserOverride);
}
}
protected Object parseResponse(Response response, ContentType acceptContentTypeOverride, Function parserOverride) {
ResponseBody body = response.body();
if (body == null) {
return null;
}
Function parser = extractResponseBodyParser(response, acceptContentTypeOverride, parserOverride);
return parser.apply(body);
}
private ContentType extractResponseContentType(Response response, ContentType acceptContentTypeOverride) {
if (acceptContentTypeOverride != null) return acceptContentTypeOverride;
if (this.acceptContentType != null) return this.acceptContentType;
return getResponseContentType(response);
}
private Function extractResponseBodyParser(Response response, ContentType acceptContentTypeOverride, Function parserOverride) {
ContentType responseContentType = extractResponseContentType(response, acceptContentTypeOverride);
Function parser = parserOverride != null ? parserOverride : parsers.get(responseContentType);
if (parser != null) {
return parser;
} else {
return (o) -> Parsers.parseStringResponseBody((ResponseBody) o);
}
}
protected ContentType getResponseContentType(Response response) {
String contentTypeHeader = response.header(ContentType.HEADER);
return contentTypeHeader != null ? ContentType.valueOf(contentTypeHeader) : acceptContentType;
}
protected RequestBody requestBody(Object body, Function composerOverride, ContentType contentType, String method) throws IOException {
if (body == null) {
// request body must not be null for some methods, so we return an empty body instead
return okhttp3.internal.http.HttpMethod.requiresRequestBody(method) ? RequestBody.create(new byte[0]) : null;
}
// some "smart" conversions
Object composedBody;
if (body instanceof File) {
composedBody = IoUtils.getBytes((File) body);
} else if (body instanceof Path) {
composedBody = IoUtils.getBytes(((Path) body).toFile());
} else if (body instanceof Reader) {
composedBody = IoUtils.getText((Reader) body);
} else {
Function composer = composers.getOrDefault(contentType, composerOverride);
if (composer == null && (!(body instanceof RequestBody)
&& !(body instanceof String)
&& !(body instanceof InputStream)
&& !(body instanceof byte[]))) {
throw new IllegalStateException("No composer was found for content type " + contentType);
}
composedBody = composer != null ? composer.apply(body) : body;
}
MediaType mediaType = contentType != null ? contentType.toMediaType() : null;
return toRequestBody(composedBody, mediaType);
}
public static byte[] extractRequestBody(RequestBody requestBody) throws IOException {
if (requestBody == null || requestBody.isOneShot()) {
return null;
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (BufferedSink bufferedSink = Okio.buffer(Okio.sink(outputStream))) {
requestBody.writeTo(bufferedSink);
bufferedSink.flush();
return outputStream.toByteArray();
}
}
private RequestBody toRequestBody(Object object, MediaType mediaType) throws IOException {
if (object instanceof RequestBody) {
return (RequestBody) object;
} else if (object instanceof String) {
return RequestBody.create(object.toString().getBytes(StandardCharsets.UTF_8), mediaType);
} else if (object instanceof InputStream) {
return RequestBody.create(IoUtils.getBytes((InputStream) object), mediaType);
} else if (object instanceof byte[]) {
return RequestBody.create((byte[]) object, mediaType);
} else {
throw new IllegalStateException(
String.format("Couldn't transform composed data of type %s to a RequestBody."
+ "The result must either be a String, an InputStream, a byte array or a okhttp3.RequestBody",
object.getClass().getSimpleName()));
}
}
public Request request(String method, String urlOrEndpoint, Map, ?> params,
ContentType contentTypeOverride,
Object body, Function composerOverride, Map, ?> headers,
ContentType acceptContentTypeOverride) throws IOException {
ContentType contentType = contentTypeOverride != null ? contentTypeOverride : this.contentType;
// url stuff
String url =
new UrlBuilder(baseUrl, queryParamComposer).append(
urlOrEndpoint)
.addParams(this.params)
.addParams(params != null ? params : Collections.emptyMap())
.build();
RequestBody requestBody = requestBody(body, composerOverride, contentType, method);
Request.Builder builder = new Request.Builder().url(url).method(method, requestBody);
// headers stuff
for (Map.Entry entry : this.headers.entrySet()) {
builder.header(entry.getKey(), entry.getValue());
}
if (headers != null) {
for (Map.Entry, ?> entry : headers.entrySet()) {
builder.header(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()));
}
}
ContentType acceptContentType = acceptContentTypeOverride != null ? acceptContentTypeOverride : this.acceptContentType;
if (acceptContentType != null) {
builder.header("Accept", acceptContentType.toString());
}
if (contentType != null && body != null) {
// only specify Content-Type header if there is a body
builder.header(ContentType.HEADER, contentType.toString());
}
return builder.build();
}
protected Object handleErrorResponse(Response response) {
if (errorResponseHandler != null) {
return errorResponseHandler.apply(response);
} else {
return defaultHandleErrorResponse(response);
}
}
// used by method closure
@SneakyThrows
protected Object defaultHandleErrorResponse(Response response) {
ErrorResponseException exception = ErrorResponseException.from(response);
response.close();
throw exception;
}
public MultivaluedQueryParamComposingType getMultivaluedQueryParamComposingType() {
return queryParamComposer.getMultivaluedQueryParamComposingType();
}
public void setMultivaluedQueryParamComposingType(
MultivaluedQueryParamComposingType multivaluedQueryParamComposingType) {
queryParamComposer.setMultivaluedQueryParamComposingType(multivaluedQueryParamComposingType);
}
public void addInterceptor(Interceptor interceptor) {
this.okHttpClient = okHttpClient.newBuilder()
.addInterceptor(interceptor)
.build();
}
public void addNetworkInterceptor(Interceptor interceptor) {
this.okHttpClient = okHttpClient.newBuilder()
.addNetworkInterceptor(interceptor)
.build();
}
public List getInterceptors() {
return okHttpClient.interceptors();
}
public Interceptor getInterceptor() {
List interceptors = getInterceptors();
return !interceptors.isEmpty() ? interceptors.get(0) : null;
}
public List getNetworkInterceptors() {
return okHttpClient.networkInterceptors();
}
public Interceptor getNetworkInterceptor() {
List interceptors = getNetworkInterceptors();
return !interceptors.isEmpty() ? interceptors.get(0) : null;
}
public AbstractHttpPoet enableHistory() {
return enableHistory(DEFAULT_HISTORY_LIMIT);
}
public AbstractHttpPoet enableHistory(int limit) {
if (history == null) {
history = new History(limit);
} else {
history.setLimit(limit);
}
return this;
}
public void disableHistory() {
history = null;
}
public void setDefaultParser(Function parser) {
getParsers().setDefaultValue(parser);
}
public void configureOkHttpClient(Function configurer) {
OkHttpClient.Builder builder = okHttpClient.newBuilder();
configurer.apply(builder);
this.okHttpClient = builder.build();
}
protected Response handleHistory(Response response, Boolean skipHistory, Object requestBody,
ContentType acceptContentTypeOverride, Function parserOverride) throws IOException {
if (history == null || skipHistory != null && skipHistory) {
return response;
}
Response cachedResponse = CachedResponseBody.newResponseWitchCachedBody(response);
Function responseParser = extractResponseBodyParser(response, acceptContentTypeOverride, parserOverride);
history.add(new HttpExchange(cachedResponse, requestBody, responseParser));
return cachedResponse;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder()
.append(getClass().getSimpleName())
.append("(baseUrl=")
.append(baseUrl);
if (contentType != null) {
builder.append(", contentType=")
.append(contentType);
}
if (acceptContentType != null) {
builder.append(", acceptContentType=")
.append(acceptContentType);
}
return builder.append(')').toString();
}
}