class ExponentialBackoffIntervalCalculator {

  //we were using the same default in multiple places, so it has been moved here for now
  private static final int MAX_RETRY_INTERVAL_EXPONENT = 5;

  public static final int UNLIMITED_RETRIES = -1;

  private final int initialInterval;
  // other calculators express this as max wait
  private final int maxRetryIntervalExponent;
  private final int maxRetries;
  final AtomicInteger currentReconnectAttempt = new AtomicInteger();

  public ExponentialBackoffIntervalCalculator(int initialInterval, int maxRetries) {
    this.initialInterval = initialInterval;
    this.maxRetries = maxRetries;
    this.maxRetryIntervalExponent = MAX_RETRY_INTERVAL_EXPONENT;
  }

  public long getInterval(int retryIndex) {
    int exponentOfTwo = retryIndex;
    if (exponentOfTwo > maxRetryIntervalExponent) {
      exponentOfTwo = maxRetryIntervalExponent;
    }
    return (long) initialInterval * (1 << exponentOfTwo);
  }

  public void resetReconnectAttempts() {
    currentReconnectAttempt.set(0);
  }

  public final long nextReconnectInterval() {
    int exponentOfTwo = currentReconnectAttempt.getAndIncrement();
    return getInterval(exponentOfTwo);
  }

  public int getCurrentReconnectAttempt() {
    return currentReconnectAttempt.get();
  }

  public boolean shouldRetry() {
    return maxRetries < 0 || currentReconnectAttempt.get() < maxRetries;
  }

  public static ExponentialBackoffIntervalCalculator from(RequestConfig requestConfig) {<FILL_FUNCTION_BODY>}
}

    final int requestRetryBackoffInterval = Optional.ofNullable(requestConfig)
        .map(RequestConfig::getRequestRetryBackoffInterval)
        .orElse(Config.DEFAULT_REQUEST_RETRY_BACKOFFINTERVAL);
    final int requestRetryBackoffLimit = Optional.ofNullable(requestConfig)
        .map(RequestConfig::getRequestRetryBackoffLimit)
        .orElse(Config.DEFAULT_REQUEST_RETRY_BACKOFFLIMIT);
    return new ExponentialBackoffIntervalCalculator(requestRetryBackoffInterval, requestRetryBackoffLimit);
  
<no_super_class>