/**
   * 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);
  }
Ejemplo n.º 5
0
  /**
   * 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();
        }
      }
    }
  }
Ejemplo n.º 6
0
  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);
    }
  }