/** * Returns a result segment of an enumerable collection of files and directories for this * directory, using the specified listing details options, request options, and operation context. * * @param maxResults The maximum number of results to retrieve. * @param continuationToken A {@link ResultContinuation} object that represents a continuation * token returned by a previous listing operation. * @param options A {@link FileRequestOptions} object that specifies any additional options for * the request. Specifying <code>null</code> will use the default request options from the * associated service client ( {@link CloudFileClient}). * @param opContext An {@link OperationContext} object that represents the context for the current * operation. This object is used to track requests to the storage service, and to provide * additional runtime information about the operation. * @return A {@link ResultSegment} object that contains a segment of the enumerable collection of * {@link ListFileItem} objects that represent the files and directories in this directory. * @throws StorageException If a storage service error occurred. */ public ResultSegment<ListFileItem> listFilesAndDirectoriesSegmented( final int maxResults, final ResultContinuation continuationToken, FileRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { opContext = new OperationContext(); } opContext.initialize(); options = FileRequestOptions.applyDefaults(options, this.fileServiceClient); Utility.assertContinuationType(continuationToken, ResultContinuationType.FILE); SegmentedStorageRequest segmentedRequest = new SegmentedStorageRequest(); segmentedRequest.setToken(continuationToken); return ExecutionEngine.executeWithRetry( this.fileServiceClient, this, this.listFilesAndDirectoriesSegmentedImpl(maxResults, options, segmentedRequest), options.getRetryPolicyFactory(), opContext); }
/** * Creates the directory using the specified options and operation context. * * @param options A {@link FileRequestOptions} object that specifies any additional options for * the request. Specifying <code>null</code> will use the default request options from the * associated service client ( {@link CloudFileClient}). * @param opContext An {@link OperationContext} object that represents the context for the current * operation. This object is used to track requests to the storage service, and to provide * additional runtime information about the operation. * @throws StorageException If a storage service error occurred. */ @DoesServiceRequest public void create(FileRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { opContext = new OperationContext(); } opContext.initialize(); options = FileRequestOptions.applyDefaults(options, this.fileServiceClient); ExecutionEngine.executeWithRetry( this.fileServiceClient, this, createDirectoryImpl(options), options.getRetryPolicyFactory(), opContext); }
/** * Downloads the directory's properties using the specified request options and operation context. * * @param accessCondition An {@link AccessCondition} object that represents the access conditions * for the directory. * @param options A {@link FileRequestOptions} object that specifies any additional options for * the request. Specifying <code>null</code> will use the default request options from the * associated service client ( {@link CloudFileClient}). * @param opContext An {@link OperationContext} object that represents the context for the current * operation. This object is used to track requests to the storage service, and to provide * additional runtime information about the operation. * @throws StorageException If a storage service error occurred. */ @DoesServiceRequest public void downloadAttributes( AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { opContext = new OperationContext(); } opContext.initialize(); options = FileRequestOptions.applyDefaults(options, this.fileServiceClient); ExecutionEngine.executeWithRetry( this.fileServiceClient, this, this.downloadAttributesImpl(accessCondition, options), options.getRetryPolicyFactory(), opContext); }
@DoesServiceRequest private boolean exists( final boolean primaryOnly, final AccessCondition accessCondition, FileRequestOptions options, OperationContext opContext) throws StorageException { if (opContext == null) { opContext = new OperationContext(); } opContext.initialize(); options = FileRequestOptions.applyDefaults(options, this.fileServiceClient); return ExecutionEngine.executeWithRetry( this.fileServiceClient, this, this.existsImpl(primaryOnly, accessCondition, options), options.getRetryPolicyFactory(), opContext); }
/** * 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. */ 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 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); } // 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 ExecutionEngine.fireResponseReceivedEvent(opContext, request, task.getResult()); Logger.info( opContext, LogConstants.RESPONSE_RECEIVED, currResult.getStatusCode(), currResult.getServiceRequestID(), currResult.getContentMD5(), currResult.getEtag()); // 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(task.getConnection(), 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 TimeoutException e) { // Retryable Logger.warn( opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); translatedException = StorageException.translateException(task.getConnection(), e, opContext); task.getResult().setException(translatedException); } catch (final SocketTimeoutException e) { // Retryable Logger.warn( opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); translatedException = new StorageException( StorageErrorCodeStrings.OPERATION_TIMED_OUT, "The operation did not complete in the specified time.", -1, null, e); task.getResult().setException(translatedException); } catch (final IOException e) { // Non Retryable if the inner exception is actually an TimeoutException, otherwise Retryable if (e.getCause() instanceof TimeoutException) { translatedException = new StorageException( StorageErrorCodeStrings.OPERATION_TIMED_OUT, SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION, Constants.HeaderConstants.HTTP_UNUSED_306, null, (Exception) e.getCause()); task.getResult().setException(translatedException); Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getCause().getClass().getName(), e.getCause().getMessage()); throw translatedException; } else { Logger.warn( opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); translatedException = StorageException.translateException(task.getConnection(), e, opContext); task.getResult().setException(translatedException); } } catch (final InvalidKeyException e) { // Non Retryable, just throw translatedException = StorageException.translateException(task.getConnection(), e, opContext); task.getResult().setException(translatedException); Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); throw translatedException; } catch (final URISyntaxException e) { // Non Retryable, just throw translatedException = StorageException.translateException(task.getConnection(), e, opContext); task.getResult().setException(translatedException); Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); throw translatedException; } catch (final TableServiceException e) { task.getResult().setStatusCode(e.getHttpStatusCode()); task.getResult().setStatusMessage(e.getMessage()); task.getResult().setException(e); if (!e.isRetryable()) { Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); throw e; } else { Logger.warn( opContext, LogConstants.RETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); translatedException = e; } } catch (final StorageException e) { // Non Retryable, just throw // do not translate StorageException task.getResult().setException(e); Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); throw e; } catch (final Exception e) { // Non Retryable, just throw translatedException = StorageException.translateException(task.getConnection(), e, opContext); task.getResult().setException(translatedException); Logger.error( opContext, LogConstants.UNRETRYABLE_EXCEPTION, e.getClass().getName(), e.getMessage()); throw 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(); } } } }
private static <CLIENT_TYPE, PARENT_TYPE, RESULT_TYPE> HttpURLConnection setupStorageRequest( final CLIENT_TYPE client, final PARENT_TYPE parentObject, final StorageRequest<CLIENT_TYPE, PARENT_TYPE, RESULT_TYPE> task, int currentRetryCount, final OperationContext opContext) throws StorageException { try { // reset result flags task.initialize(opContext); if (Utility.validateMaxExecutionTimeout( task.getRequestOptions().getOperationExpiryTimeInMs())) { // maximum execution time would be exceeded by current time TimeoutException timeoutException = new TimeoutException(SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION); throw new StorageException( StorageErrorCodeStrings.OPERATION_TIMED_OUT, SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION, Constants.HeaderConstants.HTTP_UNUSED_306, null, timeoutException); } // Run the recovery action if this is a retry. Else, initialize the location mode for the // task. // For retries, it will be initialized in retry logic. if (currentRetryCount > 0) { task.recoveryAction(opContext); Logger.info(opContext, LogConstants.RETRY); } else { task.applyLocationModeToRequest(); task.initializeLocation(); Logger.info(opContext, LogConstants.STARTING); } task.setRequestLocationMode(); // If the command only allows for a specific location, we should target // that location no matter what the retry policy says. task.validateLocation(); Logger.info( opContext, LogConstants.INIT_LOCATION, task.getCurrentLocation(), task.getLocationMode()); // 1. Build the request HttpURLConnection request = task.buildRequest(client, parentObject, opContext); // 2. Add headers task.setHeaders(request, parentObject, opContext); // Add any other custom headers that users have set on the opContext if (opContext.getUserHeaders() != null) { for (final Entry<String, String> entry : opContext.getUserHeaders().entrySet()) { request.setRequestProperty(entry.getKey(), entry.getValue()); } } // 3. Fire sending request event ExecutionEngine.fireSendingRequestEvent(opContext, request, task.getResult()); task.setIsSent(true); // 4. Sign the request task.signRequest(request, client, opContext); // set the connection on the task task.setConnection(request); return request; } catch (StorageException e) { throw e; } catch (Exception e) { throw new StorageException( null, e.getMessage(), Constants.HeaderConstants.HTTP_UNUSED_306, null, e); } }