1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.core.interceptor; 17 18 import java.io.InputStream; 19 import java.nio.ByteBuffer; 20 import java.util.Optional; 21 import org.reactivestreams.Publisher; 22 import software.amazon.awssdk.annotations.SdkPublicApi; 23 import software.amazon.awssdk.core.SdkRequest; 24 import software.amazon.awssdk.core.SdkResponse; 25 import software.amazon.awssdk.core.async.AsyncRequestBody; 26 27 // CHECKSTYLE:OFF - Avoid "Unused Import" error. If we use the FQCN in the Javadoc, we'll run into line length issues instead. 28 import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; 29 // CHECKSTYLE:ON 30 import software.amazon.awssdk.core.retry.RetryPolicy; 31 import software.amazon.awssdk.core.sync.RequestBody; 32 import software.amazon.awssdk.http.SdkHttpFullRequest; 33 import software.amazon.awssdk.http.SdkHttpRequest; 34 import software.amazon.awssdk.http.SdkHttpResponse; 35 36 /** 37 * An interceptor that is invoked during the execution lifecycle of a request/response (execution). This can be used to publish 38 * metrics, modify a request in-flight, debug request processing, view exceptions, etc. This interface exposes different methods 39 * for hooking into different parts of the lifecycle of an execution. 40 * 41 * <p> 42 * <b>Interceptor Hooks</b> 43 * Methods for a given interceptor are executed in a predictable order, each receiving the information that is known about the 44 * message so far as well as a {@link ExecutionAttributes} object for storing data that is specific to a particular execution. 45 * <ol> 46 * <li>{@link #beforeExecution} - Read the request before it is modified by other interceptors.</li> 47 * <li>{@link #modifyRequest} - Modify the request object before it is marshalled into an HTTP request.</li> 48 * <li>{@link #beforeMarshalling} - Read the request that has potentially been modified by other request interceptors before 49 * it is marshalled into an HTTP request.</li> 50 * <li>{@link #afterMarshalling} - Read the HTTP request after it is created and before it can be modified by other 51 * interceptors.</li> 52 * <li>{@link #modifyHttpRequest} - Modify the HTTP request object before it is transmitted.</li> 53 * <li>{@link #beforeTransmission} - Read the HTTP request that has potentially been modified by other request interceptors 54 * before it is sent to the service.</li> 55 * <li>{@link #afterTransmission} - Read the HTTP response after it is received and before it can be modified by other 56 * interceptors.</li> 57 * <li>{@link #modifyHttpResponse} - Modify the HTTP response object before it is unmarshalled.</li> 58 * <li>{@link #beforeUnmarshalling} - Read the HTTP response that has potentially been modified by other request interceptors 59 * before it is unmarshalled.</li> 60 * <li>{@link #afterUnmarshalling} - Read the response after it is created and before it can be modified by other 61 * interceptors.</li> 62 * <li>{@link #modifyResponse} - Modify the response object before before it is returned to the client.</li> 63 * <li>{@link #afterExecution} - Read the response that has potentially been modified by other request interceptors.</li> 64 * </ol> 65 * An additional {@link #onExecutionFailure} method is provided that is invoked if an execution fails at any point during the 66 * lifecycle of a request, including exceptions being thrown from this or other interceptors. 67 * <p> 68 * 69 * <p> 70 * <b>Interceptor Registration</b> 71 * Interceptors can be registered in one of many ways. 72 * <ol> 73 * <li><i>Override Configuration Interceptors</i> are the most common method for SDK users to register an interceptor. These 74 * interceptors are explicitly added to the client builder's override configuration when a client is created using the {@link 75 * ClientOverrideConfiguration.Builder#addExecutionInterceptor(ExecutionInterceptor)} 76 * method.</li> 77 * 78 * <li><i>Global Interceptors</i> are interceptors loaded from the classpath for all clients. When any service client is 79 * created by a client builder, all jars on the classpath (from the perspective of the current thread's classloader) are 80 * checked for a file named '/software/amazon/awssdk/global/handlers/execution.interceptors'. Any interceptors listed in these 81 * files (new line separated) are instantiated using their default constructor and loaded into the client.</li> 82 * 83 * <li><i>Service Interceptors</i> are interceptors loaded from the classpath for a particular service's clients. When a 84 * service client is created by a client builder, all jars on the classpath (from the perspective of the current thread's 85 * classloader) are checked for a file named '/software/amazon/awssdk/services/{service}/execution.interceptors', where 86 * {service} is the package name of the service client. Any interceptors listed in these files (new line separated) are 87 * instantiated using their default constructor and loaded into the client.</li> 88 * </ol> 89 * <p> 90 * 91 * <p> 92 * <b>Interceptor Order</b> 93 * The order in which interceptors are executed is sometimes relevant to the accuracy of the interceptor itself. For example, an 94 * interceptor that adds a field to a message should be executed before an interceptor that reads and modifies that field. 95 * Interceptor's order is determined by their method of registration. The following order is used: 96 * <ol> 97 * <li><i>Global Interceptors</i>. Interceptors earlier in the classpath will be placed earlier in the interceptor order than 98 * interceptors later in the classpath. Interceptors earlier within a specific file on the classpath will be placed earlier in 99 * the order than interceptors later in the file.</li> 100 * 101 * <li><i>Service Interceptors</i>. Interceptors earlier in the classpath will be placed earlier in the interceptor order than 102 * interceptors later in the classpath. Interceptors earlier within a specific file on the classpath will be placed earlier in 103 * the order than interceptors later in the file.</li> 104 * 105 * <li><i>Override Configuration Interceptors</i>. Any interceptors registered using 106 * {@link ClientOverrideConfiguration.Builder#addExecutionInterceptor(ExecutionInterceptor)} 107 * in the order they were added.</li> 108 * </ol> 109 * When a request is being processed (up to and including {@link #beforeTransmission}, interceptors are applied in forward-order, 110 * according to the order described above. When a response is being processed (after and including {@link #afterTransmission}, 111 * interceptors are applied in reverse-order from the order described above. This means that the last interceptors to touch the 112 * request are the first interceptors to touch the response. 113 * <p> 114 * 115 * <p> 116 * <b>Execution Attributes</b> 117 * {@link ExecutionAttributes} are unique to an execution (the process of an SDK processing a {@link SdkRequest}). This mutable 118 * collection of attributes is created when a call to a service client is made and can be mutated throughout the course of the 119 * client call. These attributes are made available to every interceptor hook and is available for storing data between method 120 * calls. The SDK provides some attributes automatically, available via {@link SdkExecutionAttribute}. 121 */ 122 @SdkPublicApi 123 public interface ExecutionInterceptor { 124 /** 125 * Read a request that has been given to a service client before it is modified by other interceptors. 126 * {@link #beforeMarshalling} should be used in most circumstances for reading the request because it includes modifications 127 * made by other interceptors. 128 * 129 * <p>This method is guaranteed to be executed on the thread that is making the client call. This is true even if a non- 130 * blocking I/O client is used. This is useful for transferring data that may be stored thread-locally into the execution's 131 * {@link ExecutionAttributes}. 132 * 133 * @param context The current state of the execution, including the unmodified SDK request from the service client call. 134 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 135 */ beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes)136 default void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) { 137 138 } 139 140 /** 141 * Modify an {@link SdkRequest} given to a service client before it is marshalled into an {@link SdkHttpFullRequest}. 142 * 143 * @param context The current state of the execution, including the current SDK request from the service client call. 144 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 145 * give data to future lifecycle methods. 146 * @return The potentially-modified request that should be used for the rest of the execution. Must not be null. 147 */ modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes)148 default SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) { 149 return context.request(); 150 } 151 152 /** 153 * Read the finalized request as it will be given to the marshaller to be converted into an {@link SdkHttpFullRequest}. 154 * 155 * @param context The current state of the execution, including the SDK request (potentially modified by other interceptors) 156 * from the service client call. 157 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 158 */ beforeMarshalling(Context.BeforeMarshalling context, ExecutionAttributes executionAttributes)159 default void beforeMarshalling(Context.BeforeMarshalling context, ExecutionAttributes executionAttributes) { 160 } 161 162 /** 163 * Read the marshalled HTTP request, before it is modified by other interceptors. {@link #beforeTransmission} should be used 164 * in most circumstances for reading the HTTP request because it includes modifications made by other interceptors. 165 * 166 * @param context The current state of the execution, including the SDK and unmodified HTTP request. 167 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 168 */ afterMarshalling(Context.AfterMarshalling context, ExecutionAttributes executionAttributes)169 default void afterMarshalling(Context.AfterMarshalling context, ExecutionAttributes executionAttributes) { 170 171 } 172 173 /** 174 * Modify the {@link SdkHttpFullRequest} before it is sent to the service. 175 * 176 * @param context The current state of the execution, including the SDK and current HTTP request. 177 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 178 * give data to future lifecycle methods. 179 * @return The potentially-modified HTTP request that should be sent to the service. Must not be null. 180 */ modifyHttpRequest(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes)181 default SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context, 182 ExecutionAttributes executionAttributes) { 183 return context.httpRequest(); 184 } 185 modifyHttpContent(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes)186 default Optional<RequestBody> modifyHttpContent(Context.ModifyHttpRequest context, 187 ExecutionAttributes executionAttributes) { 188 return context.requestBody(); 189 } 190 modifyAsyncHttpContent(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes)191 default Optional<AsyncRequestBody> modifyAsyncHttpContent(Context.ModifyHttpRequest context, 192 ExecutionAttributes executionAttributes) { 193 return context.asyncRequestBody(); 194 } 195 196 /** 197 * Read the finalized HTTP request as it will be sent to the HTTP client. This includes modifications made by other 198 * interceptors and the message signature. It is possible that the HTTP client could further modify the request, so debug- 199 * level wire logging should be trusted over the parameters to this method. 200 * 201 * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines 202 * a request failure is retriable, this will be invoked for each retry attempt. 203 * 204 * @param context The current state of the execution, including the SDK and HTTP request (potentially modified by other 205 * interceptors) to be sent to the downstream service. 206 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 207 */ beforeTransmission(Context.BeforeTransmission context, ExecutionAttributes executionAttributes)208 default void beforeTransmission(Context.BeforeTransmission context, ExecutionAttributes executionAttributes) { 209 210 } 211 212 /** 213 * Read the HTTP response as it was returned by the HTTP client, before it is modified by other interceptors. 214 * {@link #beforeUnmarshalling} should be used in most circumstances for reading the HTTP response because it includes 215 * modifications made by other interceptors. 216 * 217 * <p>It is possible that the HTTP client could have already modified this response, so debug-level wire logging should be 218 * trusted over the parameters to this method. 219 * 220 * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines 221 * the error code returned by the service is retriable, this will be invoked for each response returned by the service. 222 * 223 * @param context The current state of the execution, including the SDK and HTTP requests and the unmodified HTTP response. 224 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 225 */ afterTransmission(Context.AfterTransmission context, ExecutionAttributes executionAttributes)226 default void afterTransmission(Context.AfterTransmission context, ExecutionAttributes executionAttributes) { 227 } 228 229 /** 230 * Modify the {@link SdkHttpFullRequest} before it is unmarshalled into an {@link SdkResponse}. 231 * 232 * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines 233 * the error code returned by the service is retriable, this will be invoked for each response returned by the service. 234 * 235 * @param context The current state of the execution, including the SDK and HTTP requests and the current HTTP response. 236 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 237 * give data to future lifecycle methods. 238 * @return The potentially-modified HTTP response that should be given to the unmarshaller. Must not be null. 239 */ modifyHttpResponse(Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes)240 default SdkHttpResponse modifyHttpResponse(Context.ModifyHttpResponse context, 241 ExecutionAttributes executionAttributes) { 242 return context.httpResponse(); 243 } 244 245 /** 246 * Modify the {@link SdkHttpFullRequest} before it is unmarshalled into an {@link SdkResponse}. 247 * 248 * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines 249 * the error code returned by the service is retriable, this will be invoked for each response returned by the service. 250 * 251 * @param context The current state of the execution, including the SDK and HTTP requests and the current HTTP response. 252 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 253 * give data to future lifecycle methods. 254 * @return The potentially-modified HTTP response that should be given to the unmarshaller. Must not be null. 255 */ modifyAsyncHttpResponseContent(Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes)256 default Optional<Publisher<ByteBuffer>> modifyAsyncHttpResponseContent(Context.ModifyHttpResponse context, 257 ExecutionAttributes executionAttributes) { 258 259 // get headers here 260 return context.responsePublisher(); 261 } 262 263 /** 264 * Modify the {@link SdkHttpFullRequest} before it is unmarshalled into an {@link SdkResponse}. 265 * 266 * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines 267 * the error code returned by the service is retriable, this will be invoked for each response returned by the service. 268 * 269 * @param context The current state of the execution, including the SDK and HTTP requests and the current HTTP response. 270 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 271 * give data to future lifecycle methods. 272 * @return The potentially-modified HTTP response that should be given to the unmarshaller. Must not be null. 273 */ modifyHttpResponseContent(Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes)274 default Optional<InputStream> modifyHttpResponseContent(Context.ModifyHttpResponse context, 275 ExecutionAttributes executionAttributes) { 276 return context.responseBody(); 277 } 278 279 /** 280 * Read the finalized HTTP response as it will be given to the unmarshaller to be converted into an {@link SdkResponse}. 281 * 282 * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines 283 * the error code returned by the service is retriable, this will be invoked for each response returned by the service. 284 * 285 * @param context The current state of the execution, including the SDK and HTTP requests as well as the (potentially 286 * modified by other interceptors) HTTP response. 287 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 288 * give data to future lifecycle methods. 289 */ beforeUnmarshalling(Context.BeforeUnmarshalling context, ExecutionAttributes executionAttributes)290 default void beforeUnmarshalling(Context.BeforeUnmarshalling context, ExecutionAttributes executionAttributes) { 291 292 } 293 294 /** 295 * Read the {@link SdkResponse} as it was returned by the unmarshaller, before it is modified by other interceptors. 296 * {@link #afterExecution} should be used in most circumstances for reading the SDK response because it includes 297 * modifications made by other interceptors. 298 * 299 * @param context The current state of the execution, including the SDK and HTTP requests and the HTTP response. 300 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 301 * give data to future lifecycle methods. 302 */ afterUnmarshalling(Context.AfterUnmarshalling context, ExecutionAttributes executionAttributes)303 default void afterUnmarshalling(Context.AfterUnmarshalling context, ExecutionAttributes executionAttributes) { 304 305 } 306 307 /** 308 * Modify the {@link SdkResponse} before it is returned by the client. 309 * 310 * @param context The current state of the execution, including the SDK and HTTP requests as well as the SDK and HTTP 311 * response. 312 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 313 * give data to future lifecycle methods. 314 * @return The potentially-modified SDK response that should be returned by the client. Must not be null. 315 */ modifyResponse(Context.ModifyResponse context, ExecutionAttributes executionAttributes)316 default SdkResponse modifyResponse(Context.ModifyResponse context, ExecutionAttributes executionAttributes) { 317 return context.response(); 318 } 319 320 /** 321 * Read the finalized {@link SdkResponse} as it will be returned by the client invocation. 322 * 323 * @param context The current state of the execution, including the SDK and HTTP requests as well as the SDK and HTTP 324 * response. 325 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 326 * give data to future lifecycle methods. 327 */ afterExecution(Context.AfterExecution context, ExecutionAttributes executionAttributes)328 default void afterExecution(Context.AfterExecution context, ExecutionAttributes executionAttributes) { 329 330 } 331 332 /** 333 * Modify the exception before it is thrown. 334 * 335 * <p>This will only be invoked if the entire execution fails. If a retriable error happens (according to the 336 * {@link RetryPolicy}) and a subsequent retry succeeds, this method will not be invoked. 337 * 338 * @param context The context associated with the execution that failed. An SDK request will always be available, but 339 * depending on the time at which the failure happened, the HTTP request, HTTP response and SDK response may 340 * not be available. This also includes the exception that triggered the failure. 341 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 342 * give data to future lifecycle methods. 343 * @return the modified Exception 344 */ modifyException(Context.FailedExecution context, ExecutionAttributes executionAttributes)345 default Throwable modifyException(Context.FailedExecution context, ExecutionAttributes executionAttributes) { 346 return context.exception(); 347 } 348 349 /** 350 * Invoked when any error happens during an execution that prevents the request from succeeding. This could be due to an 351 * error returned by a service call, a request timeout or even another interceptor raising an exception. The provided 352 * exception will be thrown by the service client. 353 * 354 * <p>This will only be invoked if the entire execution fails. If a retriable error happens (according to the 355 * {@link RetryPolicy}) and a subsequent retry succeeds, this method will not be invoked. 356 * 357 * @param context The context associated with the execution that failed. An SDK request will always be available, but 358 * depending on the time at which the failure happened, the HTTP request, HTTP response and SDK response may 359 * not be available. This also includes the exception that triggered the failure. 360 * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to 361 * give data to future lifecycle methods. 362 */ onExecutionFailure(Context.FailedExecution context, ExecutionAttributes executionAttributes)363 default void onExecutionFailure(Context.FailedExecution context, ExecutionAttributes executionAttributes) { 364 365 } 366 } 367