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