All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.univapay.sdk.builders.RetrofitRequestCaller Maven / Gradle / Ivy

The newest version!
package com.univapay.sdk.builders;

import com.google.gson.JsonParseException;
import com.univapay.sdk.constants.UnivapayConstants;
import com.univapay.sdk.models.errors.TooManyRequestsException;
import com.univapay.sdk.models.errors.UnivapayErrorBody;
import com.univapay.sdk.models.errors.UnivapayException;
import com.univapay.sdk.models.response.UnivapayResponse;
import com.univapay.sdk.types.IdempotencyStatus;
import com.univapay.sdk.utils.Sleeper;
import com.univapay.sdk.utils.UnivapayCallback;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Optional;
import okhttp3.MediaType;
import okhttp3.ResponseBody;
import org.jetbrains.annotations.NotNull;
import retrofit2.*;

public class RetrofitRequestCaller implements Request {

  private final Call apiCall;
  private final Converter errorConverter;

  public RetrofitRequestCaller(Retrofit retrofit, Call apiCall) {
    this.errorConverter =
        retrofit.responseBodyConverter(UnivapayErrorBody.class, new Annotation[0]);
    this.apiCall = apiCall;
  }

  public RetrofitRequestCaller(
      Converter errorConverter, Call apiCall) {
    this.errorConverter = errorConverter;
    this.apiCall = apiCall;
  }

  @Override
  public Cancelable dispatch(final UnivapayCallback callback) {

    apiCall.enqueue(
        new Callback() {
          @Override
          public void onResponse(@NotNull Call call, @NotNull Response response) {

            E model;
            try {
              model = extractModel(response);
            } catch (Throwable e) {
              callback.getFailure(e);
              return;
            }

            callback.getResponse(model);
          }

          @Override
          public void onFailure(@NotNull Call call, @NotNull Throwable t) {

            // OkHttp, on cancel, throws this java.io.IOException: Canceled
            if (t instanceof IOException && "Canceled".equals(t.getMessage())) {
              // Make sure we make this more transparent for the consumer
              callback.onCancel();
            } else {
              callback.getFailure(t);
            }
          }
        });

    // return method
    return apiCall::cancel;
  }

  @Override
  public E dispatch() throws IOException, UnivapayException, TooManyRequestsException {
    try {
      return dispatch(1, null);
    } catch (InterruptedException e) {
      throw new AssertionError("Thread never sleep when maxRetry is 1");
    }
  }

  @Override
  public E dispatch(int maxRetry, Sleeper sleeper)
      throws IOException, UnivapayException, TooManyRequestsException, InterruptedException {

    Exception lastException = null;
    Call call = apiCall;

    for (int retry = 0; retry < maxRetry; retry++) {
      try {
        return extractModel(call.execute());
      } catch (IOException | TooManyRequestsException e) {
        lastException = e;
        if (retry + 1 < maxRetry) {
          sleeper.sleep();
          call = call.clone();
        }
      }
    }

    assert lastException != null;
    if (lastException instanceof IOException) {
      throw (IOException) lastException;
    } else {
      throw (TooManyRequestsException) lastException;
    }
  }

  private E extractModel(Response response)
      throws UnivapayException, IOException, TooManyRequestsException {
    if (response.isSuccessful()) {
      E model = response.body();
      String unparsedIdempotencyStatus =
          response.headers().get(UnivapayConstants.idempotencyStatusHeaderName);

      if (model != null) {
        if (unparsedIdempotencyStatus == null) {
          model.setIdempotencyStatus(IdempotencyStatus.NO_STATUS);
        } else {
          model.setIdempotencyStatus(
              IdempotencyStatus.valueOf(unparsedIdempotencyStatus.toUpperCase()));
        }
      }
      return model;
    } else if (response.code() == 429 /* Too Many Requests */) {
      throw new TooManyRequestsException(response.code(), response.message());
    } else {
      UnivapayErrorBody body = null;
      ResponseBody errorBody = response.errorBody();
      MediaType contentType = errorBody.contentType();

      if (contentType != null && contentType.subtype().equals("json")) {

        body =
            Optional.of(errorBody)
                .flatMap(
                    value -> {
                      try { // {code:null, status:null, details:null}
                        return Optional.ofNullable(this.errorConverter.convert(errorBody));
                      } catch (IOException | JsonParseException e) {
                        return Optional.empty();
                      }
                    })
                .filter(
                    value ->
                        value.getCode() != null
                            || value.getStatus() != null
                            || value.getErrors() != null)
                .orElse(null);
      }
      throw new UnivapayException(response.code(), response.message(), body);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy