/**
   * Validates a specified template.
   *
   * @param validateTemplateRequest The input for <a>ValidateTemplate</a> action.
   * @return Result of the ValidateTemplate operation returned by the service.
   * @sample AmazonCloudFormation.ValidateTemplate
   */
  @Override
  public ValidateTemplateResult validateTemplate(ValidateTemplateRequest validateTemplateRequest) {
    ExecutionContext executionContext = createExecutionContext(validateTemplateRequest);
    AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
    awsRequestMetrics.startEvent(Field.ClientExecuteTime);
    Request<ValidateTemplateRequest> request = null;
    Response<ValidateTemplateResult> response = null;

    try {
      awsRequestMetrics.startEvent(Field.RequestMarshallTime);
      try {
        request =
            new ValidateTemplateRequestMarshaller()
                .marshall(super.beforeMarshalling(validateTemplateRequest));
        // Binds the request metrics to the current request.
        request.setAWSRequestMetrics(awsRequestMetrics);
      } finally {
        awsRequestMetrics.endEvent(Field.RequestMarshallTime);
      }

      StaxResponseHandler<ValidateTemplateResult> responseHandler =
          new StaxResponseHandler<ValidateTemplateResult>(
              new ValidateTemplateResultStaxUnmarshaller());
      response = invoke(request, responseHandler, executionContext);

      return response.getAwsResponse();

    } finally {

      endClientExecution(awsRequestMetrics, request, response);
    }
  }
  private <X, Y extends AmazonWebServiceRequest> Response<X> invoke(
      Request<Y> request,
      HttpResponseHandler<AmazonWebServiceResponse<X>> responseHandler,
      ExecutionContext executionContext) {
    request.setEndpoint(endpoint);
    request.setTimeOffset(timeOffset);

    AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
    AWSCredentials credentials;
    awsRequestMetrics.startEvent(Field.CredentialsRequestTime);
    try {
      credentials = awsCredentialsProvider.getCredentials();
    } finally {
      awsRequestMetrics.endEvent(Field.CredentialsRequestTime);
    }

    AmazonWebServiceRequest originalRequest = request.getOriginalRequest();
    if (originalRequest != null && originalRequest.getRequestCredentials() != null) {
      credentials = originalRequest.getRequestCredentials();
    }

    executionContext.setCredentials(credentials);

    DefaultErrorResponseHandler errorResponseHandler =
        new DefaultErrorResponseHandler(exceptionUnmarshallers);

    return client.execute(request, responseHandler, errorResponseHandler, executionContext);
  }
  /**
   * Sends a signal to the specified resource with a success or failure status. You can use the
   * SignalResource API in conjunction with a creation policy or update policy. AWS CloudFormation
   * doesn't proceed with a stack creation or update until resources receive the required number of
   * signals or the timeout period is exceeded. The SignalResource API is useful in cases where you
   * want to send signals from anywhere other than an Amazon EC2 instance.
   *
   * @param signalResourceRequest The input for the <a>SignalResource</a> action.
   * @sample AmazonCloudFormation.SignalResource
   */
  @Override
  public void signalResource(SignalResourceRequest signalResourceRequest) {
    ExecutionContext executionContext = createExecutionContext(signalResourceRequest);
    AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
    awsRequestMetrics.startEvent(Field.ClientExecuteTime);
    Request<SignalResourceRequest> request = null;
    Response<Void> response = null;

    try {
      awsRequestMetrics.startEvent(Field.RequestMarshallTime);
      try {
        request =
            new SignalResourceRequestMarshaller()
                .marshall(super.beforeMarshalling(signalResourceRequest));
        // Binds the request metrics to the current request.
        request.setAWSRequestMetrics(awsRequestMetrics);
      } finally {
        awsRequestMetrics.endEvent(Field.RequestMarshallTime);
      }

      StaxResponseHandler<Void> responseHandler = new StaxResponseHandler<Void>(null);
      invoke(request, responseHandler, executionContext);

    } finally {

      endClientExecution(awsRequestMetrics, request, response);
    }
  }
  /**
   * You use this operation to change the parameters specified in the original manifest file by
   * supplying a new manifest file. The manifest file attached to this request replaces the original
   * manifest file. You can only use the operation after a CreateJob request but before the data
   * transfer starts and you can only use it on jobs you own.
   *
   * @param updateJobRequest Container for the necessary parameters to execute the UpdateJob service
   *     method on AmazonImportExport.
   * @return The response from the UpdateJob service method, as returned by AmazonImportExport.
   * @throws MalformedManifestException
   * @throws BucketPermissionException
   * @throws InvalidAddressException
   * @throws InvalidParameterException
   * @throws UnableToUpdateJobIdException
   * @throws MultipleRegionsException
   * @throws InvalidVersionException
   * @throws MissingParameterException
   * @throws InvalidFileSystemException
   * @throws CanceledJobIdException
   * @throws MissingCustomsException
   * @throws NoSuchBucketException
   * @throws ExpiredJobIdException
   * @throws InvalidAccessKeyIdException
   * @throws InvalidCustomsException
   * @throws InvalidManifestFieldException
   * @throws MissingManifestFieldException
   * @throws InvalidJobIdException
   * @throws AmazonClientException If any internal errors are encountered inside the client while
   *     attempting to make the request or handle the response. For example if a network connection
   *     is not available.
   * @throws AmazonServiceException If an error response is returned by AmazonImportExport
   *     indicating either a problem with the data in the request, or a server side issue.
   */
  public UpdateJobResult updateJob(UpdateJobRequest updateJobRequest) {
    ExecutionContext executionContext = createExecutionContext(updateJobRequest);
    AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
    awsRequestMetrics.startEvent(Field.ClientExecuteTime);
    Request<UpdateJobRequest> request = null;
    Response<UpdateJobResult> response = null;

    try {
      awsRequestMetrics.startEvent(Field.RequestMarshallTime);
      try {
        request =
            new UpdateJobRequestMarshaller().marshall(super.beforeMarshalling(updateJobRequest));
        // Binds the request metrics to the current request.
        request.setAWSRequestMetrics(awsRequestMetrics);
      } finally {
        awsRequestMetrics.endEvent(Field.RequestMarshallTime);
      }

      response = invoke(request, new UpdateJobResultStaxUnmarshaller(), executionContext);
      return response.getAwsResponse();

    } finally {

      endClientExecution(awsRequestMetrics, request, response);
    }
  }
 /** Captures the connection pool metrics. */
 private void captureConnectionPoolMetrics(
     ClientConnectionManager connectionManager, AWSRequestMetrics awsRequestMetrics) {
   if (awsRequestMetrics.isEnabled() && connectionManager instanceof ConnPoolControl) {
     ConnPoolControl<?> control = (ConnPoolControl<?>) connectionManager;
     PoolStats stats = control.getTotalStats();
     awsRequestMetrics.setCounter(
         AWSRequestMetrics.Field.HttpClientPoolAvailableCount, stats.getAvailable());
     awsRequestMetrics.setCounter(
         AWSRequestMetrics.Field.HttpClientPoolLeasedCount, stats.getLeased());
     awsRequestMetrics.setCounter(
         AWSRequestMetrics.Field.HttpClientPoolPendingCount, stats.getPending());
   }
 }
 /**
  * Returns a {@link Request} marshalled from the given AWS request using the specified marshaller,
  * recording the respective {@link Field#RequestMarshallTime} predefined metrics.
  */
 private <T extends AmazonWebServiceRequest> Request<T> marshall(
     T awsRequest, Marshaller<Request<T>, T> marshaller, AWSRequestMetrics awsRequestMetrics) {
   awsRequestMetrics.startEvent(Field.RequestMarshallTime);
   try {
     return marshaller.marshall(awsRequest);
   } catch (AmazonClientException ex) {
     throw ex;
   } catch (Exception ex) {
     throw new AmazonClientException(ex.getMessage(), ex);
   } finally {
     awsRequestMetrics.endEvent(Field.RequestMarshallTime);
   }
 }
  /**
   * Handles a successful response from a service call by unmarshalling the results using the
   * specified response handler.
   *
   * @param <T> The type of object expected in the response.
   * @param request The original request that generated the response being handled.
   * @param responseHandler The response unmarshaller used to interpret the contents of the
   *     response.
   * @param method The HTTP method that was invoked, and contains the contents of the response.
   * @param executionContext Extra state information about the request currently being executed.
   * @return The contents of the response, unmarshalled using the specified response handler.
   * @throws IOException If any problems were encountered reading the response contents from the
   *     HTTP method object.
   */
  private <T> T handleResponse(
      Request<?> request,
      HttpResponseHandler<AmazonWebServiceResponse<T>> responseHandler,
      HttpRequestBase method,
      org.apache.http.HttpResponse apacheHttpResponse,
      ExecutionContext executionContext)
      throws IOException {

    HttpResponse httpResponse = createResponse(method, request, apacheHttpResponse);
    if (responseHandler.needsConnectionLeftOpen() && method instanceof HttpEntityEnclosingRequest) {
      HttpEntityEnclosingRequest httpEntityEnclosingRequest = (HttpEntityEnclosingRequest) method;
      httpResponse.setContent(new HttpMethodReleaseInputStream(httpEntityEnclosingRequest));
    }

    try {
      CountingInputStream countingInputStream = null;
      if (System.getProperty(PROFILING_SYSTEM_PROPERTY) != null) {
        countingInputStream = new CountingInputStream(httpResponse.getContent());
        httpResponse.setContent(countingInputStream);
      }

      AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
      awsRequestMetrics.startEvent(Field.ResponseProcessingTime.name());
      AmazonWebServiceResponse<? extends T> awsResponse = responseHandler.handle(httpResponse);
      awsRequestMetrics.endEvent(Field.ResponseProcessingTime.name());
      if (countingInputStream != null) {
        awsRequestMetrics.setCounter(
            Field.BytesProcessed.name(), countingInputStream.getByteCount());
      }

      if (awsResponse == null) throw new RuntimeException("Unable to unmarshall response metadata");

      responseMetadataCache.add(request.getOriginalRequest(), awsResponse.getResponseMetadata());

      if (requestLog.isDebugEnabled()) {
        requestLog.debug(
            "Received successful response: "
                + apacheHttpResponse.getStatusLine().getStatusCode()
                + ", AWS Request ID: "
                + awsResponse.getRequestId());
      }
      awsRequestMetrics.addProperty(Field.AWSRequestID.name(), awsResponse.getRequestId());

      return awsResponse.getResult();
    } catch (CRC32MismatchException e) {
      throw e;
    } catch (Exception e) {
      String errorMessage = "Unable to unmarshall response (" + e.getMessage() + ")";
      throw new AmazonClientException(errorMessage, e);
    }
  }
 /**
  * Deletes a specified stack. Once the call completes successfully, stack deletion starts. Deleted
  * stacks do not show up in the DescribeStacks API if the deletion has been completed
  * successfully.
  *
  * @param deleteStackRequest Container for the necessary parameters to execute the DeleteStack
  *     service method on AmazonCloudFormation.
  * @throws AmazonClientException If any internal errors are encountered inside the client while
  *     attempting to make the request or handle the response. For example if a network connection
  *     is not available.
  * @throws AmazonServiceException If an error response is returned by AmazonCloudFormation
  *     indicating either a problem with the data in the request, or a server side issue.
  */
 public void deleteStack(DeleteStackRequest deleteStackRequest) {
   ExecutionContext executionContext = createExecutionContext(deleteStackRequest);
   AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
   Request<DeleteStackRequest> request = null;
   awsRequestMetrics.startEvent(Field.ClientExecuteTime);
   try {
     request = new DeleteStackRequestMarshaller().marshall(deleteStackRequest);
     // Binds the request metrics to the current request.
     request.setAWSRequestMetrics(awsRequestMetrics);
     invoke(request, null, executionContext);
   } finally {
     endClientExecution(awsRequestMetrics, request, null);
   }
 }
 /**
  * Creates a stack as specified in the template. After the call completes successfully, the stack
  * creation starts. You can check the status of the stack via the DescribeStacks API.
  *
  * @param createStackRequest Container for the necessary parameters to execute the CreateStack
  *     service method on AmazonCloudFormation.
  * @return The response from the CreateStack service method, as returned by AmazonCloudFormation.
  * @throws AlreadyExistsException
  * @throws LimitExceededException
  * @throws InsufficientCapabilitiesException
  * @throws AmazonClientException If any internal errors are encountered inside the client while
  *     attempting to make the request or handle the response. For example if a network connection
  *     is not available.
  * @throws AmazonServiceException If an error response is returned by AmazonCloudFormation
  *     indicating either a problem with the data in the request, or a server side issue.
  */
 public CreateStackResult createStack(CreateStackRequest createStackRequest) {
   ExecutionContext executionContext = createExecutionContext(createStackRequest);
   AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
   Request<CreateStackRequest> request = null;
   Response<CreateStackResult> response = null;
   awsRequestMetrics.startEvent(Field.ClientExecuteTime);
   try {
     request = new CreateStackRequestMarshaller().marshall(createStackRequest);
     // Binds the request metrics to the current request.
     request.setAWSRequestMetrics(awsRequestMetrics);
     response = invoke(request, new CreateStackResultStaxUnmarshaller(), executionContext);
     return response.getAwsResponse();
   } finally {
     endClientExecution(awsRequestMetrics, request, response);
   }
 }
 /**
  * Returns a set of temporary security credentials for users who have been authenticated in a
  * mobile or web application with a web identity provider, such as Amazon Cognito, Login with
  * Amazon, Facebook, Google, or any OpenID Connect-compatible identity provider.
  *
  * <p><b>NOTE:</b> For mobile applications, we recommend that you use Amazon Cognito. You can use
  * Amazon Cognito with the AWS SDK for iOS and the AWS SDK for Android to uniquely identify a user
  * and supply the user with a consistent identity throughout the lifetime of an application. To
  * learn more about Amazon Cognito, see Amazon Cognito Overview in the AWS SDK for Android
  * Developer Guide guide and Amazon Cognito Overview in the AWS SDK for iOS Developer Guide.
  *
  * <p>Calling <code>AssumeRoleWithWebIdentity</code> does not require the use of AWS security
  * credentials. Therefore, you can distribute an application (for example, on mobile devices) that
  * requests temporary security credentials without including long-term AWS credentials in the
  * application, and without deploying server-based proxy services that use long-term AWS
  * credentials. Instead, the identity of the caller is validated by using a token from the web
  * identity provider.
  *
  * <p>The temporary security credentials returned by this API consist of an access key ID, a
  * secret access key, and a security token. Applications can use these temporary security
  * credentials to sign calls to AWS service APIs. The credentials are valid for the duration that
  * you specified when calling <code>AssumeRoleWithWebIdentity</code> , which can be from 900
  * seconds (15 minutes) to 3600 seconds (1 hour). By default, the temporary security credentials
  * are valid for 1 hour.
  *
  * <p>Optionally, you can pass an IAM access policy to this operation. If you choose not to pass a
  * policy, the temporary security credentials that are returned by the operation have the
  * permissions that are defined in the access policy of the role that is being assumed. If you
  * pass a policy to this operation, the temporary security credentials that are returned by the
  * operation have the permissions that are allowed by both the access policy of the role that is
  * being assumed, <i> and </i> the policy that you pass. This gives you a way to further restrict
  * the permissions for the resulting temporary security credentials. You cannot use the passed
  * policy to grant permissions that are in excess of those allowed by the access policy of the
  * role that is being assumed. For more information, see <a
  * href="http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html">
  * Permissions for AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity </a> in the
  * <i>Using IAM</i> .
  *
  * <p>Before your application can call <code>AssumeRoleWithWebIdentity</code> , you must have an
  * identity token from a supported identity provider and create a role that the application can
  * assume. The role that your application assumes must trust the identity provider that is
  * associated with the identity token. In other words, the identity provider must be specified in
  * the role's trust policy.
  *
  * <p>For more information about how to use web identity federation and the <code>
  * AssumeRoleWithWebIdentity</code> API, see the following resources:
  *
  * <ul>
  *   <li><a href="http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_oidc_manual">
  *       Using Web Identity Federation APIs for Mobile Apps </a> and <a
  *       href="http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity">
  *       Federation Through a Web-based Identity Provider </a> .
  *   <li><a href="https://web-identity-federation-playground.s3.amazonaws.com/index.html">Web
  *       Identity Federation Playground </a> . This interactive website lets you walk through the
  *       process of authenticating via Login with Amazon, Facebook, or Google, getting temporary
  *       security credentials, and then using those credentials to make a request to AWS.
  *   <li><a href="http://aws.amazon.com/sdkforios/">AWS SDK for iOS </a> and <a
  *       href="http://aws.amazon.com/sdkforandroid/">AWS SDK for Android </a> . These toolkits
  *       contain sample apps that show how to invoke the identity providers, and then how to use
  *       the information from these providers to get and use temporary security credentials.
  *   <li><a href="http://aws.amazon.com/articles/4617974389850313">Web Identity Federation with
  *       Mobile Applications </a> . This article discusses web identity federation and shows an
  *       example of how to use web identity federation to get access to content in Amazon S3.
  * </ul>
  *
  * @param assumeRoleWithWebIdentityRequest Container for the necessary parameters to execute the
  *     AssumeRoleWithWebIdentity service method on AWSSecurityTokenService.
  * @return The response from the AssumeRoleWithWebIdentity service method, as returned by
  *     AWSSecurityTokenService.
  * @throws PackedPolicyTooLargeException
  * @throws IDPRejectedClaimException
  * @throws MalformedPolicyDocumentException
  * @throws InvalidIdentityTokenException
  * @throws ExpiredTokenException
  * @throws IDPCommunicationErrorException
  * @throws AmazonClientException If any internal errors are encountered inside the client while
  *     attempting to make the request or handle the response. For example if a network connection
  *     is not available.
  * @throws AmazonServiceException If an error response is returned by AWSSecurityTokenService
  *     indicating either a problem with the data in the request, or a server side issue.
  */
 public AssumeRoleWithWebIdentityResult assumeRoleWithWebIdentity(
     AssumeRoleWithWebIdentityRequest assumeRoleWithWebIdentityRequest) {
   ExecutionContext executionContext = createExecutionContext(assumeRoleWithWebIdentityRequest);
   AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
   Request<AssumeRoleWithWebIdentityRequest> request = null;
   Response<AssumeRoleWithWebIdentityResult> response = null;
   awsRequestMetrics.startEvent(Field.ClientExecuteTime);
   try {
     request =
         new AssumeRoleWithWebIdentityRequestMarshaller()
             .marshall(assumeRoleWithWebIdentityRequest);
     // Binds the request metrics to the current request.
     request.setAWSRequestMetrics(awsRequestMetrics);
     response =
         invoke(request, new AssumeRoleWithWebIdentityResultStaxUnmarshaller(), executionContext);
     return response.getAwsResponse();
   } finally {
     endClientExecution(awsRequestMetrics, request, response);
   }
 }
Example #11
0
 /**
  * Executes the request and returns the result.
  *
  * @param request The AmazonWebServices request to send to the remote server
  * @param responseHandler A response handler to accept a successful response from the remote
  *     server
  * @param errorResponseHandler A response handler to accept an unsuccessful response from the
  *     remote server
  * @param executionContext Additional information about the context of this web service call
  */
 public <T> Response<T> execute(
     Request<?> request,
     HttpResponseHandler<AmazonWebServiceResponse<T>> responseHandler,
     HttpResponseHandler<AmazonServiceException> errorResponseHandler,
     ExecutionContext executionContext)
     throws AmazonClientException, AmazonServiceException {
   if (executionContext == null)
     throw new AmazonClientException(
         "Internal SDK Error: No execution context parameter specified.");
   List<RequestHandler2> requestHandler2s = requestHandler2s(request, executionContext);
   final AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
   Response<T> response = null;
   try {
     response = executeHelper(request, responseHandler, errorResponseHandler, executionContext);
     TimingInfo timingInfo = awsRequestMetrics.getTimingInfo().endTiming();
     afterResponse(request, requestHandler2s, response, timingInfo);
     return response;
   } catch (AmazonClientException e) {
     afterError(request, response, requestHandler2s, e);
     throw e;
   }
 }
Example #12
0
 /** Handles an unexpected failure, returning the Throwable instance as given. */
 private <T extends Throwable> T handleUnexpectedFailure(
     T t, AWSRequestMetrics awsRequestMetrics) {
   awsRequestMetrics.incrementCounter(Field.Exception);
   awsRequestMetrics.addProperty(Field.Exception, t);
   return t;
 }
Example #13
0
  /**
   * Internal method to execute the HTTP method given.
   *
   * @see AmazonHttpClient#execute(Request, HttpResponseHandler, HttpResponseHandler)
   * @see AmazonHttpClient#execute(Request, HttpResponseHandler, HttpResponseHandler,
   *     ExecutionContext)
   */
  private <T> Response<T> executeHelper(
      Request<?> request,
      HttpResponseHandler<AmazonWebServiceResponse<T>> responseHandler,
      HttpResponseHandler<AmazonServiceException> errorResponseHandler,
      ExecutionContext executionContext)
      throws AmazonClientException, AmazonServiceException {
    /*
     * Depending on which response handler we end up choosing to handle the
     * HTTP response, it might require us to leave the underlying HTTP
     * connection open, depending on whether or not it reads the complete
     * HTTP response stream from the HTTP connection, or if delays reading
     * any of the content until after a response is returned to the caller.
     */
    boolean leaveHttpConnectionOpen = false;
    AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
    /* add the service endpoint to the logs. You can infer service name from service endpoint */
    awsRequestMetrics.addProperty(Field.ServiceName, request.getServiceName());
    awsRequestMetrics.addProperty(Field.ServiceEndpoint, request.getEndpoint());
    // Apply whatever request options we know how to handle, such as user-agent.
    setUserAgent(request);
    int requestCount = 0;
    URI redirectedURI = null;
    HttpEntity entity = null;
    AmazonClientException retriedException = null;

    // Make a copy of the original request params and headers so that we can
    // permute it in this loop and start over with the original every time.
    Map<String, String> originalParameters = new LinkedHashMap<String, String>();
    originalParameters.putAll(request.getParameters());
    Map<String, String> originalHeaders = new HashMap<String, String>();
    originalHeaders.putAll(request.getHeaders());
    final AWSCredentials credentials = executionContext.getCredentials();
    Signer signer = null;

    while (true) {
      ++requestCount;
      awsRequestMetrics.setCounter(Field.RequestCount, requestCount);
      if (requestCount > 1) { // retry
        request.setParameters(originalParameters);
        request.setHeaders(originalHeaders);
      }
      HttpRequestBase httpRequest = null;
      org.apache.http.HttpResponse apacheResponse = null;

      try {
        // Sign the request if a signer was provided
        if (signer == null) signer = executionContext.getSignerByURI(request.getEndpoint());
        if (signer != null && credentials != null) {
          awsRequestMetrics.startEvent(Field.RequestSigningTime);
          try {
            signer.sign(request, credentials);
          } finally {
            awsRequestMetrics.endEvent(Field.RequestSigningTime);
          }
        }

        if (requestLog.isDebugEnabled()) {
          requestLog.debug("Sending Request: " + request.toString());
        }

        httpRequest = httpRequestFactory.createHttpRequest(request, config, executionContext);

        if (httpRequest instanceof HttpEntityEnclosingRequest) {
          entity = ((HttpEntityEnclosingRequest) httpRequest).getEntity();
        }

        if (redirectedURI != null) {
          httpRequest.setURI(redirectedURI);
        }

        if (requestCount > 1) { // retry
          awsRequestMetrics.startEvent(Field.RetryPauseTime);
          try {
            pauseBeforeNextRetry(
                request.getOriginalRequest(),
                retriedException,
                requestCount,
                config.getRetryPolicy());
          } finally {
            awsRequestMetrics.endEvent(Field.RetryPauseTime);
          }
        }

        if (entity != null) {
          InputStream content = entity.getContent();
          if (requestCount > 1) { // retry
            if (content.markSupported()) {
              content.reset();
              content.mark(-1);
            }
          } else {
            if (content.markSupported()) {
              content.mark(-1);
            }
          }
        }

        captureConnectionPoolMetrics(httpClient.getConnectionManager(), awsRequestMetrics);
        HttpContext httpContext = new BasicHttpContext();
        httpContext.setAttribute(AWSRequestMetrics.class.getSimpleName(), awsRequestMetrics);
        retriedException = null;
        awsRequestMetrics.startEvent(Field.HttpRequestTime);
        try {
          apacheResponse = httpClient.execute(httpRequest, httpContext);
        } finally {
          awsRequestMetrics.endEvent(Field.HttpRequestTime);
        }

        if (isRequestSuccessful(apacheResponse)) {
          awsRequestMetrics.addProperty(
              Field.StatusCode, apacheResponse.getStatusLine().getStatusCode());
          /*
           * If we get back any 2xx status code, then we know we should
           * treat the service call as successful.
           */
          leaveHttpConnectionOpen = responseHandler.needsConnectionLeftOpen();
          HttpResponse httpResponse = createResponse(httpRequest, request, apacheResponse);
          T response =
              handleResponse(
                  request,
                  responseHandler,
                  httpRequest,
                  httpResponse,
                  apacheResponse,
                  executionContext);
          return new Response<T>(response, httpResponse);
        } else if (isTemporaryRedirect(apacheResponse)) {
          /*
           * S3 sends 307 Temporary Redirects if you try to delete an
           * EU bucket from the US endpoint. If we get a 307, we'll
           * point the HTTP method to the redirected location, and let
           * the next retry deliver the request to the right location.
           */
          Header[] locationHeaders = apacheResponse.getHeaders("location");
          String redirectedLocation = locationHeaders[0].getValue();
          log.debug("Redirecting to: " + redirectedLocation);
          redirectedURI = URI.create(redirectedLocation);
          httpRequest.setURI(redirectedURI);
          awsRequestMetrics.addProperty(
              Field.StatusCode, apacheResponse.getStatusLine().getStatusCode());
          awsRequestMetrics.addProperty(Field.RedirectLocation, redirectedLocation);
          awsRequestMetrics.addProperty(Field.AWSRequestID, null);

        } else {
          leaveHttpConnectionOpen = errorResponseHandler.needsConnectionLeftOpen();
          AmazonServiceException ase =
              handleErrorResponse(request, errorResponseHandler, httpRequest, apacheResponse);
          awsRequestMetrics.addProperty(Field.AWSRequestID, ase.getRequestId());
          awsRequestMetrics.addProperty(Field.AWSErrorCode, ase.getErrorCode());
          awsRequestMetrics.addProperty(Field.StatusCode, ase.getStatusCode());

          if (!shouldRetry(
              request.getOriginalRequest(),
              httpRequest,
              ase,
              requestCount,
              config.getRetryPolicy())) {
            throw ase;
          }

          // Cache the retryable exception
          retriedException = ase;
          /*
           * Checking for clock skew error again because we don't want to set the
           * global time offset for every service exception.
           */
          if (RetryUtils.isClockSkewError(ase)) {
            int timeOffset = parseClockSkewOffset(apacheResponse, ase);
            SDKGlobalConfiguration.setGlobalTimeOffset(timeOffset);
          }
          resetRequestAfterError(request, ase);
        }
      } catch (IOException ioe) {
        if (log.isInfoEnabled()) {
          log.info("Unable to execute HTTP request: " + ioe.getMessage(), ioe);
        }
        awsRequestMetrics.incrementCounter(Field.Exception);
        awsRequestMetrics.addProperty(Field.Exception, ioe);
        awsRequestMetrics.addProperty(Field.AWSRequestID, null);

        AmazonClientException ace =
            new AmazonClientException("Unable to execute HTTP request: " + ioe.getMessage(), ioe);
        if (!shouldRetry(
            request.getOriginalRequest(),
            httpRequest,
            ace,
            requestCount,
            config.getRetryPolicy())) {
          throw ace;
        }

        // Cache the retryable exception
        retriedException = ace;
        resetRequestAfterError(request, ioe);
      } catch (RuntimeException e) {
        throw handleUnexpectedFailure(e, awsRequestMetrics);
      } catch (Error e) {
        throw handleUnexpectedFailure(e, awsRequestMetrics);
      } finally {
        /*
         * Some response handlers need to manually manage the HTTP
         * connection and will take care of releasing the connection on
         * their own, but if this response handler doesn't need the
         * connection left open, we go ahead and release the it to free
         * up resources.
         */
        if (!leaveHttpConnectionOpen) {
          try {
            if (apacheResponse != null
                && apacheResponse.getEntity() != null
                && apacheResponse.getEntity().getContent() != null) {
              apacheResponse.getEntity().getContent().close();
            }
          } catch (IOException e) {
            log.warn("Cannot close the response content.", e);
          }
        }
      }
    } /* end while (true) */
  }
  /**
   * Internal method to execute the HTTP method given.
   *
   * @see AmazonHttpClient#execute(Request, HttpResponseHandler, HttpResponseHandler)
   * @see AmazonHttpClient#execute(Request, HttpResponseHandler, HttpResponseHandler,
   *     ExecutionContext)
   */
  private <T extends Object> T executeHelper(
      Request<?> request,
      HttpResponseHandler<AmazonWebServiceResponse<T>> responseHandler,
      HttpResponseHandler<AmazonServiceException> errorResponseHandler,
      ExecutionContext executionContext)
      throws AmazonClientException, AmazonServiceException {

    /*
     * Depending on which response handler we end up choosing to handle the
     * HTTP response, it might require us to leave the underlying HTTP
     * connection open, depending on whether or not it reads the complete
     * HTTP response stream from the HTTP connection, or if delays reading
     * any of the content until after a response is returned to the caller.
     */
    boolean leaveHttpConnectionOpen = false;

    AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
    /* add the service endpoint to the logs. You can infer service name from service endpoint */
    awsRequestMetrics.addProperty(Field.ServiceName.name(), request.getServiceName());
    awsRequestMetrics.addProperty(Field.ServiceEndpoint.name(), request.getEndpoint());

    // Apply whatever request options we know how to handle, such as user-agent.
    applyRequestData(request);

    int retryCount = 0;
    URI redirectedURI = null;
    HttpEntity entity = null;
    AmazonServiceException exception = null;

    // Make a copy of the original request params and headers so that we can
    // permute it in this loop and start over with the original every time.
    Map<String, String> originalParameters = new HashMap<String, String>();
    originalParameters.putAll(request.getParameters());
    Map<String, String> originalHeaders = new HashMap<String, String>();
    originalHeaders.putAll(request.getHeaders());

    while (true) {
      awsRequestMetrics.setCounter(Field.AttemptCount.name(), retryCount + 1);
      if (retryCount > 0) {
        request.setParameters(originalParameters);
        request.setHeaders(originalHeaders);
      }

      HttpRequestBase httpRequest = null;
      org.apache.http.HttpResponse response = null;

      try {
        // Sign the request if a signer was provided
        if (executionContext.getSigner() != null && executionContext.getCredentials() != null) {
          awsRequestMetrics.startEvent(Field.RequestSigningTime.name());
          executionContext.getSigner().sign(request, executionContext.getCredentials());
          awsRequestMetrics.endEvent(Field.RequestSigningTime.name());
        }

        if (requestLog.isDebugEnabled()) {
          requestLog.debug("Sending Request: " + request.toString());
        }

        httpRequest =
            httpRequestFactory.createHttpRequest(request, config, entity, executionContext);

        if (httpRequest instanceof HttpEntityEnclosingRequest) {
          entity = ((HttpEntityEnclosingRequest) httpRequest).getEntity();
        }

        if (redirectedURI != null) {
          httpRequest.setURI(redirectedURI);
        }

        if (retryCount > 0) {
          awsRequestMetrics.startEvent(Field.RetryPauseTime.name());
          pauseExponentially(retryCount, exception, executionContext.getCustomBackoffStrategy());
          awsRequestMetrics.endEvent(Field.RetryPauseTime.name());
        }

        if (entity != null) {
          InputStream content = entity.getContent();
          if (retryCount > 0) {
            if (content.markSupported()) {
              content.reset();
              content.mark(-1);
            }
          } else {
            if (content.markSupported()) {
              content.mark(-1);
            }
          }
        }

        exception = null;

        awsRequestMetrics.startEvent(Field.HttpRequestTime.name());
        response = httpClient.execute(httpRequest);
        awsRequestMetrics.endEvent(Field.HttpRequestTime.name());

        if (isRequestSuccessful(response)) {

          awsRequestMetrics.addProperty(
              Field.StatusCode.name(), response.getStatusLine().getStatusCode());

          /*
           * If we get back any 2xx status code, then we know we should
           * treat the service call as successful.
           */
          leaveHttpConnectionOpen = responseHandler.needsConnectionLeftOpen();
          return handleResponse(request, responseHandler, httpRequest, response, executionContext);
        } else if (isTemporaryRedirect(response)) {
          /*
           * S3 sends 307 Temporary Redirects if you try to delete an
           * EU bucket from the US endpoint. If we get a 307, we'll
           * point the HTTP method to the redirected location, and let
           * the next retry deliver the request to the right location.
           */
          Header[] locationHeaders = response.getHeaders("location");
          String redirectedLocation = locationHeaders[0].getValue();
          log.debug("Redirecting to: " + redirectedLocation);
          redirectedURI = URI.create(redirectedLocation);
          httpRequest.setURI(redirectedURI);
          awsRequestMetrics.addProperty(
              Field.StatusCode.name(), response.getStatusLine().getStatusCode());
          awsRequestMetrics.addProperty(Field.RedirectLocation.name(), redirectedLocation);
          awsRequestMetrics.addProperty(Field.AWSRequestID.name(), null);

        } else {
          leaveHttpConnectionOpen = errorResponseHandler.needsConnectionLeftOpen();
          exception = handleErrorResponse(request, errorResponseHandler, httpRequest, response);
          awsRequestMetrics.addProperty(Field.AWSRequestID.name(), exception.getRequestId());
          awsRequestMetrics.addProperty(Field.AWSErrorCode.name(), exception.getErrorCode());
          awsRequestMetrics.addProperty(Field.StatusCode.name(), exception.getStatusCode());

          if (!shouldRetry(httpRequest, exception, retryCount)) {
            throw exception;
          }
          resetRequestAfterError(request, exception);
        }
      } catch (IOException ioe) {
        log.info("Unable to execute HTTP request: " + ioe.getMessage(), ioe);
        awsRequestMetrics.addProperty(Field.Exception.name(), ioe.toString());
        awsRequestMetrics.addProperty(Field.AWSRequestID.name(), null);

        if (!shouldRetry(httpRequest, ioe, retryCount)) {
          throw new AmazonClientException(
              "Unable to execute HTTP request: " + ioe.getMessage(), ioe);
        }
        resetRequestAfterError(request, ioe);
      } finally {
        retryCount++;

        /*
         * Some response handlers need to manually manage the HTTP
         * connection and will take care of releasing the connection on
         * their own, but if this response handler doesn't need the
         * connection left open, we go ahead and release the it to free
         * up resources.
         */
        if (!leaveHttpConnectionOpen) {
          try {
            response.getEntity().getContent().close();
          } catch (Throwable t) {
          }
        }
      }
    } /* end while (true) */
  }