com.ebay.clients.impl.EbayClientImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ebay-sdk Show documentation
Show all versions of ebay-sdk Show documentation
Java SDK for eBay REST APIs
package com.ebay.clients.impl;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.Variant;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ebay.clients.models.EbayError;
import com.ebay.clients.models.ErrorResponse;
import com.ebay.exceptions.EbayErrorResponseException;
import com.ebay.exceptions.EbayException;
import com.ebay.exceptions.EbayNotFoundResponseException;
import com.ebay.identity.oauth2.token.models.UserToken;
import com.ebay.models.RequestRetryConfiguration;
import com.github.rholder.retry.Attempt;
import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.RetryListener;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
public class EbayClientImpl {
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String OAUTH_USER_TOKEN_PREFIX = "Bearer ";
private static final Client REST_CLIENT = ClientBuilder.newClient()
.property(ClientProperties.CONNECT_TIMEOUT, 60000).property(ClientProperties.READ_TIMEOUT, 600000)
.register(JacksonFeature.class);
private static final String UTF_8_ENCODING = "utf-8";
private static final Variant ENTITY_VARIANT = new Variant(MediaType.APPLICATION_JSON_TYPE, Locale.US,
UTF_8_ENCODING);
private static final long ONE = 1;
private static final long TWO = 2;
private static final int TOO_MANY_REQUESTS_STATUS_CODE = 429;
private static final int USER_ERROR_ERROR_ID = 25002;
private static final int SYSTEM_ERROR_ERROR_ID = 25001;
private static final String RETRY_ATTEMPT_MESSAGE = "Waited %s seconds since first retry attempt. This is attempt %s. Retrying due to Response Status Code of %d and Body of:\n%s";
private static final String RETRY_FAILED_MESSAGE = "Request retry has failed.";
private static final Logger LOGGER = LoggerFactory.getLogger(EbayClientImpl.class);
private final URI baseUri;
private final UserToken userToken;
private final RequestRetryConfiguration requestRetryConfiguration;
public EbayClientImpl(final URI baseUri, final UserToken userToken,
final RequestRetryConfiguration requestRetryConfiguration) {
this.baseUri = baseUri;
this.userToken = userToken;
this.requestRetryConfiguration = requestRetryConfiguration;
}
protected WebTarget getWebTarget() {
return REST_CLIENT.target(baseUri);
}
protected T get(final WebTarget webTarget, final Class entityType, final Status... expectedStatus) {
final Callable responseCallable = new Callable() {
@Override
public Response call() throws Exception {
Response response = webTarget.request().header(AUTHORIZATION_HEADER, getUserToken()).get();
if (Status.UNAUTHORIZED.getStatusCode() == response.getStatus()) {
userToken.refreshToken();
response = webTarget.request().header(AUTHORIZATION_HEADER, getUserToken()).get();
}
return response;
}
};
final Response response = invokeResponseCallable(responseCallable);
return handleResponse(response, entityType, expectedStatus);
}
protected V post(final WebTarget webTarget, final T object, final Class entityType,
final Status... expectedStatus) {
final Callable responseCallable = new Callable() {
@Override
public Response call() throws Exception {
final Entity entity = Entity.entity(object, ENTITY_VARIANT);
Response response = webTarget.request().header(AUTHORIZATION_HEADER, getUserToken()).post(entity);
if (Status.UNAUTHORIZED.getStatusCode() == response.getStatus()) {
userToken.refreshToken();
response = webTarget.request().header(AUTHORIZATION_HEADER, getUserToken()).post(entity);
}
return response;
}
};
final Response response = invokeResponseCallable(responseCallable);
return handleResponse(response, entityType, expectedStatus);
}
protected void put(final WebTarget webTarget, final T object, final Status... expectedStatus) {
final Callable responseCallable = new Callable() {
@Override
public Response call() throws Exception {
final Entity entity = Entity.entity(object, ENTITY_VARIANT);
Response response = webTarget.request().header(AUTHORIZATION_HEADER, getUserToken()).put(entity);
if (Status.UNAUTHORIZED.getStatusCode() == response.getStatus()) {
userToken.refreshToken();
response = webTarget.request().header(AUTHORIZATION_HEADER, getUserToken()).put(entity);
}
return response;
}
};
final Response response = invokeResponseCallable(responseCallable);
handleResponse(response, expectedStatus);
}
protected void delete(final WebTarget webTarget, final Status... expectedStatus) {
final Callable responseCallable = new Callable() {
@Override
public Response call() throws Exception {
Response response = webTarget.request().header(AUTHORIZATION_HEADER, getUserToken()).delete();
if (Status.UNAUTHORIZED.getStatusCode() == response.getStatus()) {
userToken.refreshToken();
response = webTarget.request().header(AUTHORIZATION_HEADER, getUserToken()).delete();
}
return response;
}
};
final Response response = invokeResponseCallable(responseCallable);
handleResponse(response, expectedStatus);
}
private Response invokeResponseCallable(final Callable responseCallable) {
final Retryer retryer = buildResponseRetryer();
try {
return retryer.call(responseCallable);
} catch (ExecutionException | RetryException e) {
throw new EbayException(RETRY_FAILED_MESSAGE, e);
}
}
private Retryer buildResponseRetryer() {
final RetryListener retryListener = new RetryListener() {
@Override
public void onRetry(Attempt attempt) {
final long attemptNumber = attempt.getAttemptNumber();
if (attemptNumber > ONE) {
final long delaySinceFirstAttemptInMilliseconds = attempt.getDelaySinceFirstAttempt();
final long delaySinceFirstAttemptInSeconds = TimeUnit.SECONDS
.convert(delaySinceFirstAttemptInMilliseconds, TimeUnit.MILLISECONDS);
final Response response = (Response) attempt.getResult();
response.bufferEntity();
LOGGER.warn(String.format(RETRY_ATTEMPT_MESSAGE, delaySinceFirstAttemptInSeconds, attemptNumber,
response.getStatus(), response.readEntity(String.class)));
}
}
};
final long maximumWaitDuration = requestRetryConfiguration.getMininumWaitDuration() * TWO;
return RetryerBuilder. newBuilder().retryIfResult(this::shouldRetryResponse)
.withWaitStrategy(WaitStrategies.randomWait(requestRetryConfiguration.getMininumWaitDuration(),
requestRetryConfiguration.getMininumWaitUnit(), maximumWaitDuration,
requestRetryConfiguration.getMininumWaitUnit()))
.withRetryListener(retryListener)
.withStopStrategy(StopStrategies.stopAfterDelay(requestRetryConfiguration.getTimeoutDuration(),
requestRetryConfiguration.getTimeoutUnit()))
.build();
}
private boolean shouldRetryResponse(final Response response) {
return Status.Family.SERVER_ERROR == Status.Family.familyOf(response.getStatus())
|| TOO_MANY_REQUESTS_STATUS_CODE == response.getStatus() || shouldRetryBadRequest(response);
}
private boolean shouldRetryBadRequest(final Response response) {
if (Status.BAD_REQUEST.getStatusCode() == response.getStatus()) {
response.bufferEntity();
final ErrorResponse errorResponse = response.readEntity(ErrorResponse.class);
return (errorResponse != null) && errorResponse.getErrors().stream().map(EbayError::getErrorId)
.anyMatch(errorId -> (SYSTEM_ERROR_ERROR_ID == errorId) || (USER_ERROR_ERROR_ID == errorId));
}
return false;
}
private T handleResponse(final Response response, final Class entityType, final Status... expectedStatus) {
final List expectedStatusCodes = Arrays.asList(expectedStatus).stream().map(Status::getStatusCode)
.collect(Collectors.toList());
if (expectedStatusCodes.contains(response.getStatus())) {
return response.readEntity(entityType);
} else if (Status.NOT_FOUND.getStatusCode() == response.getStatus()) {
throw new EbayNotFoundResponseException(response);
}
throw new EbayErrorResponseException(response);
}
private void handleResponse(final Response response, final Status... expectedStatus) {
final List expectedStatusCodes = Arrays.asList(expectedStatus).stream().map(Status::getStatusCode)
.collect(Collectors.toList());
if (expectedStatusCodes.contains(response.getStatus())) {
return;
} else if (Status.NOT_FOUND.getStatusCode() == response.getStatus()) {
throw new EbayNotFoundResponseException(response);
}
throw new EbayErrorResponseException(response);
}
private String getUserToken() {
return new StringBuilder().append(OAUTH_USER_TOKEN_PREFIX).append(userToken.getToken()).toString();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy