microsoft-azure-storage/src/com/microsoft/azure/storage/core/ExecutionEngine.java
public static <CLIENT_TYPE, PARENT_TYPE, RESULT_TYPE> RESULT_TYPE executeWithRetry(final CLIENT_TYPE client,
            final PARENT_TYPE parentObject, final StorageRequest<CLIENT_TYPE, PARENT_TYPE, RESULT_TYPE> task,
            final RetryPolicyFactory policyFactory, final OperationContext opContext) throws StorageException {

        RetryPolicy policy = null;

        if (policyFactory == null) {
            policy = new RetryNoRetry();
        }
        else {
            policy = policyFactory.createInstance(opContext);

            // if the returned policy is null, set to not retry
            if (policy == null) {
                policy = new RetryNoRetry();
            }
        }

        int currentRetryCount = 0;
        StorageException translatedException = null;
        HttpURLConnection request = null;
        final long startTime = new Date().getTime();

        while (true) {
            try {
                // 1-4: setup the request
                request = setupStorageRequest(client, parentObject, task, currentRetryCount, opContext);

                Logger.info(opContext, LogConstants.START_REQUEST, request.getURL(),
                        request.getRequestProperty(Constants.HeaderConstants.DATE));

                // 5. Potentially upload data
                boolean responseReceivedEventTriggered = false;
                try {
                    if (task.getSendStream() != null) {
                        Logger.info(opContext, LogConstants.UPLOAD);
                        final StreamMd5AndLength descriptor = Utility.writeToOutputStream(task.getSendStream(),
                                request.getOutputStream(), task.getLength(), false /* rewindStream */,
                                false /* calculate MD5 */, opContext, task.getRequestOptions());

                        task.validateStreamWrite(descriptor);
                        Logger.info(opContext, LogConstants.UPLOADDONE);
                    }

                    Utility.logHttpRequest(request, opContext);

                    // 6. Process the request - Get response
                    RequestResult currResult = task.getResult();
                    currResult.setStartDate(new Date());

                    Logger.info(opContext, LogConstants.GET_RESPONSE);

                    currResult.setStatusCode(request.getResponseCode());
                    currResult.setStatusMessage(request.getResponseMessage());
                    currResult.setStopDate(new Date());

                    currResult.setServiceRequestID(BaseResponse.getRequestId(request));
                    currResult.setEtag(BaseResponse.getEtag(request));
                    currResult.setRequestDate(BaseResponse.getDate(request));
                    currResult.setContentMD5(BaseResponse.getContentMD5(request));

                    // 7. Fire ResponseReceived Event
                    responseReceivedEventTriggered = true;
                    ExecutionEngine.fireResponseReceivedEvent(opContext, request, task.getResult());

                    Logger.info(opContext, LogConstants.RESPONSE_RECEIVED, currResult.getStatusCode(),
                            currResult.getServiceRequestID(), currResult.getContentMD5(), currResult.getEtag(),
                            currResult.getRequestDate());

                    Utility.logHttpResponse(request, opContext);
                }
                finally {
                    Logger.info(opContext, LogConstants.ERROR_RECEIVING_RESPONSE);
                    if (!responseReceivedEventTriggered) {
                        if (task.getResult().getStartDate() == null) {
                            task.getResult().setStartDate(new Date());
                        }

                        ExecutionEngine.fireErrorReceivingResponseEvent(opContext, request, task.getResult());
                    }
                }

                // 8. Pre-process response to check if there was an exception. Do Response parsing (headers etc).
                Logger.info(opContext, LogConstants.PRE_PROCESS);
                RESULT_TYPE result = task.preProcessResponse(parentObject, client, opContext);
                Logger.info(opContext, LogConstants.PRE_PROCESS_DONE);

                if (!task.isNonExceptionedRetryableFailure()) {

                    // 9. Post-process response. Read stream from server.
                    Logger.info(opContext, LogConstants.POST_PROCESS);
                    result = task.postProcessResponse(request, parentObject, client, opContext, result);
                    Logger.info(opContext, LogConstants.POST_PROCESS_DONE);

                    // Success return result and drain the input stream.
                    if ((task.getResult().getStatusCode() >= 200) && (task.getResult().getStatusCode() < 300)) {
                        if (request != null) {
                            InputStream inStream = request.getInputStream();
                            // At this point, we already have a result / exception to return to the user.
                            // This is just an optimization to improve socket reuse.
                            try {
                                Utility.writeToOutputStream(inStream, null, -1, false, false, null,
                                        task.getRequestOptions());
                            }
                            catch (final IOException ex) {
                            }
                            catch (StorageException e) {
                            }
                            finally {
                                inStream.close();
                            }
                        }
                    }
                    Logger.info(opContext, LogConstants.COMPLETE);

                    return result;
                }
                else {
                    Logger.warn(opContext, LogConstants.UNEXPECTED_RESULT_OR_EXCEPTION);
                    // The task may have already parsed an exception.
                    translatedException = task.materializeException(opContext);
                    task.getResult().setException(translatedException);

                    // throw on non retryable status codes: 501, 505, blob type mismatch
                    if (task.getResult().getStatusCode() == HttpURLConnection.HTTP_NOT_IMPLEMENTED
                            || task.getResult().getStatusCode() == HttpURLConnection.HTTP_VERSION
                            || translatedException.getErrorCode().equals(StorageErrorCodeStrings.INVALID_BLOB_TYPE)) {
                        throw translatedException;
                    }
                }
            }
            catch (final NetworkOnMainThreadException e) {
                // Non Retryable, just throw
                translatedException = new StorageException("NetworkOnMainThreadException",
                        SR.NETWORK_ON_MAIN_THREAD_EXCEPTION, -1, null, e);
                task.getResult().setException(translatedException);
                Logger.error(opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage());
                throw translatedException;
            }
            catch (final StorageException e) {
                // In case of table batch error or internal error, the exception will contain a different
                // status code and message than the original HTTP response. Reset based on error values.
                task.getResult().setStatusCode(e.getHttpStatusCode());
                task.getResult().setStatusMessage(e.getMessage());
                task.getResult().setException(e);
                
                Logger.warn(opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage());
                translatedException = e;
            }
            catch (final Exception e) {
                // Retryable, wrap
                Logger.warn(opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage());
                translatedException = StorageException.translateException(task, e, opContext);
                task.getResult().setException(translatedException);
            }
            finally {
                opContext.setClientTimeInMs(new Date().getTime() - startTime);

                // 10. Fire RequestCompleted Event
                if (task.isSent()) {
                    ExecutionEngine.fireRequestCompletedEvent(opContext, request, task.getResult());
                }
            }

            // Evaluate Retry Policy
            Logger.info(opContext, LogConstants.RETRY_CHECK, currentRetryCount, task.getResult().getStatusCode(),
                    translatedException == null ? null : translatedException.getMessage());

            task.setCurrentLocation(getNextLocation(task.getCurrentLocation(), task.getLocationMode()));
            Logger.info(opContext, LogConstants.NEXT_LOCATION, task.getCurrentLocation(), task.getLocationMode());

            RetryContext retryContext = new RetryContext(currentRetryCount++, task.getResult(),
                    task.getCurrentLocation(), task.getLocationMode());

            RetryInfo retryInfo = policy.evaluate(retryContext, opContext);

            if (retryInfo == null) {
                // policy does not allow for retry
                Logger.error(opContext, LogConstants.DO_NOT_RETRY_POLICY, translatedException == null ? null
                        : translatedException.getMessage());
                throw translatedException;
            }
            else if (Utility.validateMaxExecutionTimeout(task.getRequestOptions().getOperationExpiryTimeInMs(),
                    retryInfo.getRetryInterval())) {
                // maximum execution time would be exceeded by current time plus retry interval delay
                TimeoutException timeoutException = new TimeoutException(SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION);
                translatedException = new StorageException(StorageErrorCodeStrings.OPERATION_TIMED_OUT,
                        SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION, Constants.HeaderConstants.HTTP_UNUSED_306, null,
                        timeoutException);

                task.initialize(opContext);
                task.getResult().setException(translatedException);

                Logger.error(opContext, LogConstants.DO_NOT_RETRY_TIMEOUT, translatedException == null ? null
                        : translatedException.getMessage());

                throw translatedException;
            }
            else {
                // attempt to retry
                task.setCurrentLocation(retryInfo.getTargetLocation());
                task.setLocationMode(retryInfo.getUpdatedLocationMode());
                Logger.info(opContext, LogConstants.RETRY_INFO, task.getCurrentLocation(), task.getLocationMode());

                try {
                    ExecutionEngine.fireRetryingEvent(opContext, task.getConnection(), task.getResult(), retryContext);

                    Logger.info(opContext, LogConstants.RETRY_DELAY, retryInfo.getRetryInterval());
                    Thread.sleep(retryInfo.getRetryInterval());
                }
                catch (final InterruptedException e) {
                    // Restore the interrupted status
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
public static <CLIENT_TYPE, PARENT_TYPE, RESULT_TYPE> RESULT_TYPE executeWithRetry(final CLIENT_TYPE client,
            final PARENT_TYPE parentObject, final StorageRequest<CLIENT_TYPE, PARENT_TYPE, RESULT_TYPE> task,
            final RetryPolicyFactory policyFactory, final OperationContext opContext) throws StorageException {

        RetryPolicy policy = null;

        if (policyFactory == null) {
            policy = new RetryNoRetry();
        }
        else {
            policy = policyFactory.createInstance(opContext);

            // if the returned policy is null, set to not retry
            if (policy == null) {
                policy = new RetryNoRetry();
            }
        }

        int currentRetryCount = 0;
        StorageException translatedException = null;
        HttpURLConnection request = null;
        final long startTime = new Date().getTime();

        while (true) {
            try {
                // 1-4: setup the request
                request = setupStorageRequest(client, parentObject, task, currentRetryCount, opContext);

                Logger.info(opContext, LogConstants.START_REQUEST, request.getURL(),
                        request.getRequestProperty(Constants.HeaderConstants.DATE));

                // 5. Potentially upload data
                boolean responseReceivedEventTriggered = false;
                try {
                    if (task.getSendStream() != null) {
                        Logger.info(opContext, LogConstants.UPLOAD);
                        final StreamMd5AndLength descriptor = Utility.writeToOutputStream(task.getSendStream(),
                                request.getOutputStream(), task.getLength(), false /* rewindStream */,
                                false /* calculate MD5 */, opContext, task.getRequestOptions());

                        task.validateStreamWrite(descriptor);
                        Logger.info(opContext, LogConstants.UPLOADDONE);
                    }

                    Utility.logHttpRequest(request, opContext);

                    // 6. Process the request - Get response
                    RequestResult currResult = task.getResult();
                    currResult.setStartDate(new Date());

                    Logger.info(opContext, LogConstants.GET_RESPONSE);

                    currResult.setStatusCode(request.getResponseCode());
                    currResult.setStatusMessage(request.getResponseMessage());
                    currResult.setStopDate(new Date());

                    currResult.setServiceRequestID(BaseResponse.getRequestId(request));
                    currResult.setEtag(BaseResponse.getEtag(request));
                    currResult.setRequestDate(BaseResponse.getDate(request));
                    currResult.setContentMD5(BaseResponse.getContentMD5(request));

                    // 7. Fire ResponseReceived Event
                    responseReceivedEventTriggered = true;
                    ExecutionEngine.fireResponseReceivedEvent(opContext, request, task.getResult());

                    Logger.info(opContext, LogConstants.RESPONSE_RECEIVED, currResult.getStatusCode(),
                            currResult.getServiceRequestID(), currResult.getContentMD5(), currResult.getEtag(),
                            currResult.getRequestDate());

                    Utility.logHttpResponse(request, opContext);
                }
                finally {
                    Logger.info(opContext, LogConstants.ERROR_RECEIVING_RESPONSE);
                    if (!responseReceivedEventTriggered) {
                        if (task.getResult().getStartDate() == null) {
                            task.getResult().setStartDate(new Date());
                        }

                        ExecutionEngine.fireErrorReceivingResponseEvent(opContext, request, task.getResult());
                    }
                }

                // 8. Pre-process response to check if there was an exception. Do Response parsing (headers etc).
                Logger.info(opContext, LogConstants.PRE_PROCESS);
                RESULT_TYPE result = task.preProcessResponse(parentObject, client, opContext);
                Logger.info(opContext, LogConstants.PRE_PROCESS_DONE);

                if (!task.isNonExceptionedRetryableFailure()) {

                    // 9. Post-process response. Read stream from server.
                    Logger.info(opContext, LogConstants.POST_PROCESS);
                    result = task.postProcessResponse(request, parentObject, client, opContext, result);
                    Logger.info(opContext, LogConstants.POST_PROCESS_DONE);

                    // Success return result and drain the input stream.
                    if ((task.getResult().getStatusCode() >= 200) && (task.getResult().getStatusCode() < 300)) {
                        if (request != null) {
                            InputStream inStream = request.getInputStream();
                            // At this point, we already have a result / exception to return to the user.
                            // This is just an optimization to improve socket reuse.
                            try {
                                Utility.writeToOutputStream(inStream, null, -1, false, false, null,
                                        task.getRequestOptions());
                            }
                            catch (final IOException ex) {
                            }
                            catch (StorageException e) {
                            }
                            finally {
                                inStream.close();
                            }
                        }
                    }
                    Logger.info(opContext, LogConstants.COMPLETE);

                    return result;
                }
                else {
                    Logger.warn(opContext, LogConstants.UNEXPECTED_RESULT_OR_EXCEPTION);
                    // The task may have already parsed an exception.
                    translatedException = task.materializeException(opContext);
                    task.getResult().setException(translatedException);

                    // throw on non retryable status codes: 501, 505, blob type mismatch
                    if (task.getResult().getStatusCode() == HttpURLConnection.HTTP_NOT_IMPLEMENTED
                            || task.getResult().getStatusCode() == HttpURLConnection.HTTP_VERSION
                            || translatedException.getErrorCode().equals(StorageErrorCodeStrings.INVALID_BLOB_TYPE)) {
                        throw translatedException;
                    }
                }
            }
            catch (final NetworkOnMainThreadException e) {
                // Non Retryable, just throw
                translatedException = new StorageException("NetworkOnMainThreadException",
                        SR.NETWORK_ON_MAIN_THREAD_EXCEPTION, -1, null, e);
                task.getResult().setException(translatedException);
                Logger.error(opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage());
                throw translatedException;
            }
            catch (final StorageException e) {
                // In case of table batch error or internal error, the exception will contain a different
                // status code and message than the original HTTP response. Reset based on error values.
                task.getResult().setStatusCode(e.getHttpStatusCode());
                task.getResult().setStatusMessage(e.getMessage());
                task.getResult().setException(e);
                
                Logger.warn(opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage());
                translatedException = e;
            }
            catch (final Exception e) {
                // Retryable, wrap
                Logger.warn(opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage());
                translatedException = StorageException.translateException(task, e, opContext);
                task.getResult().setException(translatedException);
            }
            finally {
                opContext.setClientTimeInMs(new Date().getTime() - startTime);

                // 10. Fire RequestCompleted Event
                if (task.isSent()) {
                    ExecutionEngine.fireRequestCompletedEvent(opContext, request, task.getResult());
                }
            }

            // Evaluate Retry Policy
            Logger.info(opContext, LogConstants.RETRY_CHECK, currentRetryCount, task.getResult().getStatusCode(),
                    translatedException == null ? null : translatedException.getMessage());

            task.setCurrentLocation(getNextLocation(task.getCurrentLocation(), task.getLocationMode()));
            Logger.info(opContext, LogConstants.NEXT_LOCATION, task.getCurrentLocation(), task.getLocationMode());

            RetryContext retryContext = new RetryContext(currentRetryCount++, task.getResult(),
                    task.getCurrentLocation(), task.getLocationMode());

            RetryInfo retryInfo = policy.evaluate(retryContext, opContext);

            if (retryInfo == null) {
                // policy does not allow for retry
                Logger.error(opContext, LogConstants.DO_NOT_RETRY_POLICY, translatedException == null ? null
                        : translatedException.getMessage());
                throw translatedException;
            }
            else if (Utility.validateMaxExecutionTimeout(task.getRequestOptions().getOperationExpiryTimeInMs(),
                    retryInfo.getRetryInterval())) {
                // maximum execution time would be exceeded by current time plus retry interval delay
                TimeoutException timeoutException = new TimeoutException(SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION);
                translatedException = new StorageException(StorageErrorCodeStrings.OPERATION_TIMED_OUT,
                        SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION, Constants.HeaderConstants.HTTP_UNUSED_306, null,
                        timeoutException);

                task.initialize(opContext);
                task.getResult().setException(translatedException);

                Logger.error(opContext, LogConstants.DO_NOT_RETRY_TIMEOUT, translatedException == null ? null
                        : translatedException.getMessage());

                throw translatedException;
            }
            else {
                // attempt to retry
                task.setCurrentLocation(retryInfo.getTargetLocation());
                task.setLocationMode(retryInfo.getUpdatedLocationMode());
                Logger.info(opContext, LogConstants.RETRY_INFO, task.getCurrentLocation(), task.getLocationMode());

                try {
                    ExecutionEngine.fireRetryingEvent(opContext, task.getConnection(), task.getResult(), retryContext);

                    Logger.info(opContext, LogConstants.RETRY_DELAY, retryInfo.getRetryInterval());
                    Thread.sleep(retryInfo.getRetryInterval());
                }
                catch (final InterruptedException e) {
                    // Restore the interrupted status
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
public static < CLIENT_TYPE , PARENT_TYPE , RESULT_TYPE > RESULT_TYPE executeWithRetry ( final CLIENT_TYPE client , final PARENT_TYPE parentObject , final StorageRequest < CLIENT_TYPE , PARENT_TYPE , RESULT_TYPE > task , final RetryPolicyFactory policyFactory , final OperationContext opContext ) throws StorageException { RetryPolicy policy = null ; if ( policyFactory == null ) { policy = new RetryNoRetry ( ) ; } else { policy = policyFactory . createInstance ( opContext ) ; // if the returned policy is null, set to not retry if ( policy == null ) { policy = new RetryNoRetry ( ) ; } } int currentRetryCount = 0 ; StorageException translatedException = null ; HttpURLConnection request = null ; final long startTime = new Date ( ) . getTime ( ) ; while ( true ) { try { // 1-4: setup the request request = setupStorageRequest ( client , parentObject , task , currentRetryCount , opContext ) ; Logger . info ( opContext , LogConstants . START_REQUEST , request . getURL ( ) , request . getRequestProperty ( Constants . HeaderConstants . DATE ) ) ; // 5. Potentially upload data boolean responseReceivedEventTriggered = false ; try { if ( task . getSendStream ( ) != null ) { Logger . info ( opContext , LogConstants . UPLOAD ) ; final StreamMd5AndLength descriptor = Utility . writeToOutputStream ( task . getSendStream ( ) , request . getOutputStream ( ) , task . getLength ( ) , false /* rewindStream */ , false /* calculate MD5 */ , opContext , task . getRequestOptions ( ) ) ; task . validateStreamWrite ( descriptor ) ; Logger . info ( opContext , LogConstants . UPLOADDONE ) ; } Utility . logHttpRequest ( request , opContext ) ; // 6. Process the request - Get response RequestResult currResult = task . getResult ( ) ; currResult . setStartDate ( new Date ( ) ) ; Logger . info ( opContext , LogConstants . GET_RESPONSE ) ; currResult . setStatusCode ( request . getResponseCode ( ) ) ; currResult . setStatusMessage ( request . getResponseMessage ( ) ) ; currResult . setStopDate ( new Date ( ) ) ; currResult . setServiceRequestID ( BaseResponse . getRequestId ( request ) ) ; currResult . setEtag ( BaseResponse . getEtag ( request ) ) ; currResult . setRequestDate ( BaseResponse . getDate ( request ) ) ; currResult . setContentMD5 ( BaseResponse . getContentMD5 ( request ) ) ; // 7. Fire ResponseReceived Event responseReceivedEventTriggered = true ; ExecutionEngine . fireResponseReceivedEvent ( opContext , request , task . getResult ( ) ) ; Logger . info ( opContext , LogConstants . RESPONSE_RECEIVED , currResult . getStatusCode ( ) , currResult . getServiceRequestID ( ) , currResult . getContentMD5 ( ) , currResult . getEtag ( ) , currResult . getRequestDate ( ) ) ; Utility . logHttpResponse ( request , opContext ) ; } finally { Logger . info ( opContext , LogConstants . ERROR_RECEIVING_RESPONSE ) ; if ( ! responseReceivedEventTriggered ) { if ( task . getResult ( ) . getStartDate ( ) == null ) { task . getResult ( ) . setStartDate ( new Date ( ) ) ; } ExecutionEngine . fireErrorReceivingResponseEvent ( opContext , request , task . getResult ( ) ) ; } } // 8. Pre-process response to check if there was an exception. Do Response parsing (headers etc). Logger . info ( opContext , LogConstants . PRE_PROCESS ) ; RESULT_TYPE result = task . preProcessResponse ( parentObject , client , opContext ) ; Logger . info ( opContext , LogConstants . PRE_PROCESS_DONE ) ; if ( ! task . isNonExceptionedRetryableFailure ( ) ) { // 9. Post-process response. Read stream from server. Logger . info ( opContext , LogConstants . POST_PROCESS ) ; result = task . postProcessResponse ( request , parentObject , client , opContext , result ) ; Logger . info ( opContext , LogConstants . POST_PROCESS_DONE ) ; // Success return result and drain the input stream. if ( ( task . getResult ( ) . getStatusCode ( ) >= 200 ) && ( task . getResult ( ) . getStatusCode ( ) < 300 ) ) { if ( request != null ) { InputStream inStream = request . getInputStream ( ) ; // At this point, we already have a result / exception to return to the user. // This is just an optimization to improve socket reuse. try { Utility . writeToOutputStream ( inStream , null , - 1 , false , false , null , task . getRequestOptions ( ) ) ; } catch ( final IOException ex ) { } catch ( StorageException e ) { } finally { inStream . close ( ) ; } } } Logger . info ( opContext , LogConstants . COMPLETE ) ; return result ; } else { Logger . warn ( opContext , LogConstants . UNEXPECTED_RESULT_OR_EXCEPTION ) ; // The task may have already parsed an exception. translatedException = task . materializeException ( opContext ) ; task . getResult ( ) . setException ( translatedException ) ; // throw on non retryable status codes: 501, 505, blob type mismatch if ( task . getResult ( ) . getStatusCode ( ) == HttpURLConnection . HTTP_NOT_IMPLEMENTED || task . getResult ( ) . getStatusCode ( ) == HttpURLConnection . HTTP_VERSION || translatedException . getErrorCode ( ) . equals ( StorageErrorCodeStrings . INVALID_BLOB_TYPE ) ) { throw translatedException ; } } } catch ( final NetworkOnMainThreadException e ) { // Non Retryable, just throw translatedException = new StorageException ( "NetworkOnMainThreadException" , SR . NETWORK_ON_MAIN_THREAD_EXCEPTION , - 1 , null , e ) ; task . getResult ( ) . setException ( translatedException ) ; Logger . error ( opContext , LogConstants . UNRETRYABLE_EXCEPTION , e . getClass ( ) . getName ( ) , e . getMessage ( ) ) ; throw translatedException ; } catch ( final StorageException e ) { // In case of table batch error or internal error, the exception will contain a different // status code and message than the original HTTP response. Reset based on error values. task . getResult ( ) . setStatusCode ( e . getHttpStatusCode ( ) ) ; task . getResult ( ) . setStatusMessage ( e . getMessage ( ) ) ; task . getResult ( ) . setException ( e ) ; Logger . warn ( opContext , LogConstants . RETRYABLE_EXCEPTION , e . getClass ( ) . getName ( ) , e . getMessage ( ) ) ; translatedException = e ; } catch ( final Exception e ) { // Retryable, wrap Logger . warn ( opContext , LogConstants . RETRYABLE_EXCEPTION , e . getClass ( ) . getName ( ) , e . getMessage ( ) ) ; translatedException = StorageException . translateException ( task , e , opContext ) ; task . getResult ( ) . setException ( translatedException ) ; } finally { opContext . setClientTimeInMs ( new Date ( ) . getTime ( ) - startTime ) ; // 10. Fire RequestCompleted Event if ( task . isSent ( ) ) { ExecutionEngine . fireRequestCompletedEvent ( opContext , request , task . getResult ( ) ) ; } } // Evaluate Retry Policy Logger . info ( opContext , LogConstants . RETRY_CHECK , currentRetryCount , task . getResult ( ) . getStatusCode ( ) , translatedException == null ? null : translatedException . getMessage ( ) ) ; task . setCurrentLocation ( getNextLocation ( task . getCurrentLocation ( ) , task . getLocationMode ( ) ) ) ; Logger . info ( opContext , LogConstants . NEXT_LOCATION , task . getCurrentLocation ( ) , task . getLocationMode ( ) ) ; RetryContext retryContext = new RetryContext ( currentRetryCount ++ , task . getResult ( ) , task . getCurrentLocation ( ) , task . getLocationMode ( ) ) ; RetryInfo retryInfo = policy . evaluate ( retryContext , opContext ) ; if ( retryInfo == null ) { // policy does not allow for retry Logger . error ( opContext , LogConstants . DO_NOT_RETRY_POLICY , translatedException == null ? null : translatedException . getMessage ( ) ) ; throw translatedException ; } else if ( Utility . validateMaxExecutionTimeout ( task . getRequestOptions ( ) . getOperationExpiryTimeInMs ( ) , retryInfo . getRetryInterval ( ) ) ) { // maximum execution time would be exceeded by current time plus retry interval delay TimeoutException timeoutException = new TimeoutException ( SR . MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION ) ; translatedException = new StorageException ( StorageErrorCodeStrings . OPERATION_TIMED_OUT , SR . MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION , Constants . HeaderConstants . HTTP_UNUSED_306 , null , timeoutException ) ; task . initialize ( opContext ) ; task . getResult ( ) . setException ( translatedException ) ; Logger . error ( opContext , LogConstants . DO_NOT_RETRY_TIMEOUT , translatedException == null ? null : translatedException . getMessage ( ) ) ; throw translatedException ; } else { // attempt to retry task . setCurrentLocation ( retryInfo . getTargetLocation ( ) ) ; task . setLocationMode ( retryInfo . getUpdatedLocationMode ( ) ) ; Logger . info ( opContext , LogConstants . RETRY_INFO , task . getCurrentLocation ( ) , task . getLocationMode ( ) ) ; try { ExecutionEngine . fireRetryingEvent ( opContext , task . getConnection ( ) , task . getResult ( ) , retryContext ) ; Logger . info ( opContext , LogConstants . RETRY_DELAY , retryInfo . getRetryInterval ( ) ) ; Thread . sleep ( retryInfo . getRetryInterval ( ) ) ; } catch ( final InterruptedException e ) { // Restore the interrupted status Thread . currentThread ( ) . interrupt ( ) ; } } } }
Executes an operation and enforces a retrypolicy to handle any potential errors

@param <CLIENT_TYPE>
The type of the service client
@param <PARENT_TYPE>
The type of the parent object, i.e. CloudBlobContainer for downloadAttributes etc.
@param <RESULT_TYPE>
The type of the expected result
@param client
the service client associated with the request
@param parentObject
the parent object
@param task
the StorageRequest to execute
@param policyFactory
the factory used to generate a new retry policy instance
@param opContext
an object used to track the execution of the operation
@return the result of the operation
@throws StorageException
an exception representing any error which occurred during the operation.
Executes an operation and enforces a retrypolicy to handle any potential errors