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.client5.http.impl.io;
28
29 import java.io.IOException;
30 import java.util.Set;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.Future;
33 import java.util.concurrent.TimeoutException;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.concurrent.atomic.AtomicReference;
36 import java.util.concurrent.locks.ReentrantLock;
37
38 import org.apache.hc.client5.http.DnsResolver;
39 import org.apache.hc.client5.http.EndpointInfo;
40 import org.apache.hc.client5.http.HttpRoute;
41 import org.apache.hc.client5.http.SchemePortResolver;
42 import org.apache.hc.client5.http.config.ConnectionConfig;
43 import org.apache.hc.client5.http.config.TlsConfig;
44 import org.apache.hc.client5.http.impl.ConnPoolSupport;
45 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
46 import org.apache.hc.client5.http.impl.PrefixedIncrementingId;
47 import org.apache.hc.client5.http.io.ConnectionEndpoint;
48 import org.apache.hc.client5.http.io.HttpClientConnectionManager;
49 import org.apache.hc.client5.http.io.HttpClientConnectionOperator;
50 import org.apache.hc.client5.http.io.LeaseRequest;
51 import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
52 import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
53 import org.apache.hc.client5.http.ssl.TlsSocketStrategy;
54 import org.apache.hc.core5.annotation.Contract;
55 import org.apache.hc.core5.annotation.Internal;
56 import org.apache.hc.core5.annotation.ThreadingBehavior;
57 import org.apache.hc.core5.function.Resolver;
58 import org.apache.hc.core5.http.ClassicHttpRequest;
59 import org.apache.hc.core5.http.ClassicHttpResponse;
60 import org.apache.hc.core5.http.HttpException;
61 import org.apache.hc.core5.http.HttpHost;
62 import org.apache.hc.core5.http.URIScheme;
63 import org.apache.hc.core5.http.config.Registry;
64 import org.apache.hc.core5.http.config.RegistryBuilder;
65 import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
66 import org.apache.hc.core5.http.io.HttpConnectionFactory;
67 import org.apache.hc.core5.http.io.SocketConfig;
68 import org.apache.hc.core5.http.protocol.HttpContext;
69 import org.apache.hc.core5.io.CloseMode;
70 import org.apache.hc.core5.pool.ConnPoolControl;
71 import org.apache.hc.core5.pool.LaxConnPool;
72 import org.apache.hc.core5.pool.ManagedConnPool;
73 import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
74 import org.apache.hc.core5.pool.PoolEntry;
75 import org.apache.hc.core5.pool.PoolReusePolicy;
76 import org.apache.hc.core5.pool.PoolStats;
77 import org.apache.hc.core5.pool.StrictConnPool;
78 import org.apache.hc.core5.util.Args;
79 import org.apache.hc.core5.util.Deadline;
80 import org.apache.hc.core5.util.Identifiable;
81 import org.apache.hc.core5.util.TimeValue;
82 import org.apache.hc.core5.util.Timeout;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
105 public class PoolingHttpClientConnectionManager
106 implements HttpClientConnectionManager, ConnPoolControl<HttpRoute> {
107
108 private static final Logger LOG = LoggerFactory.getLogger(PoolingHttpClientConnectionManager.class);
109
110 public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 25;
111 public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;
112
113 private final HttpClientConnectionOperator connectionOperator;
114 private final ManagedConnPool<HttpRoute, ManagedHttpClientConnection> pool;
115 private final HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
116 private final AtomicBoolean closed;
117
118 private volatile Resolver<HttpRoute, SocketConfig> socketConfigResolver;
119 private volatile Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
120 private volatile Resolver<HttpHost, TlsConfig> tlsConfigResolver;
121
122 public PoolingHttpClientConnectionManager() {
123 this(new DefaultHttpClientConnectionOperator(null, null,
124 RegistryBuilder.<TlsSocketStrategy>create()
125 .register(URIScheme.HTTPS.id, DefaultClientTlsStrategy.createDefault())
126 .build()),
127 PoolConcurrencyPolicy.STRICT,
128 PoolReusePolicy.LIFO,
129 TimeValue.NEG_ONE_MILLISECOND,
130 null);
131 }
132
133
134
135
136 @Deprecated
137 public PoolingHttpClientConnectionManager(
138 final Registry<org.apache.hc.client5.http.socket.ConnectionSocketFactory> socketFactoryRegistry) {
139 this(socketFactoryRegistry, null);
140 }
141
142
143
144
145 @Deprecated
146 public PoolingHttpClientConnectionManager(
147 final Registry<org.apache.hc.client5.http.socket.ConnectionSocketFactory> socketFactoryRegistry,
148 final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
149 this(socketFactoryRegistry, PoolConcurrencyPolicy.STRICT, TimeValue.NEG_ONE_MILLISECOND, connFactory);
150 }
151
152
153
154
155 @Deprecated
156 public PoolingHttpClientConnectionManager(
157 final Registry<org.apache.hc.client5.http.socket.ConnectionSocketFactory> socketFactoryRegistry,
158 final PoolConcurrencyPolicy poolConcurrencyPolicy,
159 final TimeValue timeToLive,
160 final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
161 this(socketFactoryRegistry, poolConcurrencyPolicy, PoolReusePolicy.LIFO, timeToLive, connFactory);
162 }
163
164
165
166
167 @Deprecated
168 public PoolingHttpClientConnectionManager(
169 final Registry<org.apache.hc.client5.http.socket.ConnectionSocketFactory> socketFactoryRegistry,
170 final PoolConcurrencyPolicy poolConcurrencyPolicy,
171 final PoolReusePolicy poolReusePolicy,
172 final TimeValue timeToLive) {
173 this(socketFactoryRegistry, poolConcurrencyPolicy, poolReusePolicy, timeToLive, null);
174 }
175
176
177
178
179 @Deprecated
180 public PoolingHttpClientConnectionManager(
181 final Registry<org.apache.hc.client5.http.socket.ConnectionSocketFactory> socketFactoryRegistry,
182 final PoolConcurrencyPolicy poolConcurrencyPolicy,
183 final PoolReusePolicy poolReusePolicy,
184 final TimeValue timeToLive,
185 final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
186 this(socketFactoryRegistry, poolConcurrencyPolicy, poolReusePolicy, timeToLive, null, null, connFactory);
187 }
188
189
190
191
192 @Deprecated
193 public PoolingHttpClientConnectionManager(
194 final Registry<org.apache.hc.client5.http.socket.ConnectionSocketFactory> socketFactoryRegistry,
195 final PoolConcurrencyPolicy poolConcurrencyPolicy,
196 final PoolReusePolicy poolReusePolicy,
197 final TimeValue timeToLive,
198 final SchemePortResolver schemePortResolver,
199 final DnsResolver dnsResolver,
200 final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
201 this(new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver),
202 poolConcurrencyPolicy,
203 poolReusePolicy,
204 timeToLive,
205 connFactory);
206 }
207
208 @Internal
209 protected PoolingHttpClientConnectionManager(
210 final HttpClientConnectionOperator httpClientConnectionOperator,
211 final PoolConcurrencyPolicy poolConcurrencyPolicy,
212 final PoolReusePolicy poolReusePolicy,
213 final TimeValue timeToLive,
214 final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
215 super();
216 this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
217 switch (poolConcurrencyPolicy != null ? poolConcurrencyPolicy : PoolConcurrencyPolicy.STRICT) {
218 case STRICT:
219 this.pool = new StrictConnPool<HttpRoute, ManagedHttpClientConnection>(
220 DEFAULT_MAX_CONNECTIONS_PER_ROUTE,
221 DEFAULT_MAX_TOTAL_CONNECTIONS,
222 timeToLive,
223 poolReusePolicy,
224 null) {
225
226 @Override
227 public void closeExpired() {
228 enumAvailable(e -> closeIfExpired(e));
229 }
230
231 };
232 break;
233 case LAX:
234 this.pool = new LaxConnPool<HttpRoute, ManagedHttpClientConnection>(
235 DEFAULT_MAX_CONNECTIONS_PER_ROUTE,
236 timeToLive,
237 poolReusePolicy,
238 null) {
239
240 @Override
241 public void closeExpired() {
242 enumAvailable(e -> closeIfExpired(e));
243 }
244
245 };
246 break;
247 default:
248 throw new IllegalArgumentException("Unexpected PoolConcurrencyPolicy value: " + poolConcurrencyPolicy);
249 }
250 this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
251 this.closed = new AtomicBoolean(false);
252 }
253
254 @Internal
255 protected PoolingHttpClientConnectionManager(
256 final HttpClientConnectionOperator httpClientConnectionOperator,
257 final ManagedConnPool<HttpRoute, ManagedHttpClientConnection> pool,
258 final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
259 super();
260 this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
261 this.pool = Args.notNull(pool, "Connection pool");
262 this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
263 this.closed = new AtomicBoolean(false);
264 }
265
266 @Override
267 public void close() {
268 close(CloseMode.GRACEFUL);
269 }
270
271 @Override
272 public void close(final CloseMode closeMode) {
273 if (this.closed.compareAndSet(false, true)) {
274 if (LOG.isDebugEnabled()) {
275 LOG.debug("Shutdown connection pool {}", closeMode);
276 }
277 this.pool.close(closeMode);
278 LOG.debug("Connection pool shut down");
279 }
280 }
281
282 private InternalConnectionEndpoint cast(final ConnectionEndpoint endpoint) {
283 if (endpoint instanceof InternalConnectionEndpoint) {
284 return (InternalConnectionEndpoint) endpoint;
285 }
286 throw new IllegalStateException("Unexpected endpoint class: " + endpoint.getClass());
287 }
288
289 private SocketConfig resolveSocketConfig(final HttpRoute route) {
290 final Resolver<HttpRoute, SocketConfig> resolver = this.socketConfigResolver;
291 final SocketConfig socketConfig = resolver != null ? resolver.resolve(route) : null;
292 return socketConfig != null ? socketConfig : SocketConfig.DEFAULT;
293 }
294
295 private ConnectionConfig resolveConnectionConfig(final HttpRoute route) {
296 final Resolver<HttpRoute, ConnectionConfig> resolver = this.connectionConfigResolver;
297 final ConnectionConfig connectionConfig = resolver != null ? resolver.resolve(route) : null;
298 return connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
299 }
300
301 private TlsConfig resolveTlsConfig(final HttpHost host) {
302 final Resolver<HttpHost, TlsConfig> resolver = this.tlsConfigResolver;
303 final TlsConfig tlsConfig = resolver != null ? resolver.resolve(host) : null;
304 return tlsConfig != null ? tlsConfig : TlsConfig.DEFAULT;
305 }
306
307 private TimeValue resolveValidateAfterInactivity(final ConnectionConfig connectionConfig) {
308 final TimeValue timeValue = connectionConfig.getValidateAfterInactivity();
309 return timeValue != null ? timeValue : TimeValue.ofSeconds(2);
310 }
311
312 public LeaseRequest lease(final String id, final HttpRoute route, final Object state) {
313 return lease(id, route, Timeout.DISABLED, state);
314 }
315
316 @Override
317 public LeaseRequest lease(
318 final String id,
319 final HttpRoute route,
320 final Timeout requestTimeout,
321 final Object state) {
322 Args.notNull(route, "HTTP route");
323 if (LOG.isDebugEnabled()) {
324 LOG.debug("{} endpoint lease request ({}) {}", id, requestTimeout, ConnPoolSupport.formatStats(route, state, pool));
325 }
326 final Future<PoolEntry<HttpRoute, ManagedHttpClientConnection>> leaseFuture = this.pool.lease(route, state, requestTimeout, null);
327 return new LeaseRequest() {
328
329
330 private final ReentrantLock lock = new ReentrantLock();
331 private volatile ConnectionEndpoint endpoint;
332
333 @Override
334 public ConnectionEndpoint get(
335 final Timeout timeout) throws InterruptedException, ExecutionException, TimeoutException {
336 lock.lock();
337 try {
338 Args.notNull(timeout, "Operation timeout");
339 if (this.endpoint != null) {
340 return this.endpoint;
341 }
342 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry;
343 try {
344 poolEntry = leaseFuture.get(timeout.getDuration(), timeout.getTimeUnit());
345 } catch (final TimeoutException ex) {
346 leaseFuture.cancel(true);
347 throw ex;
348 }
349 if (LOG.isDebugEnabled()) {
350 LOG.debug("{} endpoint leased {}", id, ConnPoolSupport.formatStats(route, state, pool));
351 }
352 final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
353 try {
354 if (poolEntry.hasConnection()) {
355 final TimeValue timeToLive = connectionConfig.getTimeToLive();
356 if (TimeValue.isNonNegative(timeToLive)) {
357 if (timeToLive.getDuration() == 0
358 || Deadline.calculate(poolEntry.getCreated(), timeToLive).isExpired()) {
359 poolEntry.discardConnection(CloseMode.GRACEFUL);
360 }
361 }
362 }
363 if (poolEntry.hasConnection()) {
364 final TimeValue timeValue = resolveValidateAfterInactivity(connectionConfig);
365 if (TimeValue.isNonNegative(timeValue)) {
366 if (timeValue.getDuration() == 0
367 || Deadline.calculate(poolEntry.getUpdated(), timeValue).isExpired()) {
368 final ManagedHttpClientConnection conn = poolEntry.getConnection();
369 boolean stale;
370 try {
371 stale = conn.isStale();
372 } catch (final IOException ignore) {
373 stale = true;
374 }
375 if (stale) {
376 if (LOG.isDebugEnabled()) {
377 LOG.debug("{} connection {} is stale", id, ConnPoolSupport.getId(conn));
378 }
379 poolEntry.discardConnection(CloseMode.IMMEDIATE);
380 }
381 }
382 }
383 }
384 final ManagedHttpClientConnection conn = poolEntry.getConnection();
385 if (conn != null) {
386 conn.activate();
387 } else {
388 poolEntry.assignConnection(connFactory.createConnection(null));
389 }
390 this.endpoint = new InternalConnectionEndpoint(poolEntry);
391 if (LOG.isDebugEnabled()) {
392 LOG.debug("{} acquired {}", id, ConnPoolSupport.getId(endpoint));
393 }
394 return this.endpoint;
395 } catch (final Exception ex) {
396 if (LOG.isDebugEnabled()) {
397 LOG.debug("{} endpoint lease failed", id);
398 }
399 pool.release(poolEntry, false);
400 throw new ExecutionException(ex.getMessage(), ex);
401 }
402 } finally {
403 lock.unlock();
404 }
405 }
406
407 @Override
408 public boolean cancel() {
409 return leaseFuture.cancel(true);
410 }
411
412 };
413
414 }
415
416 @Override
417 public void release(final ConnectionEndpoint endpoint, final Object state, final TimeValue keepAlive) {
418 Args.notNull(endpoint, "Managed endpoint");
419 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = cast(endpoint).detach();
420 if (entry == null) {
421 return;
422 }
423 if (LOG.isDebugEnabled()) {
424 LOG.debug("{} releasing endpoint", ConnPoolSupport.getId(endpoint));
425 }
426
427 if (this.isClosed()) {
428 return;
429 }
430
431 final ManagedHttpClientConnection conn = entry.getConnection();
432 if (conn != null && keepAlive == null) {
433 conn.close(CloseMode.GRACEFUL);
434 }
435 boolean reusable = conn != null && conn.isOpen() && conn.isConsistent();
436 try {
437 if (reusable) {
438 entry.updateState(state);
439 entry.updateExpiry(keepAlive);
440 conn.passivate();
441 if (LOG.isDebugEnabled()) {
442 final String s;
443 if (TimeValue.isPositive(keepAlive)) {
444 s = "for " + keepAlive;
445 } else {
446 s = "indefinitely";
447 }
448 LOG.debug("{} connection {} can be kept alive {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn), s);
449 }
450 } else {
451 if (LOG.isDebugEnabled()) {
452 if (conn != null && !conn.isConsistent()) {
453 LOG.debug("{} connection is in an inconsistent state and cannot be kept alive)", ConnPoolSupport.getId(endpoint));
454 } else {
455 LOG.debug("{} connection is not kept alive)", ConnPoolSupport.getId(endpoint));
456 }
457 }
458 }
459 } catch (final RuntimeException ex) {
460 reusable = false;
461 throw ex;
462 } finally {
463 this.pool.release(entry, reusable);
464 if (LOG.isDebugEnabled()) {
465 LOG.debug("{} connection released {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.formatStats(entry.getRoute(), entry.getState(), pool));
466 }
467 }
468 }
469
470 @Override
471 public void connect(final ConnectionEndpoint endpoint, final TimeValue timeout, final HttpContext context) throws IOException {
472 Args.notNull(endpoint, "Managed endpoint");
473 final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
474 if (internalEndpoint.isConnected()) {
475 return;
476 }
477 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = internalEndpoint.getPoolEntry();
478 if (!poolEntry.hasConnection()) {
479 poolEntry.assignConnection(connFactory.createConnection(null));
480 }
481 final HttpRoute route = poolEntry.getRoute();
482 final HttpHost firstHop = route.getProxyHost() != null ? route.getProxyHost() : route.getTargetHost();
483 final SocketConfig socketConfig = resolveSocketConfig(route);
484 final ConnectionConfig connectionConfig = resolveConnectionConfig(route);
485 final Timeout connectTimeout = timeout != null ? Timeout.of(timeout.getDuration(), timeout.getTimeUnit()) : connectionConfig.getConnectTimeout();
486 if (LOG.isDebugEnabled()) {
487 LOG.debug("{} connecting endpoint to {} ({})", ConnPoolSupport.getId(endpoint), firstHop, connectTimeout);
488 }
489 final ManagedHttpClientConnection conn = poolEntry.getConnection();
490 this.connectionOperator.connect(
491 conn,
492 firstHop,
493 route.getTargetName(),
494 route.getLocalSocketAddress(),
495 connectTimeout,
496 socketConfig,
497 route.isTunnelled() ? null : resolveTlsConfig(route.getTargetHost()),
498 context);
499 if (LOG.isDebugEnabled()) {
500 LOG.debug("{} connected {}", ConnPoolSupport.getId(endpoint), ConnPoolSupport.getId(conn));
501 }
502 final Timeout socketTimeout = connectionConfig.getSocketTimeout();
503 if (socketTimeout != null) {
504 conn.setSocketTimeout(socketTimeout);
505 }
506 }
507
508 @Override
509 public void upgrade(final ConnectionEndpoint endpoint, final HttpContext context) throws IOException {
510 Args.notNull(endpoint, "Managed endpoint");
511 final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
512 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = internalEndpoint.getValidatedPoolEntry();
513 final HttpRoute route = poolEntry.getRoute();
514 final HttpHost target = route.getTargetHost();
515 final TlsConfig tlsConfig = resolveTlsConfig(target);
516 this.connectionOperator.upgrade(
517 poolEntry.getConnection(),
518 target,
519 route.getTargetName(),
520 tlsConfig,
521 context);
522 }
523
524 @Override
525 public void closeIdle(final TimeValue idleTime) {
526 Args.notNull(idleTime, "Idle time");
527 if (LOG.isDebugEnabled()) {
528 LOG.debug("Closing connections idle longer than {}", idleTime);
529 }
530 if (isClosed()) {
531 return;
532 }
533 this.pool.closeIdle(idleTime);
534 }
535
536 @Override
537 public void closeExpired() {
538 if (isClosed()) {
539 return;
540 }
541 LOG.debug("Closing expired connections");
542 this.pool.closeExpired();
543 }
544
545 @Override
546 public Set<HttpRoute> getRoutes() {
547 return this.pool.getRoutes();
548 }
549
550 @Override
551 public int getMaxTotal() {
552 return this.pool.getMaxTotal();
553 }
554
555 @Override
556 public void setMaxTotal(final int max) {
557 this.pool.setMaxTotal(max);
558 }
559
560 @Override
561 public int getDefaultMaxPerRoute() {
562 return this.pool.getDefaultMaxPerRoute();
563 }
564
565 @Override
566 public void setDefaultMaxPerRoute(final int max) {
567 this.pool.setDefaultMaxPerRoute(max);
568 }
569
570 @Override
571 public int getMaxPerRoute(final HttpRoute route) {
572 return this.pool.getMaxPerRoute(route);
573 }
574
575 @Override
576 public void setMaxPerRoute(final HttpRoute route, final int max) {
577 this.pool.setMaxPerRoute(route, max);
578 }
579
580 @Override
581 public PoolStats getTotalStats() {
582 return this.pool.getTotalStats();
583 }
584
585 @Override
586 public PoolStats getStats(final HttpRoute route) {
587 return this.pool.getStats(route);
588 }
589
590
591
592
593 public void setDefaultSocketConfig(final SocketConfig config) {
594 this.socketConfigResolver = (route) -> config;
595 }
596
597
598
599
600
601
602 public void setSocketConfigResolver(final Resolver<HttpRoute, SocketConfig> socketConfigResolver) {
603 this.socketConfigResolver = socketConfigResolver;
604 }
605
606
607
608
609
610
611 public void setDefaultConnectionConfig(final ConnectionConfig config) {
612 this.connectionConfigResolver = (route) -> config;
613 }
614
615
616
617
618
619
620 public void setConnectionConfigResolver(final Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver) {
621 this.connectionConfigResolver = connectionConfigResolver;
622 }
623
624
625
626
627
628
629 public void setDefaultTlsConfig(final TlsConfig config) {
630 this.tlsConfigResolver = (host) -> config;
631 }
632
633
634
635
636
637
638 public void setTlsConfigResolver(final Resolver<HttpHost, TlsConfig> tlsConfigResolver) {
639 this.tlsConfigResolver = tlsConfigResolver;
640 }
641
642 void closeIfExpired(final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry) {
643 final long now = System.currentTimeMillis();
644 if (entry.getExpiryDeadline().isBefore(now)) {
645 entry.discardConnection(CloseMode.GRACEFUL);
646 } else {
647 final ConnectionConfig connectionConfig = resolveConnectionConfig(entry.getRoute());
648 final TimeValue timeToLive = connectionConfig.getTimeToLive();
649 if (timeToLive != null && Deadline.calculate(entry.getCreated(), timeToLive).isBefore(now)) {
650 entry.discardConnection(CloseMode.GRACEFUL);
651 }
652 }
653 }
654
655
656
657
658 @Deprecated
659 public SocketConfig getDefaultSocketConfig() {
660 return SocketConfig.DEFAULT;
661 }
662
663
664
665
666
667
668 @Deprecated
669 public TimeValue getValidateAfterInactivity() {
670 return ConnectionConfig.DEFAULT.getValidateAfterInactivity();
671 }
672
673
674
675
676
677
678
679
680
681
682
683 @Deprecated
684 public void setValidateAfterInactivity(final TimeValue validateAfterInactivity) {
685 setDefaultConnectionConfig(ConnectionConfig.custom()
686 .setValidateAfterInactivity(validateAfterInactivity)
687 .build());
688 }
689
690 private static final PrefixedIncrementingId INCREMENTING_ID = new PrefixedIncrementingId("ep-");
691
692 static class InternalConnectionEndpoint extends ConnectionEndpoint implements Identifiable {
693
694 private final AtomicReference<PoolEntry<HttpRoute, ManagedHttpClientConnection>> poolEntryRef;
695 private final String id;
696
697 InternalConnectionEndpoint(
698 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry) {
699 this.poolEntryRef = new AtomicReference<>(poolEntry);
700 this.id = INCREMENTING_ID.getNextId();
701 }
702
703 @Override
704 public String getId() {
705 return id;
706 }
707
708 PoolEntry<HttpRoute, ManagedHttpClientConnection> getPoolEntry() {
709 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = poolEntryRef.get();
710 if (poolEntry == null) {
711 throw new ConnectionShutdownException();
712 }
713 return poolEntry;
714 }
715
716 PoolEntry<HttpRoute, ManagedHttpClientConnection> getValidatedPoolEntry() {
717 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = getPoolEntry();
718 final ManagedHttpClientConnection connection = poolEntry.getConnection();
719 if (connection == null || !connection.isOpen()) {
720 throw new ConnectionShutdownException();
721 }
722 return poolEntry;
723 }
724
725 PoolEntry<HttpRoute, ManagedHttpClientConnection> detach() {
726 return poolEntryRef.getAndSet(null);
727 }
728
729 @Override
730 public void close(final CloseMode closeMode) {
731 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = poolEntryRef.get();
732 if (poolEntry != null) {
733 poolEntry.discardConnection(closeMode);
734 }
735 }
736
737 @Override
738 public void close() throws IOException {
739 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = poolEntryRef.get();
740 if (poolEntry != null) {
741 poolEntry.discardConnection(CloseMode.GRACEFUL);
742 }
743 }
744
745 @Override
746 public boolean isConnected() {
747 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = getPoolEntry();
748 final ManagedHttpClientConnection connection = poolEntry.getConnection();
749 return connection != null && connection.isOpen();
750 }
751
752 @Override
753 public void setSocketTimeout(final Timeout timeout) {
754 getValidatedPoolEntry().getConnection().setSocketTimeout(timeout);
755 }
756
757
758
759
760 @Deprecated
761 @Override
762 public ClassicHttpResponse execute(
763 final String exchangeId,
764 final ClassicHttpRequest request,
765 final HttpRequestExecutor requestExecutor,
766 final HttpContext context) throws IOException, HttpException {
767 Args.notNull(request, "HTTP request");
768 Args.notNull(requestExecutor, "Request executor");
769 final ManagedHttpClientConnection connection = getValidatedPoolEntry().getConnection();
770 if (LOG.isDebugEnabled()) {
771 LOG.debug("{} executing exchange {} over {}", id, exchangeId, ConnPoolSupport.getId(connection));
772 }
773 return requestExecutor.execute(request, connection, context);
774 }
775
776
777
778
779 public ClassicHttpResponse execute(
780 final String exchangeId,
781 final ClassicHttpRequest request,
782 final RequestExecutor requestExecutor,
783 final HttpContext context) throws IOException, HttpException {
784 Args.notNull(request, "HTTP request");
785 Args.notNull(requestExecutor, "Request executor");
786 final ManagedHttpClientConnection connection = getValidatedPoolEntry().getConnection();
787 if (LOG.isDebugEnabled()) {
788 LOG.debug("{} executing exchange {} over {}", id, exchangeId, ConnPoolSupport.getId(connection));
789 }
790 return requestExecutor.execute(request, connection, context);
791 }
792
793
794
795
796 @Override
797 public EndpointInfo getInfo() {
798 final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = poolEntryRef.get();
799 if (poolEntry != null) {
800 final ManagedHttpClientConnection connection = poolEntry.getConnection();
801 if (connection != null && connection.isOpen()) {
802 return new EndpointInfo(connection.getProtocolVersion(), connection.getSSLSession());
803 }
804 }
805 return null;
806 }
807
808 }
809
810
811
812
813
814
815
816
817
818 public boolean isClosed() {
819 return this.closed.get();
820 }
821
822
823 }