microsoft-azure-storage/src/com/microsoft/azure/storage/RetryExponentialRetry.java
@Override
    public RetryInfo evaluate(RetryContext retryContext, OperationContext operationContext) {

        boolean secondaryNotFound = this.evaluateLastAttemptAndSecondaryNotFound(retryContext);

        if (retryContext.getCurrentRetryCount() < this.maximumAttempts) {
            
            // If this method is called after a successful response, it means
            // we failed during the response body download. So, we should not
            // check for success codes here. 
            int statusCode = retryContext.getLastRequestResult().getStatusCode();
            if ((!secondaryNotFound && statusCode >= 300 && statusCode < 500 && statusCode != 408)
                    || statusCode == HttpURLConnection.HTTP_NOT_IMPLEMENTED
                    || statusCode == HttpURLConnection.HTTP_VERSION) {
                return null;
            }

            // Calculate backoff Interval between 80% and 120% of the desired
            // backoff, multiply by 2^n -1 for exponential
            double incrementDelta = (Math.pow(2, retryContext.getCurrentRetryCount()) - 1);
            final int boundedRandDelta = (int) (this.deltaBackoffIntervalInMs * 0.8)
                    + this.randRef.nextInt((int) (this.deltaBackoffIntervalInMs * 1.2)
                            - (int) (this.deltaBackoffIntervalInMs * 0.8));
            incrementDelta *= boundedRandDelta;

            final long retryInterval = (int) Math.round(Math.min(this.resolvedMinBackoff + incrementDelta,
                    this.resolvedMaxBackoff));

            return this.evaluateRetryInfo(retryContext, secondaryNotFound, retryInterval);
        }

        return null;
    }
@Override
    public RetryInfo evaluate(RetryContext retryContext, OperationContext operationContext) {

        boolean secondaryNotFound = this.evaluateLastAttemptAndSecondaryNotFound(retryContext);

        if (retryContext.getCurrentRetryCount() < this.maximumAttempts) {
            
            // If this method is called after a successful response, it means
            // we failed during the response body download. So, we should not
            // check for success codes here. 
            int statusCode = retryContext.getLastRequestResult().getStatusCode();
            if ((!secondaryNotFound && statusCode >= 300 && statusCode < 500 && statusCode != 408)
                    || statusCode == HttpURLConnection.HTTP_NOT_IMPLEMENTED
                    || statusCode == HttpURLConnection.HTTP_VERSION) {
                return null;
            }

            // Calculate backoff Interval between 80% and 120% of the desired
            // backoff, multiply by 2^n -1 for exponential
            double incrementDelta = (Math.pow(2, retryContext.getCurrentRetryCount()) - 1);
            final int boundedRandDelta = (int) (this.deltaBackoffIntervalInMs * 0.8)
                    + this.randRef.nextInt((int) (this.deltaBackoffIntervalInMs * 1.2)
                            - (int) (this.deltaBackoffIntervalInMs * 0.8));
            incrementDelta *= boundedRandDelta;

            final long retryInterval = (int) Math.round(Math.min(this.resolvedMinBackoff + incrementDelta,
                    this.resolvedMaxBackoff));

            return this.evaluateRetryInfo(retryContext, secondaryNotFound, retryInterval);
        }

        return null;
    }
Determines whether the operation should be retried and specifies the interval until the next retry.

@param retryContext
A {@link RetryContext} object that indicates the number of retries, last request's results, whether
the next retry should happen in the primary or secondary location, and specifies the location mode.
@param operationContext
An {@link OperationContext} object for tracking the current operation.
@return
A {@link RetryInfo} object that indicates whether the next retry will happen in the primary or secondary
location, and specifies the location mode. If <code>null</code>, the operation will not be retried.