code: public V call(Callable<V> callable) throws ExecutionException, RetryException {
          long startTime = System.nanoTime();
          for (int attemptNumber = 1; ; attemptNumber++) {
              Attempt<V> attempt;
              try {
                  V result = attemptTimeLimiter.call(callable);
                  attempt = new ResultAttempt<V>(result, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));
              } catch (Throwable t) {
                  attempt = new ExceptionAttempt<V>(t, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));
              }
  
              for (RetryListener listener : listeners) {
                  listener.onRetry(attempt);
              }
  
              if (!rejectionPredicate.apply(attempt)) {
                  return attempt.get();
              }
              if (stopStrategy.shouldStop(attempt)) {
                  throw new RetryException(attemptNumber, attempt);
              } else {
                  long sleepTime = waitStrategy.computeSleepTime(attempt);
                  try {
                      blockStrategy.block(sleepTime);
                  } catch (InterruptedException e) {
                      Thread.currentThread().interrupt();
                      throw new RetryException(attemptNumber, attempt);
                  }
              }
          }
      }
docs: Executes the given callable. If the rejection predicate
  accepts the attempt, the stop strategy is used to decide if a new attempt
  must be made. Then the wait strategy is used to decide how much time to sleep
  and a new attempt is made.
  
  @param callable the callable task to be executed
  @return the computed result of the given callable
  @throws ExecutionException if the given callable throws an exception, and the
  rejection predicate considers the attempt as successful. The original exception
  is wrapped into an ExecutionException.
  @throws RetryException     if all the attempts failed before the stop strategy decided
  to abort, or the thread was interrupted. Note that if the thread is interrupted,
  this exception is thrown and the thread's interrupt status is set.