18
18
package org .openqa .selenium .remote .http .netty ;
19
19
20
20
import com .google .auto .service .AutoService ;
21
- import io .netty .util .HashedWheelTimer ;
22
- import io .netty .util .Timer ;
23
- import io .netty .util .concurrent .DefaultThreadFactory ;
21
+
24
22
import org .asynchttpclient .AsyncHttpClient ;
25
23
import org .asynchttpclient .DefaultAsyncHttpClientConfig ;
26
24
import org .asynchttpclient .Dsl ;
35
33
import org .openqa .selenium .remote .http .HttpResponse ;
36
34
import org .openqa .selenium .remote .http .WebSocket ;
37
35
36
+ import io .netty .util .HashedWheelTimer ;
37
+ import io .netty .util .Timer ;
38
+ import io .netty .util .concurrent .DefaultThreadFactory ;
39
+
38
40
import java .io .IOException ;
39
41
import java .io .UncheckedIOException ;
40
42
import java .util .concurrent .ThreadFactory ;
41
43
import java .util .concurrent .TimeUnit ;
44
+ import java .util .concurrent .atomic .AtomicBoolean ;
42
45
import java .util .function .BiFunction ;
43
46
44
47
public class NettyClient implements HttpClient {
48
+
45
49
private static final Timer TIMER ;
50
+ private static final AtomicBoolean addedHook = new AtomicBoolean ();
51
+ private static final AsyncHttpClient client = createHttpClient (ClientConfig .defaultConfig ());
52
+
46
53
static {
47
54
ThreadFactory threadFactory = new DefaultThreadFactory ("netty-client-timer" , true );
48
55
HashedWheelTimer timer = new HashedWheelTimer (
@@ -53,19 +60,30 @@ public class NettyClient implements HttpClient {
53
60
timer .start ();
54
61
TIMER = timer ;
55
62
}
63
+
56
64
private final ClientConfig config ;
57
- private final AsyncHttpClient client ;
58
65
private final HttpHandler handler ;
59
66
private final BiFunction <HttpRequest , WebSocket .Listener , WebSocket > toWebSocket ;
60
67
61
68
private NettyClient (ClientConfig config ) {
62
69
this .config = Require .nonNull ("HTTP client config" , config );
63
- this .client = createHttpClient (config );
64
- this .handler = new NettyHttpHandler (config , this .client ).with (config .filter ());
65
- this .toWebSocket = NettyWebSocket .create (config , this .client );
70
+ this .handler = new NettyHttpHandler (config , client ).with (config .filter ());
71
+ this .toWebSocket = NettyWebSocket .create (config , client );
72
+ if (!addedHook .get ()) {
73
+ Runtime .getRuntime ().addShutdownHook (new Thread (this ::shutdownClient ));
74
+ addedHook .set (true );
75
+ }
66
76
}
67
77
68
- private AsyncHttpClient createHttpClient (ClientConfig config ) {
78
+ /**
79
+ * Converts a long to an int, clamping the maximum and minimum values to
80
+ * fit in an integer without overflowing.
81
+ */
82
+ static int toClampedInt (long value ) {
83
+ return (int ) Math .max (Integer .MIN_VALUE , Math .min (Integer .MAX_VALUE , value ));
84
+ }
85
+
86
+ private static AsyncHttpClient createHttpClient (ClientConfig config ) {
69
87
DefaultAsyncHttpClientConfig .Builder builder =
70
88
new DefaultAsyncHttpClientConfig .Builder ()
71
89
.setThreadFactory (new DefaultThreadFactory ("AsyncHttpClient" , true ))
@@ -77,18 +95,9 @@ private AsyncHttpClient createHttpClient(ClientConfig config) {
77
95
.setRequestTimeout (toClampedInt (config .readTimeout ().toMillis ()))
78
96
.setConnectTimeout (toClampedInt (config .connectionTimeout ().toMillis ()))
79
97
.setReadTimeout (toClampedInt (config .readTimeout ().toMillis ()));
80
-
81
98
return Dsl .asyncHttpClient (builder );
82
99
}
83
100
84
- /**
85
- * Converts a long to an int, clamping the maximum and minimum values to
86
- * fit in an integer without overflowing.
87
- */
88
- private int toClampedInt (long value ) {
89
- return (int ) Math .max (Integer .MIN_VALUE , Math .min (Integer .MAX_VALUE , value ));
90
- }
91
-
92
101
@ Override
93
102
public HttpResponse execute (HttpRequest request ) {
94
103
return handler .execute (request );
@@ -112,6 +121,10 @@ public HttpClient with(Filter filter) {
112
121
113
122
@ Override
114
123
public void close () {
124
+ // no-op -- done by the shutdown hook
125
+ }
126
+
127
+ private void shutdownClient () {
115
128
try {
116
129
client .close ();
117
130
} catch (IOException e ) {
0 commit comments