1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
73
74
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
105
106 public final AsyncServerBootstrap setCanonicalHostName(final String canonicalHostName) {
107 this.canonicalHostName = canonicalHostName;
108 return this;
109 }
110
111
112
113
114 public final AsyncServerBootstrap setIOReactorConfig(final IOReactorConfig ioReactorConfig) {
115 this.ioReactorConfig = ioReactorConfig;
116 return this;
117 }
118
119
120
121
122 public final AsyncServerBootstrap setHttp1Config(final Http1Config http1Config) {
123 this.http1Config = http1Config;
124 return this;
125 }
126
127
128
129
130 public final AsyncServerBootstrap setCharCodingConfig(final CharCodingConfig charCodingConfig) {
131 this.charCodingConfig = charCodingConfig;
132 return this;
133 }
134
135
136
137
138 public final AsyncServerBootstrap setHttpProcessor(final HttpProcessor httpProcessor) {
139 this.httpProcessor = httpProcessor;
140 return this;
141 }
142
143
144
145
146 public final AsyncServerBootstrap setConnectionReuseStrategy(final ConnectionReuseStrategy connStrategy) {
147 this.connStrategy = connStrategy;
148 return this;
149 }
150
151
152
153
154 public final AsyncServerBootstrap setTlsStrategy(final TlsStrategy tlsStrategy) {
155 this.tlsStrategy = tlsStrategy;
156 return this;
157 }
158
159
160
161
162 public final AsyncServerBootstrap setTlsHandshakeTimeout(final Timeout handshakeTimeout) {
163 this.handshakeTimeout = handshakeTimeout;
164 return this;
165 }
166
167
168
169
170 public final AsyncServerBootstrap setIOSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
171 this.ioSessionDecorator = ioSessionDecorator;
172 return this;
173 }
174
175
176
177
178 public final AsyncServerBootstrap setExceptionCallback(final Callback<Exception> exceptionCallback) {
179 this.exceptionCallback = exceptionCallback;
180 return this;
181 }
182
183
184
185
186 public final AsyncServerBootstrap setIOSessionListener(final IOSessionListener sessionListener) {
187 this.sessionListener = sessionListener;
188 return this;
189 }
190
191
192
193
194 public final AsyncServerBootstrap setLookupRegistry(final LookupRegistry<Supplier<AsyncServerExchangeHandler>> lookupRegistry) {
195 this.lookupRegistry = lookupRegistry;
196 return this;
197 }
198
199
200
201
202
203
204 public final AsyncServerBootstrap setStreamListener(final Http1StreamListener streamListener) {
205 this.streamListener = streamListener;
206 return this;
207 }
208
209
210
211
212
213
214
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
225
226
227
228
229
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
241
242
243
244
245
246 public final <T> AsyncServerBootstrap register(
247 final String uriPattern,
248 final AsyncServerRequestHandler<T> requestHandler) {
249 register(uriPattern, () -> new BasicServerExchangeHandler<>(requestHandler));
250 return this;
251 }
252
253
254
255
256
257
258
259
260
261 public final <T> AsyncServerBootstrap registerVirtual(
262 final String hostname,
263 final String uriPattern,
264 final AsyncServerRequestHandler<T> requestHandler) {
265 registerVirtual(hostname, uriPattern, () -> new BasicServerExchangeHandler<>(requestHandler));
266 return this;
267 }
268
269
270
271
272 public final AsyncServerBootstrap addFilterBefore(final String existing, final String name, final AsyncFilterHandler filterHandler) {
273 Args.notBlank(existing, "Existing");
274 Args.notBlank(name, "Name");
275 Args.notNull(filterHandler, "Filter handler");
276 filters.add(new FilterEntry<>(FilterEntry.Position.BEFORE, name, filterHandler, existing));
277 return this;
278 }
279
280
281
282
283 public final AsyncServerBootstrap addFilterAfter(final String existing, final String name, final AsyncFilterHandler filterHandler) {
284 Args.notBlank(existing, "Existing");
285 Args.notBlank(name, "Name");
286 Args.notNull(filterHandler, "Filter handler");
287 filters.add(new FilterEntry<>(FilterEntry.Position.AFTER, name, filterHandler, existing));
288 return this;
289 }
290
291
292
293
294 public final AsyncServerBootstrap replaceFilter(final String existing, final AsyncFilterHandler filterHandler) {
295 Args.notBlank(existing, "Existing");
296 Args.notNull(filterHandler, "Filter handler");
297 filters.add(new FilterEntry<>(FilterEntry.Position.REPLACE, existing, filterHandler, existing));
298 return this;
299 }
300
301
302
303
304 public final AsyncServerBootstrap addFilterFirst(final String name, final AsyncFilterHandler filterHandler) {
305 Args.notNull(name, "Name");
306 Args.notNull(filterHandler, "Filter handler");
307 filters.add(new FilterEntry<>(FilterEntry.Position.FIRST, name, filterHandler, null));
308 return this;
309 }
310
311
312
313
314 public final AsyncServerBootstrap addFilterLast(final String name, final AsyncFilterHandler filterHandler) {
315 Args.notNull(name, "Name");
316 Args.notNull(filterHandler, "Filter handler");
317 filters.add(new FilterEntry<>(FilterEntry.Position.LAST, name, filterHandler, null));
318 return this;
319 }
320
321 public HttpAsyncServer create() {
322 final RequestHandlerRegistry<Supplier<AsyncServerExchangeHandler>> registry = new RequestHandlerRegistry<>(
323 canonicalHostName != null ? canonicalHostName : InetAddressUtils.getCanonicalLocalHostName(),
324 () -> lookupRegistry != null ? lookupRegistry :
325 UriPatternType.newMatcher(UriPatternType.URI_PATTERN));
326 for (final HandlerEntry<Supplier<AsyncServerExchangeHandler>> entry: handlerList) {
327 registry.register(entry.hostname, entry.uriPattern, entry.handler);
328 }
329
330 final HandlerFactory<AsyncServerExchangeHandler> handlerFactory;
331 if (!filters.isEmpty()) {
332 final NamedElementChain<AsyncFilterHandler> filterChainDefinition = new NamedElementChain<>();
333 filterChainDefinition.addLast(
334 new TerminalAsyncServerFilter(new DefaultAsyncResponseExchangeHandlerFactory(registry)),
335 StandardFilter.MAIN_HANDLER.name());
336 filterChainDefinition.addFirst(
337 new AsyncServerExpectationFilter(),
338 StandardFilter.EXPECT_CONTINUE.name());
339
340 for (final FilterEntry<AsyncFilterHandler> entry: filters) {
341 switch (entry.position) {
342 case AFTER:
343 filterChainDefinition.addAfter(entry.existing, entry.filterHandler, entry.name);
344 break;
345 case BEFORE:
346 filterChainDefinition.addBefore(entry.existing, entry.filterHandler, entry.name);
347 break;
348 case REPLACE:
349 filterChainDefinition.replace(entry.existing, entry.filterHandler);
350 break;
351 case FIRST:
352 filterChainDefinition.addFirst(entry.filterHandler, entry.name);
353 break;
354 case LAST:
355
356
357 filterChainDefinition.addBefore(StandardFilter.MAIN_HANDLER.name(), entry.filterHandler, entry.name);
358 break;
359 }
360 }
361
362 NamedElementChain<AsyncFilterHandler>.Node current = filterChainDefinition.getLast();
363 AsyncServerFilterChainElement execChain = null;
364 while (current != null) {
365 execChain = new AsyncServerFilterChainElement(current.getValue(), execChain);
366 current = current.getPrevious();
367 }
368
369 handlerFactory = new AsyncServerFilterChainExchangeHandlerFactory(execChain, exceptionCallback);
370 } else {
371 handlerFactory = new DefaultAsyncResponseExchangeHandlerFactory(registry, handler -> new BasicAsyncServerExpectationDecorator(handler, exceptionCallback));
372 }
373
374 final ServerHttp1StreamDuplexerFactory streamHandlerFactory = new ServerHttp1StreamDuplexerFactory(
375 httpProcessor != null ? httpProcessor : HttpProcessors.server(),
376 handlerFactory,
377 http1Config != null ? http1Config : Http1Config.DEFAULT,
378 charCodingConfig != null ? charCodingConfig : CharCodingConfig.DEFAULT,
379 connStrategy != null ? connStrategy : DefaultConnectionReuseStrategy.INSTANCE,
380 DefaultHttpRequestParserFactory.INSTANCE,
381 DefaultHttpResponseWriterFactory.INSTANCE,
382 DefaultContentLengthStrategy.INSTANCE,
383 DefaultContentLengthStrategy.INSTANCE,
384 streamListener);
385 final IOEventHandlerFactory ioEventHandlerFactory = new ServerHttp1IOEventHandlerFactory(
386 streamHandlerFactory,
387 tlsStrategy,
388 handshakeTimeout);
389 return new HttpAsyncServer(ioEventHandlerFactory, ioReactorConfig, ioSessionDecorator, exceptionCallback,
390 sessionListener);
391 }
392
393 }