com.gocardless.http.HttpClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gocardless-pro Show documentation
Show all versions of gocardless-pro Show documentation
Client library for accessing the GoCardless Pro API
package com.gocardless.http;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import com.github.rholder.retry.*;
import com.gocardless.GoCardlessException;
import com.gocardless.errors.GoCardlessInternalException;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import okhttp3.*;
/**
* An HTTP client that can execute {@link ApiRequest}s.
*
* Users of this library should not need to access this class directly.
*/
public class HttpClient {
/**
* The maximum number of times that a request can be retried.
*/
public static final int MAX_RETRIES = 3;
/**
* The amount of time to wait before retrying a failed request in milli seconds
*/
public static final long WAIT_BETWEEN_RETRIES_IN_MILLI_SECONDS = 500;
/**
* See http://tools.ietf.org/html/rfc7230#section-3.2.6.
*/
private static final String DISALLOWED_USER_AGENT_CHARACTERS =
"[^\\w!#$%&'\\*\\+\\-\\.\\^`\\|~]";
private static final String USER_AGENT =
String.format("gocardless-pro-java/5.23.0 java/%s %s/%s %s/%s",
cleanUserAgentToken(System.getProperty("java.vm.specification.version")),
cleanUserAgentToken(System.getProperty("java.vm.name")),
cleanUserAgentToken(System.getProperty("java.version")),
cleanUserAgentToken(System.getProperty("os.name")),
cleanUserAgentToken(System.getProperty("os.version")));
private static final RequestBody EMPTY_BODY = RequestBody.create(null, new byte[0]);
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json");
private static final Map HEADERS;
static {
ImmutableMap.Builder builder = ImmutableMap.builder();
builder.put("GoCardless-Version", "2015-07-06");
builder.put("Accept", "application/json");
builder.put("GoCardless-Client-Library", "gocardless-pro-java");
builder.put("GoCardless-Client-Version", "5.23.0");
HEADERS = builder.build();
}
private final OkHttpClient rawClient;
private final UrlFormatter urlFormatter;
private final ResponseParser responseParser;
private final RequestWriter requestWriter;
private final String credentials;
private final boolean errorOnIdempotencyConflict;
private final int maxNoOfRetries;
private final long waitBetweenRetriesInMilliSeconds;
/**
* Constructor. Users of this library should not need to access this class directly - you should
* instantiate a GoCardlessClient and its underlying HttpClient using
* GoCardlessClient.newBuilder().
*
* @param accessToken the access token.
* @param baseUrl base URI to make requests against.
* @param rawClient the OkHttpClient instance to use to make requests (which will be configured
* to log requests with LoggingInterceptor).
*/
public HttpClient(String accessToken, String baseUrl, OkHttpClient rawClient,
boolean errorOnIdempotencyConflict, int maxNoOfRetries,
long waitBetweenRetriesInMilliSeconds) {
this.rawClient = rawClient;
this.urlFormatter = new UrlFormatter(baseUrl);
Gson gson = GsonFactory.build();
this.responseParser = new ResponseParser(gson);
this.requestWriter = new RequestWriter(gson);
this.credentials = String.format("Bearer %s", accessToken);
this.errorOnIdempotencyConflict = errorOnIdempotencyConflict;
this.maxNoOfRetries = maxNoOfRetries;
this.waitBetweenRetriesInMilliSeconds = waitBetweenRetriesInMilliSeconds;
}
public boolean isErrorOnIdempotencyConflict() {
return this.errorOnIdempotencyConflict;
}
@VisibleForTesting
public int getMaxNoOfRetries() {
return this.maxNoOfRetries;
}
T execute(ApiRequest apiRequest) {
Request request = buildRequest(apiRequest);
Response response = execute(request);
return parseResponseBody(apiRequest, response);
}
ApiResponse executeWrapped(ApiRequest apiRequest) {
Request request = buildRequest(apiRequest);
Response response = execute(request);
T resource = parseResponseBody(apiRequest, response);
return new ApiResponse<>(resource, response.code(), response.headers().toMultimap());
}
T executeWithRetries(final ApiRequest apiRequest) {
Retryer retrier = RetryerBuilder.newBuilder()
.retryIfExceptionOfType(GoCardlessNetworkException.class)
.retryIfExceptionOfType(GoCardlessInternalException.class)
.withWaitStrategy(WaitStrategies.fixedWait(this.waitBetweenRetriesInMilliSeconds,
MILLISECONDS))
.withStopStrategy(StopStrategies.stopAfterAttempt(this.maxNoOfRetries)).build();
Callable executeOnce = new Callable() {
@Override
public T call() throws Exception {
return execute(apiRequest);
}
};
try {
return retrier.call(executeOnce);
} catch (ExecutionException | RetryException e) {
Throwable cause = e.getCause();
throw Throwables.propagate(cause);
}
}
private Request buildRequest(ApiRequest apiRequest) {
HttpUrl url = apiRequest.getUrl(urlFormatter);
Request.Builder request =
new Request.Builder().url(url).headers(Headers.of(apiRequest.getHeaders()))
.header("Authorization", credentials).header("User-Agent", USER_AGENT)
.method(apiRequest.getMethod(), getBody(apiRequest));
for (Map.Entry entry : HEADERS.entrySet()) {
request = request.header(entry.getKey(), entry.getValue());
}
return request.build();
}
private RequestBody getBody(ApiRequest request) {
if (!request.hasBody()) {
if (request.getMethod().equals("GET")) {
return null;
} else {
return EMPTY_BODY;
}
}
String json = requestWriter.write(request, request.getRequestEnvelope());
return RequestBody.create(MEDIA_TYPE, json);
}
private Response execute(Request request) {
Response response;
try {
response = rawClient.newCall(request).execute();
} catch (IOException e) {
throw new GoCardlessNetworkException("Failed to execute request", e);
}
if (!response.isSuccessful()) {
throw handleErrorResponse(response);
}
return response;
}
private T parseResponseBody(ApiRequest request, Response response) {
try {
String responseBody = response.body().string();
return request.parseResponse(responseBody, responseParser);
} catch (IOException e) {
throw new GoCardlessNetworkException("Failed to read response body", e);
}
}
private GoCardlessException handleErrorResponse(Response response) {
try {
String responseBody = response.body().string();
return responseParser.parseError(responseBody);
} catch (IOException e) {
throw new GoCardlessNetworkException("Failed to read response body", e);
}
}
private static String cleanUserAgentToken(String s) {
return s.replaceAll(DISALLOWED_USER_AGENT_CHARACTERS, "_");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy