/* * Copyright 2011-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.amazonaws.client; import com.amazonaws.AmazonWebServiceRequest; import com.amazonaws.Request; import com.amazonaws.RequestConfig; import com.amazonaws.Response; import com.amazonaws.SdkBaseException; import com.amazonaws.annotation.Immutable; import com.amazonaws.annotation.SdkProtectedApi; import com.amazonaws.annotation.ThreadSafe; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.handlers.RequestHandler2; import com.amazonaws.http.AmazonHttpClient; import com.amazonaws.http.ExecutionContext; import com.amazonaws.http.HttpResponseHandler; import com.amazonaws.internal.auth.SignerProvider; import com.amazonaws.metrics.AwsSdkMetrics; import com.amazonaws.metrics.RequestMetricCollector; import com.amazonaws.util.AWSRequestMetrics; import com.amazonaws.util.CredentialUtils; import java.net.URI; import java.util.List; /** * Default implementation of {@link ClientHandler}. */ @Immutable @ThreadSafe @SdkProtectedApi public class ClientHandlerImpl extends ClientHandler { private final AWSCredentialsProvider awsCredentialsProvider; private final SignerProvider signerProvider; private final URI endpoint; private final List<RequestHandler2> requestHandler2s; private final RequestMetricCollector clientLevelMetricCollector; private final AmazonHttpClient client; public ClientHandlerImpl(ClientHandlerParams handlerParams) { this.signerProvider = handlerParams.getClientParams().getSignerProvider(); this.endpoint = handlerParams.getClientParams().getEndpoint(); this.awsCredentialsProvider = handlerParams.getClientParams().getCredentialsProvider(); this.requestHandler2s = handlerParams.getClientParams().getRequestHandlers(); this.clientLevelMetricCollector = handlerParams.getClientParams().getRequestMetricCollector(); this.client = buildHttpClient(handlerParams); } private AmazonHttpClient buildHttpClient(ClientHandlerParams handlerParams) { final AwsSyncClientParams clientParams = handlerParams.getClientParams(); return AmazonHttpClient.builder() .clientConfiguration(clientParams.getClientConfiguration()) .retryPolicy(clientParams.getRetryPolicy()) .requestMetricCollector(clientParams.getRequestMetricCollector()) .useBrowserCompatibleHostNameVerifier(handlerParams.isDisableStrictHostnameVerification()) .build(); } @Override public <Input, Output> Output execute( ClientExecutionParams<Input, Output> executionParams) { final Input input = executionParams.getInput(); ExecutionContext executionContext = createExecutionContext( executionParams.getRequestConfig()); AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics(); awsRequestMetrics.startEvent(AWSRequestMetrics.Field.ClientExecuteTime); Request<Input> request = null; Response<Output> response = null; try { awsRequestMetrics.startEvent(AWSRequestMetrics.Field.RequestMarshallTime); try { request = executionParams.getMarshaller().marshall(input); request.setAWSRequestMetrics(awsRequestMetrics); } finally { awsRequestMetrics.endEvent(AWSRequestMetrics.Field.RequestMarshallTime); } response = invoke(request, executionParams.getRequestConfig(), executionContext, executionParams.getResponseHandler(), executionParams.getErrorResponseHandler()); return response.getAwsResponse(); } finally { endClientExecution(awsRequestMetrics, executionParams.getRequestConfig(), request, response); } } @Override public void shutdown() { client.shutdown(); } private ExecutionContext createExecutionContext(RequestConfig requestConfig) { boolean isMetricsEnabled = isRequestMetricsEnabled(requestConfig); return ExecutionContext.builder() .withRequestHandler2s(requestHandler2s) .withUseRequestMetrics(isMetricsEnabled) .withSignerProvider(signerProvider) .build(); } /** * Returns true if request metric collection is applicable to the given request; false * otherwise. */ private boolean isRequestMetricsEnabled(RequestConfig requestConfig) { return hasRequestMetricsCollector(requestConfig) || isRMCEnabledAtClientOrSdkLevel(); } private boolean hasRequestMetricsCollector(RequestConfig requestConfig) { return requestConfig.getRequestMetricsCollector() != null && requestConfig.getRequestMetricsCollector().isEnabled(); } /** * Returns true if request metric collection is enabled at the service client or AWS SDK level * request; false otherwise. */ private boolean isRMCEnabledAtClientOrSdkLevel() { RequestMetricCollector collector = requestMetricCollector(); return collector != null && collector.isEnabled(); } /** * Returns the client specific request metric collector if there is one; or the one at the AWS * SDK level otherwise. */ private RequestMetricCollector requestMetricCollector() { return clientLevelMetricCollector != null ? clientLevelMetricCollector : AwsSdkMetrics.getRequestMetricCollector(); } /** * Runs the {@code beforeMarshalling} method of any {@code RequestHandler2}s associated with * this client. * * @param request the request passed in from the user * @return The (possibly different) request to marshall */ @SuppressWarnings("unchecked") protected final <T extends AmazonWebServiceRequest> T beforeMarshalling(T request) { T local = request; for (RequestHandler2 handler : requestHandler2s) { local = (T) handler.beforeMarshalling(local); } return local; } /** * Normal invoke with authentication. Credentials are required and may be overriden at the * request level. **/ private <Output, Input> Response<Output> invoke(Request<Input> request, RequestConfig requestConfig, ExecutionContext executionContext, HttpResponseHandler<Output> responseHandler, HttpResponseHandler<? extends SdkBaseException> errorResponseHandler) { executionContext.setCredentialsProvider(CredentialUtils.getCredentialsProvider( requestConfig, awsCredentialsProvider)); return doInvoke(request, requestConfig, executionContext, responseHandler, errorResponseHandler); } /** * Invoke the request using the http client. Assumes credentials (or lack thereof) have been * configured in the ExecutionContext beforehand. **/ private <Output, Input> Response<Output> doInvoke(Request<Input> request, RequestConfig requestConfig, ExecutionContext executionContext, HttpResponseHandler<Output> responseHandler, HttpResponseHandler<? extends SdkBaseException> errorResponseHandler) { request.setEndpoint(endpoint); return client.requestExecutionBuilder() .request(request) .requestConfig(requestConfig) .executionContext(executionContext) .errorResponseHandler(errorResponseHandler) .execute(responseHandler); } /** * Convenient method to end the client execution without logging the awsRequestMetrics. */ private void endClientExecution(AWSRequestMetrics awsRequestMetrics, RequestConfig requestConfig, Request<?> request, Response<?> response) { if (request != null) { awsRequestMetrics.endEvent(AWSRequestMetrics.Field.ClientExecuteTime); awsRequestMetrics.getTimingInfo().endTiming(); RequestMetricCollector metricCollector = findRequestMetricCollector(requestConfig); metricCollector.collectMetrics(request, response); awsRequestMetrics.log(); } } /** * Returns the most specific request metric collector, starting from the request level, then * client level, then finally the AWS SDK level. */ private RequestMetricCollector findRequestMetricCollector(RequestConfig requestConfig) { RequestMetricCollector reqLevelMetricsCollector = requestConfig .getRequestMetricsCollector(); if (reqLevelMetricsCollector != null) { return reqLevelMetricsCollector; } else if (clientLevelMetricCollector != null) { return clientLevelMetricCollector; } else { return AwsSdkMetrics.getRequestMetricCollector(); } } }