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.http.impl.bootstrap;
28  
29  import java.util.ArrayList;
30  import java.util.List;
31  
32  import org.apache.hc.core5.function.Callback;
33  import org.apache.hc.core5.function.Decorator;
34  import org.apache.hc.core5.function.Supplier;
35  import org.apache.hc.core5.http.ConnectionReuseStrategy;
36  import org.apache.hc.core5.http.config.CharCodingConfig;
37  import org.apache.hc.core5.http.config.Http1Config;
38  import org.apache.hc.core5.http.config.NamedElementChain;
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.DefaultHttpRequestParserFactory;
44  import org.apache.hc.core5.http.impl.nio.DefaultHttpResponseWriterFactory;
45  import org.apache.hc.core5.http.impl.nio.ServerHttp1IOEventHandlerFactory;
46  import org.apache.hc.core5.http.impl.nio.ServerHttp1StreamDuplexerFactory;
47  import org.apache.hc.core5.http.nio.AsyncFilterHandler;
48  import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
49  import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
50  import org.apache.hc.core5.http.nio.HandlerFactory;
51  import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
52  import org.apache.hc.core5.http.nio.support.AsyncServerExpectationFilter;
53  import org.apache.hc.core5.http.nio.support.AsyncServerFilterChainElement;
54  import org.apache.hc.core5.http.nio.support.AsyncServerFilterChainExchangeHandlerFactory;
55  import org.apache.hc.core5.http.nio.support.BasicAsyncServerExpectationDecorator;
56  import org.apache.hc.core5.http.nio.support.BasicServerExchangeHandler;
57  import org.apache.hc.core5.http.nio.support.DefaultAsyncResponseExchangeHandlerFactory;
58  import org.apache.hc.core5.http.nio.support.TerminalAsyncServerFilter;
59  import org.apache.hc.core5.http.protocol.HttpProcessor;
60  import org.apache.hc.core5.http.protocol.LookupRegistry;
61  import org.apache.hc.core5.http.protocol.RequestHandlerRegistry;
62  import org.apache.hc.core5.http.protocol.UriPatternType;
63  import org.apache.hc.core5.net.InetAddressUtils;
64  import org.apache.hc.core5.reactor.IOEventHandlerFactory;
65  import org.apache.hc.core5.reactor.IOReactorConfig;
66  import org.apache.hc.core5.reactor.IOSession;
67  import org.apache.hc.core5.reactor.IOSessionListener;
68  import org.apache.hc.core5.util.Args;
69  import org.apache.hc.core5.util.Timeout;
70  
71  /**
72   * {@link HttpAsyncServer} bootstrap.
73   *
74   * @since 5.0
75   */
76  public class AsyncServerBootstrap {
77  
78      private final List<HandlerEntry<Supplier<AsyncServerExchangeHandler>>> handlerList;
79      private final List<FilterEntry<AsyncFilterHandler>> filters;
80      private String canonicalHostName;
81      private LookupRegistry<Supplier<AsyncServerExchangeHandler>> lookupRegistry;
82      private IOReactorConfig ioReactorConfig;
83      private Http1Config http1Config;
84      private CharCodingConfig charCodingConfig;
85      private HttpProcessor httpProcessor;
86      private ConnectionReuseStrategy connStrategy;
87      private TlsStrategy tlsStrategy;
88      private Timeout handshakeTimeout;
89      private Decorator<IOSession> ioSessionDecorator;
90      private Callback<Exception> exceptionCallback;
91      private IOSessionListener sessionListener;
92      private Http1StreamListener streamListener;
93  
94      private AsyncServerBootstrap() {
95          this.handlerList = new ArrayList<>();
96          this.filters = new ArrayList<>();
97      }
98  
99      public static AsyncServerBootstrap bootstrap() {
100         return new AsyncServerBootstrap();
101     }
102 
103     /**
104      * Sets canonical name (fully qualified domain name) of the server.
105      */
106     public final AsyncServerBootstrap setCanonicalHostName(final String canonicalHostName) {
107         this.canonicalHostName = canonicalHostName;
108         return this;
109     }
110 
111     /**
112      * Sets I/O reactor configuration.
113      */
114     public final AsyncServerBootstrap setIOReactorConfig(final IOReactorConfig ioReactorConfig) {
115         this.ioReactorConfig = ioReactorConfig;
116         return this;
117     }
118 
119     /**
120      * Sets HTTP/1.1 protocol parameters.
121      */
122     public final AsyncServerBootstrap setHttp1Config(final Http1Config http1Config) {
123         this.http1Config = http1Config;
124         return this;
125     }
126 
127     /**
128      * Sets connection configuration.
129      */
130     public final AsyncServerBootstrap setCharCodingConfig(final CharCodingConfig charCodingConfig) {
131         this.charCodingConfig = charCodingConfig;
132         return this;
133     }
134 
135     /**
136      * Assigns {@link org.apache.hc.core5.http.protocol.HttpProcessor} instance.
137      */
138     public final AsyncServerBootstrap setHttpProcessor(final HttpProcessor httpProcessor) {
139         this.httpProcessor = httpProcessor;
140         return this;
141     }
142 
143     /**
144      * Assigns {@link org.apache.hc.core5.http.ConnectionReuseStrategy} instance.
145      */
146     public final AsyncServerBootstrap setConnectionReuseStrategy(final ConnectionReuseStrategy connStrategy) {
147         this.connStrategy = connStrategy;
148         return this;
149     }
150 
151     /**
152      * Assigns {@link TlsStrategy} instance.
153      */
154     public final AsyncServerBootstrap setTlsStrategy(final TlsStrategy tlsStrategy) {
155         this.tlsStrategy = tlsStrategy;
156         return this;
157     }
158 
159     /**
160      * Assigns TLS handshake {@link Timeout}.
161      */
162     public final AsyncServerBootstrap setTlsHandshakeTimeout(final Timeout handshakeTimeout) {
163         this.handshakeTimeout = handshakeTimeout;
164         return this;
165     }
166 
167     /**
168      * Assigns {@link IOSession} {@link Decorator} instance.
169      */
170     public final AsyncServerBootstrap setIOSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
171         this.ioSessionDecorator = ioSessionDecorator;
172         return this;
173     }
174 
175     /**
176      * Assigns {@link Exception} {@link Callback} instance.
177      */
178     public final AsyncServerBootstrap setExceptionCallback(final Callback<Exception> exceptionCallback) {
179         this.exceptionCallback = exceptionCallback;
180         return this;
181     }
182 
183     /**
184      * Assigns {@link IOSessionListener} instance.
185      */
186     public final AsyncServerBootstrap setIOSessionListener(final IOSessionListener sessionListener) {
187         this.sessionListener = sessionListener;
188         return this;
189     }
190 
191     /**
192      * Assigns {@link LookupRegistry} instance.
193      */
194     public final AsyncServerBootstrap setLookupRegistry(final LookupRegistry<Supplier<AsyncServerExchangeHandler>> lookupRegistry) {
195         this.lookupRegistry = lookupRegistry;
196         return this;
197     }
198 
199     /**
200      * Assigns {@link Http1StreamListener} instance.
201      *
202      * @since 5.0
203      */
204     public final AsyncServerBootstrap setStreamListener(final Http1StreamListener streamListener) {
205         this.streamListener = streamListener;
206         return this;
207     }
208 
209     /**
210      * Registers the given {@link AsyncServerExchangeHandler} {@link Supplier} as a default handler for URIs
211      * matching the given pattern.
212      *
213      * @param uriPattern the pattern to register the handler for.
214      * @param supplier the handler supplier.
215      */
216     public final AsyncServerBootstrap register(final String uriPattern, final Supplier<AsyncServerExchangeHandler> supplier) {
217         Args.notBlank(uriPattern, "URI pattern");
218         Args.notNull(supplier, "Supplier");
219         handlerList.add(new HandlerEntry<>(null, uriPattern, supplier));
220         return this;
221     }
222 
223     /**
224      * Registers the given {@link AsyncServerExchangeHandler} {@link Supplier} as a handler for URIs
225      * matching the given host and the pattern.
226      *
227      * @param hostname the host name
228      * @param uriPattern the pattern to register the handler for.
229      * @param supplier the handler supplier.
230      */
231     public final AsyncServerBootstrap registerVirtual(final String hostname, final String uriPattern, final Supplier<AsyncServerExchangeHandler> supplier) {
232         Args.notBlank(hostname, "Hostname");
233         Args.notBlank(uriPattern, "URI pattern");
234         Args.notNull(supplier, "Supplier");
235         handlerList.add(new HandlerEntry<>(hostname, uriPattern, supplier));
236         return this;
237     }
238 
239     /**
240      * Registers the given {@link AsyncServerRequestHandler} as a default handler for URIs
241      * matching the given pattern.
242      *
243      * @param uriPattern the pattern to register the handler for.
244      * @param requestHandler the handler.
245      */
246     public final <T> AsyncServerBootstrap register(
247             final String uriPattern,
248             final AsyncServerRequestHandler<T> requestHandler) {
249         register(uriPattern, new Supplier<AsyncServerExchangeHandler>() {
250 
251             @Override
252             public AsyncServerExchangeHandler get() {
253                 return new BasicServerExchangeHandler<>(requestHandler);
254             }
255 
256         });
257         return this;
258     }
259 
260     /**
261      * Registers the given {@link AsyncServerRequestHandler} as a handler for URIs
262      * matching the given host and the pattern.
263      *
264      * @param hostname the host name
265      * @param uriPattern the pattern to register the handler for.
266      * @param requestHandler the handler.
267      */
268     public final <T> AsyncServerBootstrap registerVirtual(
269             final String hostname,
270             final String uriPattern,
271             final AsyncServerRequestHandler<T> requestHandler) {
272         registerVirtual(hostname, uriPattern, new Supplier<AsyncServerExchangeHandler>() {
273 
274             @Override
275             public AsyncServerExchangeHandler get() {
276                 return new BasicServerExchangeHandler<>(requestHandler);
277             }
278 
279         });
280         return this;
281     }
282 
283     /**
284      * Adds the filter before the filter with the given name.
285      */
286     public final AsyncServerBootstrap addFilterBefore(final String existing, final String name, final AsyncFilterHandler filterHandler) {
287         Args.notBlank(existing, "Existing");
288         Args.notBlank(name, "Name");
289         Args.notNull(filterHandler, "Filter handler");
290         filters.add(new FilterEntry<>(FilterEntry.Postion.BEFORE, name, filterHandler, existing));
291         return this;
292     }
293 
294     /**
295      * Adds the filter after the filter with the given name.
296      */
297     public final AsyncServerBootstrap addFilterAfter(final String existing, final String name, final AsyncFilterHandler filterHandler) {
298         Args.notBlank(existing, "Existing");
299         Args.notBlank(name, "Name");
300         Args.notNull(filterHandler, "Filter handler");
301         filters.add(new FilterEntry<>(FilterEntry.Postion.AFTER, name, filterHandler, existing));
302         return this;
303     }
304 
305     /**
306      * Replace an existing filter with the given name with new filter.
307      */
308     public final AsyncServerBootstrap replaceFilter(final String existing, final AsyncFilterHandler filterHandler) {
309         Args.notBlank(existing, "Existing");
310         Args.notNull(filterHandler, "Filter handler");
311         filters.add(new FilterEntry<>(FilterEntry.Postion.REPLACE, existing, filterHandler, existing));
312         return this;
313     }
314 
315     /**
316      * Add an filter to the head of the processing list.
317      */
318     public final AsyncServerBootstrap addFilterFirst(final String name, final AsyncFilterHandler filterHandler) {
319         Args.notNull(name, "Name");
320         Args.notNull(filterHandler, "Filter handler");
321         filters.add(new FilterEntry<>(FilterEntry.Postion.FIRST, name, filterHandler, null));
322         return this;
323     }
324 
325     /**
326      * Add an filter to the tail of the processing list.
327      */
328     public final AsyncServerBootstrap addFilterLast(final String name, final AsyncFilterHandler filterHandler) {
329         Args.notNull(name, "Name");
330         Args.notNull(filterHandler, "Filter handler");
331         filters.add(new FilterEntry<>(FilterEntry.Postion.LAST, name, filterHandler, null));
332         return this;
333     }
334 
335     public HttpAsyncServer create() {
336         final RequestHandlerRegistry<Supplier<AsyncServerExchangeHandler>> registry = new RequestHandlerRegistry<>(
337                 canonicalHostName != null ? canonicalHostName : InetAddressUtils.getCanonicalLocalHostName(),
338                 new Supplier<LookupRegistry<Supplier<AsyncServerExchangeHandler>>>() {
339 
340                     @Override
341                     public LookupRegistry<Supplier<AsyncServerExchangeHandler>> get() {
342                         return lookupRegistry != null ? lookupRegistry :
343                                 UriPatternType.<Supplier<AsyncServerExchangeHandler>>newMatcher(UriPatternType.URI_PATTERN);
344                     }
345 
346                 });
347         for (final HandlerEntry<Supplier<AsyncServerExchangeHandler>> entry: handlerList) {
348             registry.register(entry.hostname, entry.uriPattern, entry.handler);
349         }
350 
351         final HandlerFactory<AsyncServerExchangeHandler> handlerFactory;
352         if (!filters.isEmpty()) {
353             final NamedElementChain<AsyncFilterHandler> filterChainDefinition = new NamedElementChain<>();
354             filterChainDefinition.addLast(
355                     new TerminalAsyncServerFilter(new DefaultAsyncResponseExchangeHandlerFactory(registry)),
356                     StandardFilter.MAIN_HANDLER.name());
357             filterChainDefinition.addFirst(
358                     new AsyncServerExpectationFilter(),
359                     StandardFilter.EXPECT_CONTINUE.name());
360 
361             for (final FilterEntry<AsyncFilterHandler> entry: filters) {
362                 switch (entry.postion) {
363                     case AFTER:
364                         filterChainDefinition.addAfter(entry.existing, entry.filterHandler, entry.name);
365                         break;
366                     case BEFORE:
367                         filterChainDefinition.addBefore(entry.existing, entry.filterHandler, entry.name);
368                         break;
369                     case REPLACE:
370                         filterChainDefinition.replace(entry.existing, entry.filterHandler);
371                         break;
372                     case FIRST:
373                         filterChainDefinition.addFirst(entry.filterHandler, entry.name);
374                         break;
375                     case LAST:
376                         // Don't add last, after TerminalAsyncServerFilter, as that does not delegate to the chain
377                         // Instead, add the filter just before it, making it effectively the last filter
378                         filterChainDefinition.addBefore(StandardFilter.MAIN_HANDLER.name(), entry.filterHandler, entry.name);
379                         break;
380                 }
381             }
382 
383             NamedElementChain<AsyncFilterHandler>.Node current = filterChainDefinition.getLast();
384             AsyncServerFilterChainElement execChain = null;
385             while (current != null) {
386                 execChain = new AsyncServerFilterChainElement(current.getValue(), execChain);
387                 current = current.getPrevious();
388             }
389 
390             handlerFactory = new AsyncServerFilterChainExchangeHandlerFactory(execChain, exceptionCallback);
391         } else {
392             handlerFactory = new DefaultAsyncResponseExchangeHandlerFactory(registry, new Decorator<AsyncServerExchangeHandler>() {
393 
394                 @Override
395                 public AsyncServerExchangeHandlerxchangeHandler.html#AsyncServerExchangeHandler">AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler handler) {
396                     return new BasicAsyncServerExpectationDecorator(handler, exceptionCallback);
397                 }
398 
399             });
400         }
401 
402         final ServerHttp1StreamDuplexerFactoryFactory.html#ServerHttp1StreamDuplexerFactory">ServerHttp1StreamDuplexerFactory streamHandlerFactory = new ServerHttp1StreamDuplexerFactory(
403                 httpProcessor != null ? httpProcessor : HttpProcessors.server(),
404                 handlerFactory,
405                 http1Config != null ? http1Config : Http1Config.DEFAULT,
406                 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
407                 connStrategy != null ? connStrategy : DefaultConnectionReuseStrategy.INSTANCE,
408                 DefaultHttpRequestParserFactory.INSTANCE,
409                 DefaultHttpResponseWriterFactory.INSTANCE,
410                 DefaultContentLengthStrategy.INSTANCE,
411                 DefaultContentLengthStrategy.INSTANCE,
412                 streamListener);
413         final IOEventHandlerFactory ioEventHandlerFactory = new ServerHttp1IOEventHandlerFactory(
414                 streamHandlerFactory,
415                 tlsStrategy,
416                 handshakeTimeout);
417         return new HttpAsyncServer(ioEventHandlerFactory, ioReactorConfig, ioSessionDecorator, exceptionCallback,
418                 sessionListener);
419     }
420 
421 }