View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.client5.http.impl.async;
29  
30  import org.apache.hc.client5.http.DnsResolver;
31  import org.apache.hc.client5.http.SchemePortResolver;
32  import org.apache.hc.client5.http.SystemDefaultDnsResolver;
33  import org.apache.hc.client5.http.config.TlsConfig;
34  import org.apache.hc.client5.http.impl.DefaultClientConnectionReuseStrategy;
35  import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
36  import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
37  import org.apache.hc.client5.http.impl.compat.ClassicToAsyncAdaptor;
38  import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
39  import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
40  import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
41  import org.apache.hc.core5.annotation.Experimental;
42  import org.apache.hc.core5.concurrent.DefaultThreadFactory;
43  import org.apache.hc.core5.function.Supplier;
44  import org.apache.hc.core5.http.config.CharCodingConfig;
45  import org.apache.hc.core5.http.config.Http1Config;
46  import org.apache.hc.core5.http.impl.routing.RequestRouter;
47  import org.apache.hc.core5.http.nio.AsyncPushConsumer;
48  import org.apache.hc.core5.http.nio.HandlerFactory;
49  import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
50  import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
51  import org.apache.hc.core5.http.protocol.HttpProcessor;
52  import org.apache.hc.core5.http.protocol.RequestUserAgent;
53  import org.apache.hc.core5.http2.HttpVersionPolicy;
54  import org.apache.hc.core5.http2.config.H2Config;
55  import org.apache.hc.core5.http2.protocol.H2RequestConnControl;
56  import org.apache.hc.core5.http2.protocol.H2RequestContent;
57  import org.apache.hc.core5.http2.protocol.H2RequestTargetHost;
58  import org.apache.hc.core5.reactor.IOEventHandlerFactory;
59  import org.apache.hc.core5.reactor.IOReactorConfig;
60  import org.apache.hc.core5.util.Timeout;
61  import org.apache.hc.core5.util.VersionInfo;
62  
63  /**
64   * Factory methods for {@link CloseableHttpAsyncClient} instances.
65   *
66   * @since 5.0
67   */
68  public final class HttpAsyncClients {
69  
70      private HttpAsyncClients() {
71          super();
72      }
73  
74      /**
75       * Creates builder object for construction of custom
76       * {@link CloseableHttpAsyncClient} instances.
77       */
78      public static HttpAsyncClientBuilder custom() {
79          return HttpAsyncClientBuilder.create();
80      }
81  
82      /**
83       * Creates {@link CloseableHttpAsyncClient} instance with default configuration.
84       */
85      public static CloseableHttpAsyncClient createDefault() {
86          return HttpAsyncClientBuilder.create().build();
87      }
88  
89      /**
90       * Creates {@link CloseableHttpAsyncClient} instance with default
91       * configuration and system properties.
92       */
93      public static CloseableHttpAsyncClient createSystem() {
94          return HttpAsyncClientBuilder.create().useSystemProperties().build();
95      }
96  
97      /**
98       * Creates builder object for construction of custom HTTP/2
99       * {@link CloseableHttpAsyncClient} instances optimized for HTTP/2 protocol
100      * and message multiplexing
101      */
102     public static H2AsyncClientBuilder customHttp2() {
103         return H2AsyncClientBuilder.create();
104     }
105 
106     /**
107      * Creates HTTP/2 {@link CloseableHttpAsyncClient} instance with default configuration
108      * optimized for HTTP/2 protocol and message multiplexing.
109      */
110     public static CloseableHttpAsyncClient createHttp2Default() {
111         return H2AsyncClientBuilder.create().build();
112     }
113 
114     /**
115      * Creates HTTP/2 {@link CloseableHttpAsyncClient} instance with default configuration and
116      * system properties optimized for HTTP/2 protocol and message multiplexing.
117      */
118     public static CloseableHttpAsyncClient createHttp2System() {
119         return H2AsyncClientBuilder.create().useSystemProperties().build();
120     }
121 
122     private static HttpProcessor createMinimalProtocolProcessor() {
123         return new DefaultHttpProcessor(
124                 new H2RequestTargetHost(),
125                 new H2RequestContent(),
126                 new H2RequestConnControl(),
127                 new RequestUserAgent(VersionInfo.getSoftwareInfo(
128                         "Apache-HttpAsyncClient", "org.apache.hc.client5", HttpAsyncClients.class)));
129     }
130 
131     private static MinimalHttpAsyncClient createMinimalHttpAsyncClientImpl(
132             final IOEventHandlerFactory eventHandlerFactory,
133             final AsyncPushConsumerRegistry pushConsumerRegistry,
134             final IOReactorConfig ioReactorConfig,
135             final AsyncClientConnectionManager connmgr,
136             final SchemePortResolver schemePortResolver,
137             final TlsConfig tlsConfig) {
138         return new MinimalHttpAsyncClient(
139                 eventHandlerFactory,
140                 pushConsumerRegistry,
141                 ioReactorConfig,
142                 new DefaultThreadFactory("httpclient-main", true),
143                 new DefaultThreadFactory("httpclient-dispatch", true),
144                 connmgr,
145                 schemePortResolver,
146                 tlsConfig);
147     }
148 
149     /**
150      * Creates {@link MinimalHttpAsyncClient} instance optimized for
151      * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
152      * functionality.
153      *
154      * @deprecated Use {@link #createMinimal(H2Config, Http1Config, IOReactorConfig, AsyncClientConnectionManager)}
155      */
156     @Deprecated
157     public static MinimalHttpAsyncClient createMinimal(
158             final HttpVersionPolicy versionPolicy,
159             final H2Config h2Config,
160             final Http1Config h1Config,
161             final IOReactorConfig ioReactorConfig,
162             final AsyncClientConnectionManager connmgr) {
163         final AsyncPushConsumerRegistry pushConsumerRegistry = new AsyncPushConsumerRegistry();
164         return createMinimalHttpAsyncClientImpl(
165                 new HttpAsyncClientProtocolNegotiationStarter(
166                         createMinimalProtocolProcessor(),
167                         (request, context) -> pushConsumerRegistry.get(request),
168                         h2Config,
169                         h1Config,
170                         CharCodingConfig.DEFAULT,
171                         DefaultClientConnectionReuseStrategy.INSTANCE,
172                         LoggingExceptionCallback.INSTANCE),
173                 pushConsumerRegistry,
174                 ioReactorConfig,
175                 connmgr,
176                 DefaultSchemePortResolver.INSTANCE,
177                 versionPolicy != null ? TlsConfig.custom().setVersionPolicy(versionPolicy).build() : null);
178     }
179 
180     /**
181      * Creates {@link MinimalHttpAsyncClient} instance optimized for
182      * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
183      * functionality.
184      *
185      * @since 5.2
186      */
187     public static MinimalHttpAsyncClient createMinimal(
188             final H2Config h2Config,
189             final Http1Config h1Config,
190             final IOReactorConfig ioReactorConfig,
191             final AsyncClientConnectionManager connmgr) {
192         final AsyncPushConsumerRegistry pushConsumerRegistry = new AsyncPushConsumerRegistry();
193         return createMinimalHttpAsyncClientImpl(
194                 new HttpAsyncClientProtocolNegotiationStarter(
195                         createMinimalProtocolProcessor(),
196                         (request, context) -> pushConsumerRegistry.get(request),
197                         h2Config,
198                         h1Config,
199                         CharCodingConfig.DEFAULT,
200                         DefaultClientConnectionReuseStrategy.INSTANCE,
201                         LoggingExceptionCallback.INSTANCE),
202                 pushConsumerRegistry,
203                 ioReactorConfig,
204                 connmgr,
205                 DefaultSchemePortResolver.INSTANCE,
206                 null);
207     }
208 
209     /**
210      * Creates {@link MinimalHttpAsyncClient} instance optimized for
211      * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
212      * functionality.
213      *
214      * @deprecated Use {@link #createMinimal(H2Config, Http1Config, IOReactorConfig)}
215      */
216     @Deprecated
217     public static MinimalHttpAsyncClient createMinimal(
218             final HttpVersionPolicy versionPolicy,
219             final H2Config h2Config,
220             final Http1Config h1Config,
221             final IOReactorConfig ioReactorConfig) {
222         return createMinimal(versionPolicy, h2Config, h1Config, ioReactorConfig,
223                 PoolingAsyncClientConnectionManagerBuilder.create().build());
224     }
225 
226     /**
227      * Creates {@link MinimalHttpAsyncClient} instance optimized for
228      * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
229      * functionality.
230      */
231     public static MinimalHttpAsyncClient createMinimal(
232             final H2Config h2Config,
233             final Http1Config h1Config,
234             final IOReactorConfig ioReactorConfig) {
235         return createMinimal(h2Config, h1Config, ioReactorConfig,
236                 PoolingAsyncClientConnectionManagerBuilder.create().build());
237     }
238 
239     /**
240      * Creates {@link MinimalHttpAsyncClient} instance optimized for
241      * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
242      * functionality.
243      */
244     public static MinimalHttpAsyncClient createMinimal(final H2Config h2Config, final Http1Config h1Config) {
245         return createMinimal(HttpVersionPolicy.NEGOTIATE, h2Config, h1Config, IOReactorConfig.DEFAULT);
246     }
247 
248     /**
249      * Creates {@link MinimalHttpAsyncClient} instance optimized for
250      * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
251      * functionality.
252      */
253     public static MinimalHttpAsyncClient createMinimal() {
254         return createMinimal(H2Config.DEFAULT, Http1Config.DEFAULT);
255     }
256 
257     /**
258      * Creates {@link MinimalHttpAsyncClient} instance optimized for
259      * HTTP/1.1 and HTTP/2 message transport without advanced HTTP protocol
260      * functionality.
261      */
262     public static MinimalHttpAsyncClient createMinimal(final AsyncClientConnectionManager connManager) {
263         return createMinimal(
264                 HttpVersionPolicy.NEGOTIATE,
265                 H2Config.DEFAULT,
266                 Http1Config.DEFAULT,
267                 IOReactorConfig.DEFAULT,
268                 connManager);
269     }
270 
271     private static MinimalH2AsyncClient createMinimalHttp2AsyncClientImpl(
272             final IOEventHandlerFactory eventHandlerFactory,
273             final AsyncPushConsumerRegistry pushConsumerRegistry,
274             final IOReactorConfig ioReactorConfig,
275             final DnsResolver dnsResolver,
276             final TlsStrategy tlsStrategy) {
277         return new MinimalH2AsyncClient(
278                 eventHandlerFactory,
279                 pushConsumerRegistry,
280                 ioReactorConfig,
281                 new DefaultThreadFactory("httpclient-main", true),
282                 new DefaultThreadFactory("httpclient-dispatch", true),
283                 dnsResolver,
284                 tlsStrategy);
285     }
286 
287     /**
288      * Creates {@link MinimalH2AsyncClient} instance optimized for HTTP/2 multiplexing message
289      * transport without advanced HTTP protocol functionality.
290      */
291     public static MinimalH2AsyncClient createHttp2Minimal(
292             final H2Config h2Config,
293             final IOReactorConfig ioReactorConfig,
294             final DnsResolver dnsResolver,
295             final TlsStrategy tlsStrategy) {
296         final AsyncPushConsumerRegistry pushConsumerRegistry = new AsyncPushConsumerRegistry();
297         return createMinimalHttp2AsyncClientImpl(
298                 new H2AsyncClientProtocolStarter(
299                         createMinimalProtocolProcessor(),
300                         (request, context) -> pushConsumerRegistry.get(request),
301                         h2Config,
302                         CharCodingConfig.DEFAULT,
303                         LoggingExceptionCallback.INSTANCE),
304                 pushConsumerRegistry,
305                 ioReactorConfig,
306                 dnsResolver,
307                 tlsStrategy);
308     }
309 
310     /**
311      * Creates {@link MinimalH2AsyncClient} instance optimized for HTTP/2 multiplexing message
312      * transport without advanced HTTP protocol functionality.
313      */
314     public static MinimalH2AsyncClient createHttp2Minimal(
315             final H2Config h2Config,
316             final IOReactorConfig ioReactorConfig,
317             final TlsStrategy tlsStrategy) {
318         return createHttp2Minimal(h2Config, ioReactorConfig, SystemDefaultDnsResolver.INSTANCE, tlsStrategy);
319     }
320 
321     /**
322      * Creates {@link MinimalH2AsyncClient} instance optimized for HTTP/2 multiplexing message
323      * transport without advanced HTTP protocol functionality.
324      */
325     public static MinimalH2AsyncClient createHttp2Minimal(
326             final H2Config h2Config,
327             final IOReactorConfig ioReactorConfig) {
328         return createHttp2Minimal(h2Config, ioReactorConfig, DefaultClientTlsStrategy.createDefault());
329     }
330 
331     /**
332      * Creates {@link MinimalH2AsyncClient} instance optimized for HTTP/2 multiplexing message
333      * transport without advanced HTTP protocol functionality.
334      */
335     public static MinimalH2AsyncClient createHttp2Minimal(final H2Config h2Config) {
336         return createHttp2Minimal(h2Config, IOReactorConfig.DEFAULT);
337     }
338 
339     /**
340      * Creates {@link MinimalH2AsyncClient} instance optimized for HTTP/2 multiplexing message
341      * transport without advanced HTTP protocol functionality.
342      */
343     public static MinimalH2AsyncClient createHttp2Minimal() {
344         return createHttp2Minimal(H2Config.DEFAULT);
345     }
346 
347     /**
348      * Creates {@link HandlerFactory} backed by a push {@link RequestRouter}.
349      *
350      * @since 5.4
351      */
352     public static HandlerFactory<AsyncPushConsumer> pushRouter(final RequestRouter<Supplier<AsyncPushConsumer>> requestRouter) {
353         return (request, context) -> {
354             final Supplier<AsyncPushConsumer> supplier = requestRouter.resolve(request, context);
355             return supplier != null ? supplier.get() : null;
356         };
357     }
358 
359     /**
360      * Creates an {@link CloseableHttpClient} facade backed by {@link CloseableHttpAsyncClient}
361      * built internally and acting as a compatibility bridge between the classic APIs based
362      * on the standard {@link java.io.InputStream} / {@link java.io.OutputStream} model
363      * and the underlying asynchronous message transport.
364      * <p>
365      * This feature is considered experimental and may be discontinued in the future.
366      *
367      * @param client async client
368      * @param operationTimeout maximum period an operation can block awaiting input / output.
369      *
370      * @since 5.5
371      */
372     @Experimental
373     public static CloseableHttpClient classic(final CloseableHttpAsyncClient client, final Timeout operationTimeout) {
374         client.start();
375         return new ClassicToAsyncAdaptor(client, operationTimeout);
376     }
377 
378 }