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