1 /*
2 * Copyright 2015-2020 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 package com.amazonaws.http.timers.request;
16
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.ScheduledThreadPoolExecutor;
19 import java.util.concurrent.TimeUnit;
20
21 import org.apache.http.client.methods.HttpRequestBase;
22
23 import com.amazonaws.annotation.SdkInternalApi;
24 import com.amazonaws.annotation.SdkTestInternalApi;
25 import com.amazonaws.annotation.ThreadSafe;
26 import com.amazonaws.http.timers.TimeoutThreadPoolBuilder;
27
28 /**
29 * Represents a timer class to enforce HTTP request timeouts.
30 */
31 // DO NOT override finalize(). The shutdown() method is called from AmazonHttpClient#shutdown()
32 // which is called from it's finalize() method. Since finalize methods can be be called in any order
33 // and even concurrently, we need to rely on AmazonHttpClient to call our shutdown() method.
34 @ThreadSafe
35 @SdkInternalApi
36 public class HttpRequestTimer {
37
38 private static final String threadNamePrefix = "AwsSdkRequestTimerThread";
39
40 private volatile ScheduledThreadPoolExecutor executor;
41
42 /**
43 * Start the timer with the specified timeout and return a object that can be used to track the
44 * state of the timer and cancel it if need be.
45 *
46 * @param apacheRequest
47 * HTTP request this timer will abort if triggered.
48 * @param requestTimeoutMillis
49 * A positive value here enables the timer, a non-positive value disables it and
50 * returns a dummy tracker task
51 * @return Implementation of {@link HttpRequestAbortTaskTrackerImpl} to query the state of the
52 * task and cancel it if appropriate
53 */
54 public HttpRequestAbortTaskTracker startTimer(final HttpRequestBase apacheRequest, final int requestTimeoutMillis) {
55 if (isTimeoutDisabled(requestTimeoutMillis)) {
56 return NoOpHttpRequestAbortTaskTracker.INSTANCE;
57 } else if (executor == null) {
58 initializeExecutor();
59 }
60 HttpRequestAbortTaskImpl timerTask = new HttpRequestAbortTaskImpl(apacheRequest);
61 ScheduledFuture<?> timerTaskFuture = executor.schedule(timerTask, requestTimeoutMillis, TimeUnit.MILLISECONDS);
62 return new HttpRequestAbortTaskTrackerImpl(timerTask, timerTaskFuture);
63 }
64
65 private boolean isTimeoutDisabled(final int requestTimeoutMillis) {
66 return requestTimeoutMillis <= 0;
67 }
68
69 /**
70 * Executor is lazily initialized as it's not compatible with Java 6
71 */
72 private synchronized void initializeExecutor() {
73 if (executor == null) {
74 executor = TimeoutThreadPoolBuilder.buildDefaultTimeoutThreadPool(threadNamePrefix);
75 }
76 }
77
78 /**
79 * Shutdown the underlying {@link ScheduledThreadPoolExecutor}. Should be invoked when
80 * {@link com.amazonaws.http.AmazonHttpClient} is shutdown
81 */
82 public synchronized void shutdown() {
83 if (executor != null) {
84 executor.shutdown();
85 }
86 }
87
88 /**
89 * This method is current exposed for testing purposes
90 *
91 * @return The underlying {@link ScheduledThreadPoolExecutor}
92 */
93 @SdkTestInternalApi
94 public ScheduledThreadPoolExecutor getExecutor() {
95 return executor;
96 }
97
98 }
99