code: public R call() throws ExecutionException, RetryException {
          long elapsed = 0;
          TimeUnit unit = TimeUnit.MILLISECONDS;
          Stopwatch watch = Stopwatch.createStarted();
          
          for (int attempt = 1; ; attempt++) {
              Tried<R> target = null;
              if (!this.rejection.apply(target = oneCall())) {
                  elapsed = watch.stop().elapsed(unit);
                  
                  if (log.isDebugEnabled()) {
                      log.debug(String.format("Retrying %s at %s attempt. elapsed: %s ms", 
                              target.hasResult() ? "successfully" : "rejection with exception", attempt, elapsed));
                  }
                  
                  return target.get();
              }
              
              if (this.getStopStrategy().shouldStop(attempt, watch.elapsed(unit))) {
                  elapsed = watch.stop().elapsed(unit);
                  
                  if (log.isDebugEnabled()) {
                      log.debug(String.format("Retrying stopped at %s attempt. elapsed: %s ms", attempt, elapsed));
                  }
                  
                  throw new RetryException(attempt, target);
              } else {
                  long sleepTime = this.getWaitStrategy()
                          .computeSleepTime(attempt, watch.elapsed(unit));
                  
                  try {
                      this.getBlockStrategy().block(sleepTime);
                      if (log.isDebugEnabled()) {
                          log.debug(String.format("Retrying blocked %s ms at %s attempt", sleepTime, attempt));
                      }
                  } catch (InterruptedException e) {
                      Thread.currentThread().interrupt();
                      elapsed = watch.stop().elapsed(unit);
                      
                      if (log.isDebugEnabled()) {
                          log.debug(String.format(
                                  "Retrying interrupted at %s attempt. elapsed: %s ms. %s", attempt, elapsed, e.getMessage()));
                      }
                      
                      throw new RetryException(attempt, target);
                  }
              }
          }
      }
docs: Executes the delegate 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.
  
  @return
  @throws ExecutionException
  @throws RetryException