26
26
import java .io .OutputStream ;
27
27
import java .net .URI ;
28
28
import java .util .ArrayList ;
29
+ import java .util .LinkedList ;
29
30
import java .util .List ;
30
31
import java .util .Map ;
31
- import java .util .Optional ;
32
32
import java .util .concurrent .CompletableFuture ;
33
33
import java .util .concurrent .Future ;
34
34
import java .util .concurrent .atomic .AtomicLong ;
35
35
import java .util .logging .Level ;
36
36
import java .util .logging .Logger ;
37
+ import java .util .stream .Collectors ;
37
38
38
39
import javax .ws .rs .ProcessingException ;
39
40
import javax .ws .rs .client .Client ;
173
174
class ApacheConnector implements Connector {
174
175
175
176
private static final Logger LOGGER = Logger .getLogger (ApacheConnector .class .getName ());
176
-
177
177
private static final VersionInfo vi ;
178
178
private static final String release ;
179
179
@@ -325,14 +325,16 @@ class ApacheConnector implements Connector {
325
325
}
326
326
clientBuilder .setDefaultRequestConfig (requestConfig );
327
327
328
- Optional <Object > contract = config .getInstances ().stream ()
329
- .filter (a -> ApacheHttpClientBuilderConfigurator .class .isInstance (a )).findFirst ();
328
+ LinkedList <Object > contracts = config .getInstances ().stream ()
329
+ .filter (ApacheHttpClientBuilderConfigurator .class ::isInstance )
330
+ .collect (Collectors .toCollection (LinkedList ::new ));
330
331
331
- final HttpClientBuilder configuredBuilder = contract .isPresent ()
332
- ? ((ApacheHttpClientBuilderConfigurator ) contract .get ()).configure (clientBuilder )
333
- : null ;
332
+ HttpClientBuilder configuredBuilder = clientBuilder ;
333
+ for (Object configurator : contracts ) {
334
+ configuredBuilder = ((ApacheHttpClientBuilderConfigurator ) configurator ).configure (configuredBuilder );
335
+ }
334
336
335
- this .client = configuredBuilder != null ? configuredBuilder . build () : clientBuilder .build ();
337
+ this .client = configuredBuilder .build ();
336
338
}
337
339
338
340
private HttpClientConnectionManager getConnectionManager (final Client client ,
@@ -515,7 +517,8 @@ public ClientResponse apply(final ClientRequest clientRequest) throws Processing
515
517
}
516
518
517
519
try {
518
- responseContext .setEntityStream (getInputStream (response ));
520
+ final ConnectionClosingMechanism closingMechanism = new ConnectionClosingMechanism (clientRequest , request );
521
+ responseContext .setEntityStream (getInputStream (response , closingMechanism ));
519
522
} catch (final IOException e ) {
520
523
LOGGER .log (Level .SEVERE , null , e );
521
524
}
@@ -655,8 +658,8 @@ private static Map<String, String> writeOutBoundHeaders(final ClientRequest clie
655
658
return stringHeaders ;
656
659
}
657
660
658
- private static InputStream getInputStream (final CloseableHttpResponse response ) throws IOException {
659
-
661
+ private static InputStream getInputStream (final CloseableHttpResponse response ,
662
+ final ConnectionClosingMechanism closingMechanism ) throws IOException {
660
663
final InputStream inputStream ;
661
664
662
665
if (response .getEntity () == null ) {
@@ -670,18 +673,57 @@ private static InputStream getInputStream(final CloseableHttpResponse response)
670
673
}
671
674
}
672
675
673
- return new FilterInputStream (inputStream ) {
674
- @ Override
675
- public void close () throws IOException {
676
- try {
677
- super .close ();
678
- } catch (IOException ex ) {
679
- // Ignore
680
- } finally {
681
- response .close ();
676
+ return closingMechanism .getEntityStream (inputStream , response );
677
+ }
678
+
679
+ /**
680
+ * The way the Apache CloseableHttpResponse is to be closed.
681
+ * See https://github.com/eclipse-ee4j/jersey/issues/4321
682
+ * {@link ApacheClientProperties#CONNECTION_CLOSING_STRATEGY}
683
+ */
684
+ private final class ConnectionClosingMechanism {
685
+ private ApacheConnectionClosingStrategy connectionClosingStrategy = null ;
686
+ private final ClientRequest clientRequest ;
687
+ private final HttpUriRequest apacheRequest ;
688
+
689
+ private ConnectionClosingMechanism (ClientRequest clientRequest , HttpUriRequest apacheRequest ) {
690
+ this .clientRequest = clientRequest ;
691
+ this .apacheRequest = apacheRequest ;
692
+ Object closingStrategyProperty = clientRequest
693
+ .resolveProperty (ApacheClientProperties .CONNECTION_CLOSING_STRATEGY , Object .class );
694
+ if (closingStrategyProperty != null ) {
695
+ if (ApacheConnectionClosingStrategy .class .isInstance (closingStrategyProperty )) {
696
+ connectionClosingStrategy = (ApacheConnectionClosingStrategy ) closingStrategyProperty ;
697
+ } else {
698
+ LOGGER .log (
699
+ Level .WARNING ,
700
+ LocalizationMessages .IGNORING_VALUE_OF_PROPERTY (
701
+ ApacheClientProperties .CONNECTION_CLOSING_STRATEGY ,
702
+ closingStrategyProperty ,
703
+ ApacheConnectionClosingStrategy .class .getName ())
704
+ );
682
705
}
683
706
}
684
- };
707
+
708
+ if (connectionClosingStrategy == null ) {
709
+ if (vi .getRelease ().compareTo ("4.5" ) > 0 ) {
710
+ connectionClosingStrategy = ApacheConnectionClosingStrategy .GracefulClosingStrategy .INSTANCE ;
711
+ } else {
712
+ connectionClosingStrategy = ApacheConnectionClosingStrategy .ImmediateClosingStrategy .INSTANCE ;
713
+ }
714
+ }
715
+ }
716
+
717
+ private InputStream getEntityStream (final InputStream inputStream ,
718
+ final CloseableHttpResponse response ) {
719
+ InputStream filterStream = new FilterInputStream (inputStream ) {
720
+ @ Override
721
+ public void close () throws IOException {
722
+ connectionClosingStrategy .close (clientRequest , apacheRequest , response , in );
723
+ }
724
+ };
725
+ return filterStream ;
726
+ }
685
727
}
686
728
687
729
private static class ConnectionFactory extends ManagedHttpClientConnectionFactory {
0 commit comments