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