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