1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.core5.http2.nio.pool;
28
29 import java.net.InetSocketAddress;
30 import java.util.concurrent.Future;
31
32 import org.apache.hc.core5.annotation.Contract;
33 import org.apache.hc.core5.annotation.ThreadingBehavior;
34 import org.apache.hc.core5.concurrent.FutureCallback;
35 import org.apache.hc.core5.function.Callback;
36 import org.apache.hc.core5.function.Resolver;
37 import org.apache.hc.core5.http.HttpHost;
38 import org.apache.hc.core5.http.URIScheme;
39 import org.apache.hc.core5.http.impl.DefaultAddressResolver;
40 import org.apache.hc.core5.http.nio.command.ShutdownCommand;
41 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
42 import org.apache.hc.core5.http2.nio.command.PingCommand;
43 import org.apache.hc.core5.http2.nio.support.BasicPingHandler;
44 import org.apache.hc.core5.io.CloseMode;
45 import org.apache.hc.core5.reactor.AbstractIOSessionPool;
46 import org.apache.hc.core5.reactor.Command;
47 import org.apache.hc.core5.reactor.ConnectionInitiator;
48 import org.apache.hc.core5.reactor.IOSession;
49 import org.apache.hc.core5.reactor.ssl.TransportSecurityLayer;
50 import org.apache.hc.core5.util.Args;
51 import org.apache.hc.core5.util.TimeValue;
52 import org.apache.hc.core5.util.Timeout;
53
54
55
56
57
58
59 @Contract(threading = ThreadingBehavior.SAFE)
60 public final class H2ConnPool extends AbstractIOSessionPool<HttpHost> {
61
62 private final ConnectionInitiator connectionInitiator;
63 private final Resolver<HttpHost, InetSocketAddress> addressResolver;
64 private final TlsStrategy tlsStrategy;
65
66 private volatile TimeValue validateAfterInactivity = TimeValue.NEG_ONE_MILLISECOND;
67
68 public H2ConnPool(
69 final ConnectionInitiator connectionInitiator,
70 final Resolver<HttpHost, InetSocketAddress> addressResolver,
71 final TlsStrategy tlsStrategy) {
72 super();
73 this.connectionInitiator = Args.notNull(connectionInitiator, "Connection initiator");
74 this.addressResolver = addressResolver != null ? addressResolver : DefaultAddressResolver.INSTANCE;
75 this.tlsStrategy = tlsStrategy;
76 }
77
78 public TimeValue getValidateAfterInactivity() {
79 return validateAfterInactivity;
80 }
81
82 public void setValidateAfterInactivity(final TimeValue timeValue) {
83 this.validateAfterInactivity = timeValue;
84 }
85
86 @Override
87 protected void closeSession(
88 final IOSession ioSession,
89 final CloseMode closeMode) {
90 if (closeMode == CloseMode.GRACEFUL) {
91 ioSession.enqueue(ShutdownCommand.GRACEFUL, Command.Priority.NORMAL);
92 } else {
93 ioSession.close(closeMode);
94 }
95 }
96
97 @Override
98 protected Future<IOSession> connectSession(
99 final HttpHost namedEndpoint,
100 final Timeout connectTimeout,
101 final FutureCallback<IOSession> callback) {
102 final InetSocketAddress remoteAddress = addressResolver.resolve(namedEndpoint);
103 return connectionInitiator.connect(namedEndpoint, remoteAddress, null, connectTimeout, null, new FutureCallback<IOSession>() {
104
105 @Override
106 public void completed(final IOSession ioSession) {
107 if (tlsStrategy != null
108 && URIScheme.HTTPS.same(namedEndpoint.getSchemeName())
109 && ioSession instanceof TransportSecurityLayer) {
110 tlsStrategy.upgrade(
111 (TransportSecurityLayer) ioSession,
112 namedEndpoint,
113 ioSession.getLocalAddress(),
114 ioSession.getRemoteAddress(),
115 null,
116 connectTimeout);
117 ioSession.setSocketTimeout(connectTimeout);
118 }
119 callback.completed(ioSession);
120 }
121
122 @Override
123 public void failed(final Exception ex) {
124 callback.failed(ex);
125 }
126
127 @Override
128 public void cancelled() {
129 callback.cancelled();
130 }
131
132 });
133 }
134
135 @Override
136 protected void validateSession(
137 final IOSession ioSession,
138 final Callback<Boolean> callback) {
139 if (ioSession.isOpen()) {
140 final TimeValue timeValue = validateAfterInactivity;
141 if (TimeValue.isNonNegative(timeValue)) {
142 final long lastAccessTime = Math.min(ioSession.getLastReadTime(), ioSession.getLastWriteTime());
143 final long deadline = lastAccessTime + timeValue.toMilliseconds();
144 if (deadline <= System.currentTimeMillis()) {
145 final Timeout socketTimeoutMillis = ioSession.getSocketTimeout();
146 ioSession.enqueue(new PingCommand(new BasicPingHandler(new Callback<Boolean>() {
147
148 @Override
149 public void execute(final Boolean result) {
150 ioSession.setSocketTimeout(socketTimeoutMillis);
151 callback.execute(result);
152 }
153
154 })), Command.Priority.NORMAL);
155 return;
156 }
157 }
158 callback.execute(true);
159 } else {
160 callback.execute(false);
161 }
162 }
163
164 }