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  package org.apache.hc.core5.http2.impl.nio.bootstrap;
28  
29  import java.util.ArrayList;
30  import java.util.List;
31  
32  import org.apache.hc.core5.annotation.Experimental;
33  import org.apache.hc.core5.function.Callback;
34  import org.apache.hc.core5.function.Decorator;
35  import org.apache.hc.core5.function.Supplier;
36  import org.apache.hc.core5.http.HttpHost;
37  import org.apache.hc.core5.http.config.CharCodingConfig;
38  import org.apache.hc.core5.http.config.Http1Config;
39  import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
40  import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy;
41  import org.apache.hc.core5.http.impl.Http1StreamListener;
42  import org.apache.hc.core5.http.impl.HttpProcessors;
43  import org.apache.hc.core5.http.impl.nio.ClientHttp1StreamDuplexerFactory;
44  import org.apache.hc.core5.http.impl.nio.DefaultHttpRequestWriterFactory;
45  import org.apache.hc.core5.http.impl.nio.DefaultHttpResponseParserFactory;
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.ssl.TlsStrategy;
49  import org.apache.hc.core5.http.protocol.HttpProcessor;
50  import org.apache.hc.core5.http.protocol.UriPatternType;
51  import org.apache.hc.core5.http2.HttpVersionPolicy;
52  import org.apache.hc.core5.http2.config.H2Config;
53  import org.apache.hc.core5.http2.impl.H2Processors;
54  import org.apache.hc.core5.http2.impl.nio.ClientH2StreamMultiplexerFactory;
55  import org.apache.hc.core5.http2.impl.nio.ClientHttpProtocolNegotiationStarter;
56  import org.apache.hc.core5.http2.impl.nio.H2StreamListener;
57  import org.apache.hc.core5.http2.nio.support.DefaultAsyncPushConsumerFactory;
58  import org.apache.hc.core5.http2.ssl.H2ClientTlsStrategy;
59  import org.apache.hc.core5.pool.ConnPoolListener;
60  import org.apache.hc.core5.pool.DefaultDisposalCallback;
61  import org.apache.hc.core5.pool.LaxConnPool;
62  import org.apache.hc.core5.pool.ManagedConnPool;
63  import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
64  import org.apache.hc.core5.pool.PoolReusePolicy;
65  import org.apache.hc.core5.pool.StrictConnPool;
66  import org.apache.hc.core5.reactor.IOEventHandlerFactory;
67  import org.apache.hc.core5.reactor.IOReactorConfig;
68  import org.apache.hc.core5.reactor.IOSession;
69  import org.apache.hc.core5.reactor.IOSessionListener;
70  import org.apache.hc.core5.util.Args;
71  import org.apache.hc.core5.util.TimeValue;
72  import org.apache.hc.core5.util.Timeout;
73  
74  /**
75   * {@link H2AsyncRequester} bootstrap.
76   *
77   * @since 5.0
78   */
79  public class H2RequesterBootstrap {
80  
81      private final List<RequestRouter.Entry<Supplier<AsyncPushConsumer>>> routeEntries;
82      private UriPatternType uriPatternType;
83      private IOReactorConfig ioReactorConfig;
84      private HttpProcessor httpProcessor;
85      private CharCodingConfig charCodingConfig;
86      private HttpVersionPolicy versionPolicy;
87      private H2Config h2Config;
88      private Http1Config http1Config;
89      private int defaultMaxPerRoute;
90      private int maxTotal;
91      private TimeValue timeToLive;
92      private PoolReusePolicy poolReusePolicy;
93      private PoolConcurrencyPolicy poolConcurrencyPolicy;
94      private TlsStrategy tlsStrategy;
95      private Timeout handshakeTimeout;
96      private Decorator<IOSession> ioSessionDecorator;
97      private Callback<Exception> exceptionCallback;
98      private IOSessionListener sessionListener;
99      private H2StreamListener streamListener;
100     private Http1StreamListener http1StreamListener;
101     private ConnPoolListener<HttpHost> connPoolListener;
102 
103     private H2RequesterBootstrap() {
104         this.routeEntries = new ArrayList<>();
105     }
106 
107     public static H2RequesterBootstrap bootstrap() {
108         return new H2RequesterBootstrap();
109     }
110 
111     /**
112      * Sets I/O reactor configuration.
113      */
114     public final H2RequesterBootstrap setIOReactorConfig(final IOReactorConfig ioReactorConfig) {
115         this.ioReactorConfig = ioReactorConfig;
116         return this;
117     }
118 
119     /**
120      * Assigns {@link HttpProcessor} instance.
121      */
122     public final H2RequesterBootstrap setHttpProcessor(final HttpProcessor httpProcessor) {
123         this.httpProcessor = httpProcessor;
124         return this;
125     }
126 
127     /**
128      * Sets HTTP protocol version policy
129      */
130     public final H2RequesterBootstrap setVersionPolicy(final HttpVersionPolicy versionPolicy) {
131         this.versionPolicy = versionPolicy;
132         return this;
133     }
134 
135     /**
136      * Sets HTTP/2 protocol parameters
137      */
138     public final H2RequesterBootstrap setH2Config(final H2Config h2Config) {
139         this.h2Config = h2Config;
140         return this;
141     }
142 
143     /**
144      * Sets HTTP/1.1 protocol parameters
145      */
146     public final H2RequesterBootstrap setHttp1Config(final Http1Config http1Config) {
147         this.http1Config = http1Config;
148         return this;
149     }
150 
151     /**
152      * Sets message char coding.
153      */
154     public final H2RequesterBootstrap setCharCodingConfig(final CharCodingConfig charCodingConfig) {
155         this.charCodingConfig = charCodingConfig;
156         return this;
157     }
158 
159     public final H2RequesterBootstrap setDefaultMaxPerRoute(final int defaultMaxPerRoute) {
160         this.defaultMaxPerRoute = defaultMaxPerRoute;
161         return this;
162     }
163 
164     public final H2RequesterBootstrap setMaxTotal(final int maxTotal) {
165         this.maxTotal = maxTotal;
166         return this;
167     }
168 
169     public final H2RequesterBootstrap setTimeToLive(final TimeValue timeToLive) {
170         this.timeToLive = timeToLive;
171         return this;
172     }
173 
174     /**
175      * Assigns {@link PoolReusePolicy} instance.
176      */
177     public final H2RequesterBootstrap setPoolReusePolicy(final PoolReusePolicy poolReusePolicy) {
178         this.poolReusePolicy = poolReusePolicy;
179         return this;
180     }
181 
182     /**
183      * Assigns {@link PoolConcurrencyPolicy} instance.
184      */
185     @Experimental
186     public final H2RequesterBootstrap setPoolConcurrencyPolicy(final PoolConcurrencyPolicy poolConcurrencyPolicy) {
187         this.poolConcurrencyPolicy = poolConcurrencyPolicy;
188         return this;
189     }
190 
191     /**
192      * Assigns {@link TlsStrategy} instance.
193      */
194     public final H2RequesterBootstrap setTlsStrategy(final TlsStrategy tlsStrategy) {
195         this.tlsStrategy = tlsStrategy;
196         return this;
197     }
198 
199     public final H2RequesterBootstrap setHandshakeTimeout(final Timeout handshakeTimeout) {
200         this.handshakeTimeout = handshakeTimeout;
201         return this;
202     }
203 
204     /**
205      * Assigns {@link IOSession} {@link Decorator} instance.
206      */
207     public final H2RequesterBootstrap setIOSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
208         this.ioSessionDecorator = ioSessionDecorator;
209         return this;
210     }
211 
212     /**
213      * Assigns {@link Exception} {@link Callback} instance.
214      */
215     public final H2RequesterBootstrap setExceptionCallback(final Callback<Exception> exceptionCallback) {
216         this.exceptionCallback = exceptionCallback;
217         return this;
218     }
219 
220     /**
221      * Assigns {@link IOSessionListener} instance.
222      */
223     public final H2RequesterBootstrap setIOSessionListener(final IOSessionListener sessionListener) {
224         this.sessionListener = sessionListener;
225         return this;
226     }
227 
228     /**
229      * Assigns {@link H2StreamListener} instance.
230      */
231     public final H2RequesterBootstrap setStreamListener(final H2StreamListener streamListener) {
232         this.streamListener = streamListener;
233         return this;
234     }
235 
236     /**
237      * Assigns {@link Http1StreamListener} instance.
238      */
239     public final H2RequesterBootstrap setStreamListener(final Http1StreamListener http1StreamListener) {
240         this.http1StreamListener = http1StreamListener;
241         return this;
242     }
243 
244     /**
245      * Assigns {@link ConnPoolListener} instance.
246      */
247     public final H2RequesterBootstrap setConnPoolListener(final ConnPoolListener<HttpHost> connPoolListener) {
248         this.connPoolListener = connPoolListener;
249         return this;
250     }
251 
252     /**
253      * Assigns {@link UriPatternType} for handler registration.
254      */
255     public final H2RequesterBootstrap setUriPatternType(final UriPatternType uriPatternType) {
256         this.uriPatternType = uriPatternType;
257         return this;
258     }
259 
260     /**
261      * Registers the given {@link AsyncPushConsumer} {@link Supplier} as a default handler for URIs
262      * matching the given pattern.
263      *
264      * @param uriPattern the pattern to register the handler for.
265      * @param supplier the handler supplier.
266      */
267     public final H2RequesterBootstrap register(final String uriPattern, final Supplier<AsyncPushConsumer> supplier) {
268         Args.notBlank(uriPattern, "URI pattern");
269         Args.notNull(supplier, "Push consumer supplier");
270         routeEntries.add(new RequestRouter.Entry<>(uriPattern, supplier));
271         return this;
272     }
273 
274     /**
275      * Registers the given {@link AsyncPushConsumer} {@link Supplier} as a handler for URIs
276      * matching the given host and the pattern.
277      *
278      * @param hostname the host name
279      * @param uriPattern the pattern to register the handler for.
280      * @param supplier the handler supplier.
281      *
282      * @since 5.3
283      */
284     public final H2RequesterBootstrap register(final String hostname, final String uriPattern, final Supplier<AsyncPushConsumer> supplier) {
285         Args.notBlank(hostname, "Hostname");
286         Args.notBlank(uriPattern, "URI pattern");
287         Args.notNull(supplier, "Push consumer supplier");
288         routeEntries.add(new RequestRouter.Entry<>(hostname, uriPattern, supplier));
289         return this;
290     }
291 
292     /**
293      * @deprecated Use {@link #register(String, String, Supplier)}.
294      */
295     @Deprecated
296     public final H2RequesterBootstrap registerVirtual(final String hostname, final String uriPattern, final Supplier<AsyncPushConsumer> supplier) {
297         return register(hostname, uriPattern, supplier);
298     }
299 
300     public H2AsyncRequester create() {
301         final ManagedConnPool<HttpHost, IOSession> connPool;
302         switch (poolConcurrencyPolicy != null ? poolConcurrencyPolicy : PoolConcurrencyPolicy.STRICT) {
303             case LAX:
304                 connPool = new LaxConnPool<>(
305                         defaultMaxPerRoute > 0 ? defaultMaxPerRoute : 20,
306                         timeToLive,
307                         poolReusePolicy,
308                         new DefaultDisposalCallback<>(),
309                         connPoolListener);
310                 break;
311             case STRICT:
312             default:
313                 connPool = new StrictConnPool<>(
314                         defaultMaxPerRoute > 0 ? defaultMaxPerRoute : 20,
315                         maxTotal > 0 ? maxTotal : 50,
316                         timeToLive,
317                         poolReusePolicy,
318                         new DefaultDisposalCallback<>(),
319                         connPoolListener);
320                 break;
321         }
322         final RequestRouter<Supplier<AsyncPushConsumer>> requestRouter = RequestRouter.create(
323                 null, uriPatternType, routeEntries, RequestRouter.LOCAL_AUTHORITY_RESOLVER, null);
324 
325         final ClientH2StreamMultiplexerFactory http2StreamHandlerFactory = new ClientH2StreamMultiplexerFactory(
326                 httpProcessor != null ? httpProcessor : H2Processors.client(),
327                 new DefaultAsyncPushConsumerFactory(requestRouter),
328                 h2Config != null ? h2Config : H2Config.DEFAULT,
329                 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
330                 streamListener);
331 
332         final TlsStrategy actualTlsStrategy = tlsStrategy != null ? tlsStrategy : new H2ClientTlsStrategy();
333 
334         final ClientHttp1StreamDuplexerFactory http1StreamHandlerFactory = new ClientHttp1StreamDuplexerFactory(
335                 httpProcessor != null ? httpProcessor : HttpProcessors.client(),
336                 http1Config != null ? http1Config : Http1Config.DEFAULT,
337                 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
338                 DefaultConnectionReuseStrategy.INSTANCE,
339                 new DefaultHttpResponseParserFactory(http1Config),
340                 DefaultHttpRequestWriterFactory.INSTANCE,
341                 DefaultContentLengthStrategy.INSTANCE,
342                 DefaultContentLengthStrategy.INSTANCE,
343                 http1StreamListener);
344 
345         final IOEventHandlerFactory ioEventHandlerFactory = new ClientHttpProtocolNegotiationStarter(
346                 http1StreamHandlerFactory,
347                 http2StreamHandlerFactory,
348                 versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE,
349                 actualTlsStrategy,
350                 handshakeTimeout);
351 
352         return new H2AsyncRequester(
353                 versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE,
354                 ioReactorConfig,
355                 ioEventHandlerFactory,
356                 ioSessionDecorator,
357                 exceptionCallback,
358                 sessionListener,
359                 connPool,
360                 actualTlsStrategy,
361                 handshakeTimeout);
362     }
363 
364 }