001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.reactive.function.server;
018
019import java.util.List;
020import java.util.Map;
021import java.util.function.BiFunction;
022import java.util.function.Consumer;
023import java.util.function.Function;
024import java.util.function.Predicate;
025import java.util.function.Supplier;
026
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import reactor.core.publisher.Flux;
030import reactor.core.publisher.Mono;
031
032import org.springframework.core.io.Resource;
033import org.springframework.http.codec.HttpMessageWriter;
034import org.springframework.http.server.reactive.HttpHandler;
035import org.springframework.util.Assert;
036import org.springframework.web.reactive.result.view.ViewResolver;
037import org.springframework.web.server.ServerWebExchange;
038import org.springframework.web.server.WebHandler;
039import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
040
041/**
042 * <strong>Central entry point to Spring's functional web framework.</strong>
043 * Exposes routing functionality, such as to {@linkplain #route() create} a
044 * {@code RouterFunction} using a discoverable builder-style API, to
045 * {@linkplain #route(RequestPredicate, HandlerFunction) create} a {@code RouterFunction}
046 * given a {@code RequestPredicate} and {@code HandlerFunction}, and to do further
047 * {@linkplain #nest(RequestPredicate, RouterFunction) subrouting} on an existing routing
048 * function.
049 *
050 * <p>Additionally, this class can {@linkplain #toHttpHandler(RouterFunction) transform} a
051 * {@code RouterFunction} into an {@code HttpHandler}, which can be run in Servlet 3.1+,
052 * Reactor, or Undertow.
053 *
054 * @author Arjen Poutsma
055 * @since 5.0
056 */
057public abstract class RouterFunctions {
058
059        private static final Log logger = LogFactory.getLog(RouterFunctions.class);
060
061        /**
062         * Name of the {@link ServerWebExchange} attribute that contains the {@link ServerRequest}.
063         */
064        public static final String REQUEST_ATTRIBUTE = RouterFunctions.class.getName() + ".request";
065
066        /**
067         * Name of the {@link ServerWebExchange} attribute that contains the URI
068         * templates map, mapping variable names to values.
069         */
070        public static final String URI_TEMPLATE_VARIABLES_ATTRIBUTE =
071                        RouterFunctions.class.getName() + ".uriTemplateVariables";
072
073        /**
074         * Name of the {@link ServerWebExchange#getAttributes() attribute} that
075         * contains the matching pattern, as a {@link org.springframework.web.util.pattern.PathPattern}.
076         */
077        public static final String MATCHING_PATTERN_ATTRIBUTE =
078                        RouterFunctions.class.getName() + ".matchingPattern";
079
080
081
082
083        /**
084         * Offers a discoverable way to create router functions through a builder-style interface.
085         * @return a router function builder
086         * @since 5.1
087         */
088        public static Builder route() {
089                return new RouterFunctionBuilder();
090        }
091
092        /**
093         * Route to the given handler function if the given request predicate applies.
094         * <p>For instance, the following example routes GET requests for "/user" to the
095         * {@code listUsers} method in {@code userController}:
096         * <pre class="code">
097         * RouterFunction&lt;ServerResponse&gt; route =
098         *     RouterFunctions.route(RequestPredicates.GET("/user"), userController::listUsers);
099         * </pre>
100         * @param predicate the predicate to test
101         * @param handlerFunction the handler function to route to if the predicate applies
102         * @param <T> the type of response returned by the handler function
103         * @return a router function that routes to {@code handlerFunction} if
104         * {@code predicate} evaluates to {@code true}
105         * @see RequestPredicates
106         */
107        public static <T extends ServerResponse> RouterFunction<T> route(
108                        RequestPredicate predicate, HandlerFunction<T> handlerFunction) {
109
110                return new DefaultRouterFunction<>(predicate, handlerFunction);
111        }
112
113        /**
114         * Route to the given router function if the given request predicate applies. This method can be
115         * used to create <strong>nested routes</strong>, where a group of routes share a common path
116         * (prefix), header, or other request predicate.
117         * <p>For instance, the following example first creates a composed route that resolves to
118         * {@code listUsers} for a GET, and {@code createUser} for a POST. This composed route then gets
119         * nested with a "/user" path predicate, so that GET requests for "/user" will list users,
120         * and POST request for "/user" will create a new user.
121         * <pre class="code">
122         * RouterFunction&lt;ServerResponse&gt; userRoutes =
123         *   RouterFunctions.route(RequestPredicates.method(HttpMethod.GET), this::listUsers)
124         *     .andRoute(RequestPredicates.method(HttpMethod.POST), this::createUser);
125         * RouterFunction&lt;ServerResponse&gt; nestedRoute =
126         *   RouterFunctions.nest(RequestPredicates.path("/user"), userRoutes);
127         * </pre>
128         * @param predicate the predicate to test
129         * @param routerFunction the nested router function to delegate to if the predicate applies
130         * @param <T> the type of response returned by the handler function
131         * @return a router function that routes to {@code routerFunction} if
132         * {@code predicate} evaluates to {@code true}
133         * @see RequestPredicates
134         */
135        public static <T extends ServerResponse> RouterFunction<T> nest(
136                        RequestPredicate predicate, RouterFunction<T> routerFunction) {
137
138                return new DefaultNestedRouterFunction<>(predicate, routerFunction);
139        }
140
141        /**
142         * Route requests that match the given pattern to resources relative to the given root location.
143         * For instance
144         * <pre class="code">
145         * Resource location = new FileSystemResource("public-resources/");
146         * RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resources("/resources/**", location);
147     * </pre>
148         * @param pattern the pattern to match
149         * @param location the location directory relative to which resources should be resolved
150         * @return a router function that routes to resources
151         * @see #resourceLookupFunction(String, Resource)
152         */
153        public static RouterFunction<ServerResponse> resources(String pattern, Resource location) {
154                return resources(resourceLookupFunction(pattern, location));
155        }
156
157        /**
158         * Returns the resource lookup function used by {@link #resources(String, Resource)}.
159         * The returned function can be {@linkplain Function#andThen(Function) composed} on, for
160         * instance to return a default resource when the lookup function does not match:
161         * <pre class="code">
162         * Mono&lt;Resource&gt; defaultResource = Mono.just(new ClassPathResource("index.html"));
163         * Function&lt;ServerRequest, Mono&lt;Resource&gt;&gt; lookupFunction =
164         *   RouterFunctions.resourceLookupFunction("/resources/**", new FileSystemResource("public-resources/"))
165         *     .andThen(resourceMono -&gt; resourceMono.switchIfEmpty(defaultResource));
166         * RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resources(lookupFunction);
167     * </pre>
168         * @param pattern the pattern to match
169         * @param location the location directory relative to which resources should be resolved
170         * @return the default resource lookup function for the given parameters.
171         */
172        public static Function<ServerRequest, Mono<Resource>> resourceLookupFunction(String pattern, Resource location) {
173                return new PathResourceLookupFunction(pattern, location);
174        }
175
176        /**
177         * Route to resources using the provided lookup function. If the lookup function provides a
178         * {@link Resource} for the given request, it will be it will be exposed using a
179         * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests.
180         * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest}
181         * @return a router function that routes to resources
182         */
183        public static RouterFunction<ServerResponse> resources(Function<ServerRequest, Mono<Resource>> lookupFunction) {
184                return new ResourcesRouterFunction(lookupFunction);
185        }
186
187        /**
188         * Convert the given {@linkplain RouterFunction router function} into a {@link HttpHandler}.
189         * This conversion uses {@linkplain HandlerStrategies#builder() default strategies}.
190         * <p>The returned handler can be adapted to run in
191         * <ul>
192         * <li>Servlet 3.1+ using the
193         * {@link org.springframework.http.server.reactive.ServletHttpHandlerAdapter},</li>
194         * <li>Reactor using the
195         * {@link org.springframework.http.server.reactive.ReactorHttpHandlerAdapter},</li>
196         * <li>Undertow using the
197         * {@link org.springframework.http.server.reactive.UndertowHttpHandlerAdapter}.</li>
198         * </ul>
199         * <p>Note that {@code HttpWebHandlerAdapter} also implements {@link WebHandler}, allowing
200         * for additional filter and exception handler registration through
201         * {@link WebHttpHandlerBuilder}.
202         * @param routerFunction the router function to convert
203         * @return an http handler that handles HTTP request using the given router function
204         */
205        public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction) {
206                return toHttpHandler(routerFunction, HandlerStrategies.withDefaults());
207        }
208
209        /**
210         * Convert the given {@linkplain RouterFunction router function} into a {@link HttpHandler},
211         * using the given strategies.
212         * <p>The returned {@code HttpHandler} can be adapted to run in
213         * <ul>
214         * <li>Servlet 3.1+ using the
215         * {@link org.springframework.http.server.reactive.ServletHttpHandlerAdapter},</li>
216         * <li>Reactor using the
217         * {@link org.springframework.http.server.reactive.ReactorHttpHandlerAdapter},</li>
218         * <li>Undertow using the
219         * {@link org.springframework.http.server.reactive.UndertowHttpHandlerAdapter}.</li>
220         * </ul>
221         * @param routerFunction the router function to convert
222         * @param strategies the strategies to use
223         * @return an http handler that handles HTTP request using the given router function
224         */
225        public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction, HandlerStrategies strategies) {
226                WebHandler webHandler = toWebHandler(routerFunction, strategies);
227                return WebHttpHandlerBuilder.webHandler(webHandler)
228                                .filters(filters -> filters.addAll(strategies.webFilters()))
229                                .exceptionHandlers(handlers -> handlers.addAll(strategies.exceptionHandlers()))
230                                .localeContextResolver(strategies.localeContextResolver())
231                                .build();
232        }
233
234        /**
235         * Convert the given {@linkplain RouterFunction router function} into a {@link WebHandler}.
236         * This conversion uses {@linkplain HandlerStrategies#builder() default strategies}.
237         * @param routerFunction the router function to convert
238         * @return a web handler that handles web request using the given router function
239         */
240        public static WebHandler toWebHandler(RouterFunction<?> routerFunction) {
241                return toWebHandler(routerFunction, HandlerStrategies.withDefaults());
242        }
243
244        /**
245         * Convert the given {@linkplain RouterFunction router function} into a {@link WebHandler},
246         * using the given strategies.
247         * @param routerFunction the router function to convert
248         * @param strategies the strategies to use
249         * @return a web handler that handles web request using the given router function
250         */
251        public static WebHandler toWebHandler(RouterFunction<?> routerFunction, HandlerStrategies strategies) {
252                Assert.notNull(routerFunction, "RouterFunction must not be null");
253                Assert.notNull(strategies, "HandlerStrategies must not be null");
254
255                return new RouterFunctionWebHandler(strategies, routerFunction);
256        }
257
258        /**
259         * Represents a discoverable builder for router functions.
260         * Obtained via {@link RouterFunctions#route()}.
261         * @since 5.1
262         */
263        public interface Builder {
264
265                /**
266                 * Adds a route to the given handler function that handles all HTTP {@code GET} requests
267                 * that match the given pattern.
268                 * @param pattern the pattern to match to
269                 * @param handlerFunction the handler function to handle all {@code GET} requests that
270                 * match {@code pattern}
271                 * @return this builder
272                 */
273                Builder GET(String pattern, HandlerFunction<ServerResponse> handlerFunction);
274
275                /**
276                 * Adds a route to the given handler function that handles all HTTP {@code GET} requests
277                 * that match the given pattern and predicate.
278                 * <p>For instance, the following example routes GET requests for "/user" that accept JSON
279                 * to the {@code listUsers} method in {@code userController}:
280                 * <pre class="code">
281                 * RouterFunction&lt;ServerResponse&gt; route =
282                 *   RouterFunctions.route()
283                 *     .GET("/user", RequestPredicates.accept(MediaType.APPLICATION_JSON), userController::listUsers)
284                 *     .build();
285                 * </pre>
286                 * @param pattern the pattern to match to
287                 * @param predicate additional predicate to match
288                 * @param handlerFunction the handler function to handle all {@code GET} requests that
289                 * match {@code pattern}
290                 * @return this builder
291                 * @see RequestPredicates
292                 */
293                Builder GET(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
294
295                /**
296                 * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests
297                 * that match the given pattern.
298                 * @param pattern the pattern to match to
299                 * @param handlerFunction the handler function to handle all {@code HEAD} requests that
300                 * match {@code pattern}
301                 * @return this builder
302                 */
303                Builder HEAD(String pattern, HandlerFunction<ServerResponse> handlerFunction);
304
305                /**
306                 * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests
307                 * that match the given pattern and predicate.
308                 * @param pattern the pattern to match to
309                 * @param predicate additional predicate to match
310                 * @param handlerFunction the handler function to handle all {@code HEAD} requests that
311                 * match {@code pattern}
312                 * @return this builder
313                 */
314                Builder HEAD(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
315
316                /**
317                 * Adds a route to the given handler function that handles all HTTP {@code POST} requests
318                 * that match the given pattern.
319                 * @param pattern the pattern to match to
320                 * @param handlerFunction the handler function to handle all {@code POST} requests that
321                 * match {@code pattern}
322                 * @return this builder
323                 */
324                Builder POST(String pattern, HandlerFunction<ServerResponse> handlerFunction);
325
326                /**
327                 * Adds a route to the given handler function that handles all HTTP {@code POST} requests
328                 * that match the given pattern and predicate.
329                 * <p>For instance, the following example routes POST requests for "/user" that contain JSON
330                 * to the {@code addUser} method in {@code userController}:
331                 * <pre class="code">
332                 * RouterFunction&lt;ServerResponse&gt; route =
333                 *   RouterFunctions.route()
334                 *     .POST("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::addUser)
335                 *     .build();
336                 * </pre>
337                 * @param pattern the pattern to match to
338                 * @param predicate additional predicate to match
339                 * @param handlerFunction the handler function to handle all {@code POST} requests that
340                 * match {@code pattern}
341                 * @return this builder
342                 */
343                Builder POST(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
344
345                /**
346                 * Adds a route to the given handler function that handles all HTTP {@code PUT} requests
347                 * that match the given pattern.
348                 * @param pattern the pattern to match to
349                 * @param handlerFunction the handler function to handle all {@code PUT} requests that
350                 * match {@code pattern}
351                 * @return this builder
352                 */
353                Builder PUT(String pattern, HandlerFunction<ServerResponse> handlerFunction);
354
355                /**
356                 * Adds a route to the given handler function that handles all HTTP {@code PUT} requests
357                 * that match the given pattern and predicate.
358                 * <p>For instance, the following example routes PUT requests for "/user" that contain JSON
359                 * to the {@code editUser} method in {@code userController}:
360                 * <pre class="code">
361                 * RouterFunction&lt;ServerResponse&gt; route =
362                 *   RouterFunctions.route()
363                 *     .PUT("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
364                 *     .build();
365                 * </pre>
366                 * @param pattern the pattern to match to
367                 * @param predicate additional predicate to match
368                 * @param handlerFunction the handler function to handle all {@code PUT} requests that
369                 * match {@code pattern}
370                 * @return this builder
371                 */
372                Builder PUT(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
373
374                /**
375                 * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests
376                 * that match the given pattern.
377                 * @param pattern the pattern to match to
378                 * @param handlerFunction the handler function to handle all {@code PATCH} requests that
379                 * match {@code pattern}
380                 * @return this builder
381                 */
382                Builder PATCH(String pattern, HandlerFunction<ServerResponse> handlerFunction);
383
384                /**
385                 * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests
386                 * that match the given pattern and predicate.
387                 * <p>For instance, the following example routes PATCH requests for "/user" that contain JSON
388                 * to the {@code editUser} method in {@code userController}:
389                 * <pre class="code">
390                 * RouterFunction&lt;ServerResponse&gt; route =
391                 *   RouterFunctions.route()
392                 *     .PATCH("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
393                 *     .build();
394                 * </pre>
395                 * @param pattern the pattern to match to
396                 * @param predicate additional predicate to match
397                 * @param handlerFunction the handler function to handle all {@code PATCH} requests that
398                 * match {@code pattern}
399                 * @return this builder
400                 */
401                Builder PATCH(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
402
403                /**
404                 * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests
405                 * that match the given pattern.
406                 * @param pattern the pattern to match to
407                 * @param handlerFunction the handler function to handle all {@code DELETE} requests that
408                 * match {@code pattern}
409                 * @return this builder
410                 */
411                Builder DELETE(String pattern, HandlerFunction<ServerResponse> handlerFunction);
412
413                /**
414                 * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests
415                 * that match the given pattern and predicate.
416                 * @param pattern the pattern to match to
417                 * @param predicate additional predicate to match
418                 * @param handlerFunction the handler function to handle all {@code DELETE} requests that
419                 * match {@code pattern}
420                 * @return this builder
421                 */
422                Builder DELETE(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
423
424                /**
425                 * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests
426                 * that match the given pattern.
427                 * @param pattern the pattern to match to
428                 * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that
429                 * match {@code pattern}
430                 * @return this builder
431                 */
432                Builder OPTIONS(String pattern, HandlerFunction<ServerResponse> handlerFunction);
433
434                /**
435                 * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests
436                 * that match the given pattern and predicate.
437                 * @param pattern the pattern to match to
438                 * @param predicate additional predicate to match
439                 * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that
440                 * match {@code pattern}
441                 * @return this builder
442                 */
443                Builder OPTIONS(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
444
445                /**
446                 * Adds a route to the given handler function that handles all requests that match the
447                 * given predicate.
448                 * @param predicate the request predicate to match
449                 * @param handlerFunction the handler function to handle all requests that match the predicate
450                 * @return this builder
451                 * @since 5.2
452                 * @see RequestPredicates
453                 */
454                Builder route(RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
455
456                /**
457                 * Adds the given route to this builder. Can be used to merge externally defined router
458                 * functions into this builder, or can be combined with
459                 * {@link RouterFunctions#route(RequestPredicate, HandlerFunction)}
460                 * to allow for more flexible predicate matching.
461                 * <p>For instance, the following example adds the router function returned from
462                 * {@code OrderController.routerFunction()}.
463                 * to the {@code changeUser} method in {@code userController}:
464                 * <pre class="code">
465                 * RouterFunction&lt;ServerResponse&gt; route =
466                 *   RouterFunctions.route()
467                 *     .GET("/users", userController::listUsers)
468                 *     .add(orderController.routerFunction());
469                 *     .build();
470                 * </pre>
471                 * @param routerFunction the router function to be added
472                 * @return this builder
473                 * @see RequestPredicates
474                 */
475                Builder add(RouterFunction<ServerResponse> routerFunction);
476
477                /**
478                 * Route requests that match the given pattern to resources relative to the given root location.
479                 * For instance
480                 * <pre class="code">
481                 * Resource location = new FileSystemResource("public-resources/");
482                 * RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resources("/resources/**", location);
483             * </pre>
484                 * @param pattern the pattern to match
485                 * @param location the location directory relative to which resources should be resolved
486                 * @return this builder
487                 */
488                Builder resources(String pattern, Resource location);
489
490                /**
491                 * Route to resources using the provided lookup function. If the lookup function provides a
492                 * {@link Resource} for the given request, it will be it will be exposed using a
493                 * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests.
494                 * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest}
495                 * @return this builder
496                 */
497                Builder resources(Function<ServerRequest, Mono<Resource>> lookupFunction);
498
499                /**
500                 * Route to the supplied router function if the given request predicate applies. This method
501                 * can be used to create <strong>nested routes</strong>, where a group of routes share a
502                 * common path (prefix), header, or other request predicate.
503                 * <p>For instance, the following example creates a nested route with a "/user" path
504                 * predicate, so that GET requests for "/user" will list users,
505                 * and POST request for "/user" will create a new user.
506                 * <pre class="code">
507                 * RouterFunction&lt;ServerResponse&gt; nestedRoute =
508                 *   RouterFunctions.route()
509                 *     .nest(RequestPredicates.path("/user"), () ->
510                 *       RouterFunctions.route()
511                 *         .GET(this::listUsers)
512                 *         .POST(this::createUser)
513                 *         .build())
514                 *     .build();
515                 * </pre>
516                 * @param predicate the predicate to test
517                 * @param routerFunctionSupplier supplier for the nested router function to delegate to if
518                 * the predicate applies
519                 * @return this builder
520                 * @see RequestPredicates
521                 */
522                Builder nest(RequestPredicate predicate, Supplier<RouterFunction<ServerResponse>> routerFunctionSupplier);
523
524                /**
525                 * Route to a built router function if the given request predicate applies.
526                 * This method can be used to create <strong>nested routes</strong>, where a group of routes
527                 * share a common path (prefix), header, or other request predicate.
528                 * <p>For instance, the following example creates a nested route with a "/user" path
529                 * predicate, so that GET requests for "/user" will list users,
530                 * and POST request for "/user" will create a new user.
531                 * <pre class="code">
532                 * RouterFunction&lt;ServerResponse&gt; nestedRoute =
533                 *   RouterFunctions.route()
534                 *     .nest(RequestPredicates.path("/user"), builder ->
535                 *       builder.GET(this::listUsers)
536                 *              .POST(this::createUser))
537                 *     .build();
538                 * </pre>
539                 * @param predicate the predicate to test
540                 * @param builderConsumer consumer for a {@code Builder} that provides the nested router
541                 * function
542                 * @return this builder
543                 * @see RequestPredicates
544                 */
545                Builder nest(RequestPredicate predicate, Consumer<Builder> builderConsumer);
546
547                /**
548                 * Route to the supplied router function if the given path prefix pattern applies. This method
549                 * can be used to create <strong>nested routes</strong>, where a group of routes share a
550                 * common path prefix. Specifically, this method can be used to merge externally defined
551                 * router functions under a path prefix.
552                 * <p>For instance, the following example creates a nested route with a "/user" path
553                 * predicate that delegates to the router function defined in {@code userController},
554                 * and with a "/order" path that delegates to {@code orderController}.
555                 * <pre class="code">
556                 * RouterFunction&lt;ServerResponse&gt; nestedRoute =
557                 *   RouterFunctions.route()
558                 *     .path("/user", userController::routerFunction)
559                 *     .path("/order", orderController::routerFunction)
560                 *     .build();
561                 * </pre>
562                 * @param pattern the pattern to match to
563                 * @param routerFunctionSupplier supplier for the nested router function to delegate to if
564                 * the pattern matches
565                 * @return this builder
566                 */
567                Builder path(String pattern, Supplier<RouterFunction<ServerResponse>> routerFunctionSupplier);
568
569                /**
570                 * Route to a built router function if the given path prefix pattern applies.
571                 * This method can be used to create <strong>nested routes</strong>, where a group of routes
572                 * share a common path prefix.
573                 * <p>For instance, the following example creates a nested route with a "/user" path
574                 * predicate, so that GET requests for "/user" will list users,
575                 * and POST request for "/user" will create a new user.
576                 * <pre class="code">
577                 * RouterFunction&lt;ServerResponse&gt; nestedRoute =
578                 *   RouterFunctions.route()
579                 *     .path("/user", builder ->
580                 *       builder.GET(this::listUsers)
581                 *              .POST(this::createUser))
582                 *     .build();
583                 * </pre>
584                 * @param pattern the pattern to match to
585                 * @param builderConsumer consumer for a {@code Builder} that provides the nested router
586                 * function
587                 * @return this builder
588                 */
589                Builder path(String pattern, Consumer<Builder> builderConsumer);
590
591                /**
592                 * Filters all routes created by this builder with the given filter function. Filter
593                 * functions are typically used to address cross-cutting concerns, such as logging,
594                 * security, etc.
595                 * <p>For instance, the following example creates a filter that returns a 401 Unauthorized
596                 * response if the request does not contain the necessary authentication headers.
597                 * <pre class="code">
598                 * RouterFunction&lt;ServerResponse&gt; filteredRoute =
599                 *   RouterFunctions.route()
600                 *     .GET("/user", this::listUsers)
601                 *     .filter((request, next) -> {
602                 *       // check for authentication headers
603                 *       if (isAuthenticated(request)) {
604                 *         return next.handle(request);
605                 *       }
606                 *       else {
607                 *         return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
608                 *       }
609                 *     })
610                 *     .build();
611                 * </pre>
612                 * @param filterFunction the function to filter all routes built by this builder
613                 * @return this builder
614                 */
615                Builder filter(HandlerFilterFunction<ServerResponse, ServerResponse> filterFunction);
616
617                /**
618                 * Filter the request object for all routes created by this builder with the given request
619                 * processing function. Filters are typically used to address cross-cutting concerns, such
620                 * as logging, security, etc.
621                 * <p>For instance, the following example creates a filter that logs the request before
622                 * the handler function executes.
623                 * <pre class="code">
624                 * RouterFunction&lt;ServerResponse&gt; filteredRoute =
625                 *   RouterFunctions.route()
626                 *     .GET("/user", this::listUsers)
627                 *     .before(request -> {
628                 *       log(request);
629                 *       return request;
630                 *     })
631                 *     .build();
632                 * </pre>
633                 * @param requestProcessor a function that transforms the request
634                 * @return this builder
635                 */
636                Builder before(Function<ServerRequest, ServerRequest> requestProcessor);
637
638                /**
639                 * Filter the response object for all routes created by this builder with the given response
640                 * processing function. Filters are typically used to address cross-cutting concerns, such
641                 * as logging, security, etc.
642                 * <p>For instance, the following example creates a filter that logs the response after
643                 * the handler function executes.
644                 * <pre class="code">
645                 * RouterFunction&lt;ServerResponse&gt; filteredRoute =
646                 *   RouterFunctions.route()
647                 *     .GET("/user", this::listUsers)
648                 *     .after((request, response) -> {
649                 *       log(response);
650                 *       return response;
651                 *     })
652                 *     .build();
653                 * </pre>
654                 * @param responseProcessor a function that transforms the response
655                 * @return this builder
656                 */
657                Builder after(BiFunction<ServerRequest, ServerResponse, ServerResponse> responseProcessor);
658
659                /**
660                 * Filters all exceptions that match the predicate by applying the given response provider
661                 * function.
662                 * <p>For instance, the following example creates a filter that returns a 500 response
663                 * status when an {@code IllegalStateException} occurs.
664                 * <pre class="code">
665                 * RouterFunction&lt;ServerResponse&gt; filteredRoute =
666                 *   RouterFunctions.route()
667                 *     .GET("/user", this::listUsers)
668                 *     .onError(e -> e instanceof IllegalStateException,
669                 *       (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
670                 *     .build();
671                 * </pre>
672                 * @param predicate the type of exception to filter
673                 * @param responseProvider a function that creates a response
674                 * @return this builder
675                 */
676                Builder onError(Predicate<? super Throwable> predicate,
677                                BiFunction<? super  Throwable, ServerRequest, Mono<ServerResponse>> responseProvider);
678
679                /**
680                 * Filters all exceptions of the given type by applying the given response provider
681                 * function.
682                 * <p>For instance, the following example creates a filter that returns a 500 response
683                 * status when an {@code IllegalStateException} occurs.
684                 * <pre class="code">
685                 * RouterFunction&lt;ServerResponse&gt; filteredRoute =
686                 *   RouterFunctions.route()
687                 *     .GET("/user", this::listUsers)
688                 *     .onError(IllegalStateException.class,
689                 *       (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
690                 *     .build();
691                 * </pre>
692                 * @param exceptionType the type of exception to filter
693                 * @param responseProvider a function that creates a response
694                 * @return this builder
695                 */
696                <T extends Throwable> Builder onError(Class<T> exceptionType,
697                                BiFunction<? super T, ServerRequest, Mono<ServerResponse>> responseProvider);
698
699                /**
700                 * Builds the {@code RouterFunction}. All created routes are
701                 * {@linkplain RouterFunction#and(RouterFunction) composed} with one another, and filters
702                 * (if any) are applied to the result.
703                 * @return the built router function
704                 */
705                RouterFunction<ServerResponse> build();
706        }
707
708
709        /**
710         * Receives notifications from the logical structure of router functions.
711         */
712        public interface Visitor {
713
714                /**
715                 * Receive notification of the beginning of a nested router function.
716                 * @param predicate the predicate that applies to the nested router functions
717                 * @see RouterFunctions#nest(RequestPredicate, RouterFunction)
718                 */
719                void startNested(RequestPredicate predicate);
720
721                /**
722                 * Receive notification of the end of a nested router function.
723                 * @param predicate the predicate that applies to the nested router functions
724                 * @see RouterFunctions#nest(RequestPredicate, RouterFunction)
725                 */
726                void endNested(RequestPredicate predicate);
727
728                /**
729                 * Receive notification of a standard predicated route to a handler function.
730                 * @param predicate the predicate that applies to the handler function
731                 * @param handlerFunction the handler function.
732                 * @see RouterFunctions#route(RequestPredicate, HandlerFunction)
733                 */
734                void route(RequestPredicate predicate, HandlerFunction<?> handlerFunction);
735
736                /**
737                 * Receive notification of a resource router function.
738                 * @param lookupFunction the lookup function for the resources
739                 * @see RouterFunctions#resources(Function)
740                 */
741                void resources(Function<ServerRequest, Mono<Resource>> lookupFunction);
742
743                /**
744                 * Receive notification of an unknown router function. This method is called for router
745                 * functions that were not created via the various {@link RouterFunctions} methods.
746                 * @param routerFunction the router function
747                 */
748                void unknown(RouterFunction<?> routerFunction);
749        }
750
751
752        abstract static class AbstractRouterFunction<T extends ServerResponse> implements RouterFunction<T> {
753
754                @Override
755                public String toString() {
756                        ToStringVisitor visitor = new ToStringVisitor();
757                        accept(visitor);
758                        return visitor.toString();
759                }
760        }
761
762
763        /**
764         * A composed routing function that first invokes one function, and then invokes the
765         * another function (of the same response type {@code T}) if this route had
766         * {@linkplain Mono#empty() no result}.
767         * @param <T> the server response type
768         */
769        static final class SameComposedRouterFunction<T extends ServerResponse> extends AbstractRouterFunction<T> {
770
771                private final RouterFunction<T> first;
772
773                private final RouterFunction<T> second;
774
775                public SameComposedRouterFunction(RouterFunction<T> first, RouterFunction<T> second) {
776                        this.first = first;
777                        this.second = second;
778                }
779
780                @Override
781                public Mono<HandlerFunction<T>> route(ServerRequest request) {
782                        return Flux.concat(this.first.route(request), Mono.defer(() -> this.second.route(request)))
783                                        .next();
784                }
785
786                @Override
787                public void accept(Visitor visitor) {
788                        this.first.accept(visitor);
789                        this.second.accept(visitor);
790                }
791        }
792
793
794        /**
795         * A composed routing function that first invokes one function, and then invokes
796         * another function (of a different response type) if this route had
797         * {@linkplain Mono#empty() no result}.
798         */
799        static final class DifferentComposedRouterFunction extends AbstractRouterFunction<ServerResponse> {
800
801                private final RouterFunction<?> first;
802
803                private final RouterFunction<?> second;
804
805                public DifferentComposedRouterFunction(RouterFunction<?> first, RouterFunction<?> second) {
806                        this.first = first;
807                        this.second = second;
808                }
809
810                @Override
811                public Mono<HandlerFunction<ServerResponse>> route(ServerRequest request) {
812                        return Flux.concat(this.first.route(request), Mono.defer(() -> this.second.route(request)))
813                                        .next()
814                                        .map(this::cast);
815                }
816
817                @SuppressWarnings("unchecked")
818                private <T extends ServerResponse> HandlerFunction<T> cast(HandlerFunction<?> handlerFunction) {
819                        return (HandlerFunction<T>) handlerFunction;
820                }
821
822                @Override
823                public void accept(Visitor visitor) {
824                        this.first.accept(visitor);
825                        this.second.accept(visitor);
826                }
827        }
828
829
830        /**
831         * Filter the specified {@linkplain HandlerFunction handler functions} with the given
832         * {@linkplain HandlerFilterFunction filter function}.
833         * @param <T> the type of the {@linkplain HandlerFunction handler function} to filter
834         * @param <S> the type of the response of the function
835         */
836        static final class FilteredRouterFunction<T extends ServerResponse, S extends ServerResponse>
837                        implements RouterFunction<S> {
838
839                private final RouterFunction<T> routerFunction;
840
841                private final HandlerFilterFunction<T, S> filterFunction;
842
843                public FilteredRouterFunction(
844                                RouterFunction<T> routerFunction,
845                                HandlerFilterFunction<T, S> filterFunction) {
846                        this.routerFunction = routerFunction;
847                        this.filterFunction = filterFunction;
848                }
849
850                @Override
851                public Mono<HandlerFunction<S>> route(ServerRequest request) {
852                        return this.routerFunction.route(request).map(this.filterFunction::apply);
853                }
854
855                @Override
856                public void accept(Visitor visitor) {
857                        this.routerFunction.accept(visitor);
858                }
859
860                @Override
861                public String toString() {
862                        return this.routerFunction.toString();
863                }
864        }
865
866
867        private static final class DefaultRouterFunction<T extends ServerResponse> extends AbstractRouterFunction<T> {
868
869                private final RequestPredicate predicate;
870
871                private final HandlerFunction<T> handlerFunction;
872
873                public DefaultRouterFunction(RequestPredicate predicate, HandlerFunction<T> handlerFunction) {
874                        Assert.notNull(predicate, "Predicate must not be null");
875                        Assert.notNull(handlerFunction, "HandlerFunction must not be null");
876                        this.predicate = predicate;
877                        this.handlerFunction = handlerFunction;
878                }
879
880                @Override
881                public Mono<HandlerFunction<T>> route(ServerRequest request) {
882                        if (this.predicate.test(request)) {
883                                if (logger.isTraceEnabled()) {
884                                        String logPrefix = request.exchange().getLogPrefix();
885                                        logger.trace(logPrefix + String.format("Matched %s", this.predicate));
886                                }
887                                return Mono.just(this.handlerFunction);
888                        }
889                        else {
890                                return Mono.empty();
891                        }
892                }
893
894                @Override
895                public void accept(Visitor visitor) {
896                        visitor.route(this.predicate, this.handlerFunction);
897                }
898        }
899
900
901        private static final class DefaultNestedRouterFunction<T extends ServerResponse> extends AbstractRouterFunction<T> {
902
903                private final RequestPredicate predicate;
904
905                private final RouterFunction<T> routerFunction;
906
907                public DefaultNestedRouterFunction(RequestPredicate predicate, RouterFunction<T> routerFunction) {
908                        Assert.notNull(predicate, "Predicate must not be null");
909                        Assert.notNull(routerFunction, "RouterFunction must not be null");
910                        this.predicate = predicate;
911                        this.routerFunction = routerFunction;
912                }
913
914                @Override
915                public Mono<HandlerFunction<T>> route(ServerRequest serverRequest) {
916                        return this.predicate.nest(serverRequest)
917                                        .map(nestedRequest -> {
918                                                                if (logger.isTraceEnabled()) {
919                                                                        String logPrefix = serverRequest.exchange().getLogPrefix();
920                                                                        logger.trace(logPrefix + String.format("Matched nested %s", this.predicate));
921                                                                }
922                                                                return this.routerFunction.route(nestedRequest)
923                                                                                .doOnNext(match -> {
924                                                                                        if (nestedRequest != serverRequest) {
925                                                                                                serverRequest.attributes().clear();
926                                                                                                serverRequest.attributes()
927                                                                                                                .putAll(nestedRequest.attributes());
928                                                                                        }
929                                                                                });
930                                                        }
931                                        ).orElseGet(Mono::empty);
932                }
933
934
935                @Override
936                public void accept(Visitor visitor) {
937                        visitor.startNested(this.predicate);
938                        this.routerFunction.accept(visitor);
939                        visitor.endNested(this.predicate);
940                }
941        }
942
943
944        private static class ResourcesRouterFunction extends  AbstractRouterFunction<ServerResponse> {
945
946                private final Function<ServerRequest, Mono<Resource>> lookupFunction;
947
948                public ResourcesRouterFunction(Function<ServerRequest, Mono<Resource>> lookupFunction) {
949                        Assert.notNull(lookupFunction, "Function must not be null");
950                        this.lookupFunction = lookupFunction;
951                }
952
953                @Override
954                public Mono<HandlerFunction<ServerResponse>> route(ServerRequest request) {
955                        return this.lookupFunction.apply(request).map(ResourceHandlerFunction::new);
956                }
957
958                @Override
959                public void accept(Visitor visitor) {
960                        visitor.resources(this.lookupFunction);
961                }
962        }
963
964
965        private static class HandlerStrategiesResponseContext implements ServerResponse.Context {
966
967                private final HandlerStrategies strategies;
968
969                public HandlerStrategiesResponseContext(HandlerStrategies strategies) {
970                        this.strategies = strategies;
971                }
972
973                @Override
974                public List<HttpMessageWriter<?>> messageWriters() {
975                        return this.strategies.messageWriters();
976                }
977
978                @Override
979                public List<ViewResolver> viewResolvers() {
980                        return this.strategies.viewResolvers();
981                }
982        }
983
984
985        private static class RouterFunctionWebHandler implements WebHandler {
986
987                private static final HandlerFunction<ServerResponse> NOT_FOUND_HANDLER =
988                                request -> ServerResponse.notFound().build();
989
990                private final HandlerStrategies strategies;
991
992                private final RouterFunction<?> routerFunction;
993
994                public RouterFunctionWebHandler(HandlerStrategies strategies, RouterFunction<?> routerFunction) {
995                        this.strategies = strategies;
996                        this.routerFunction = routerFunction;
997                }
998
999                @Override
1000                public Mono<Void> handle(ServerWebExchange exchange) {
1001                        return Mono.defer(() -> {
1002                                ServerRequest request = new DefaultServerRequest(exchange, this.strategies.messageReaders());
1003                                addAttributes(exchange, request);
1004                                return this.routerFunction.route(request)
1005                                                .defaultIfEmpty(notFound())
1006                                                .flatMap(handlerFunction -> wrapException(() -> handlerFunction.handle(request)))
1007                                                .flatMap(response -> wrapException(() -> response.writeTo(exchange,
1008                                                                new HandlerStrategiesResponseContext(this.strategies))));
1009                        });
1010                }
1011
1012                private void addAttributes(ServerWebExchange exchange, ServerRequest request) {
1013                        Map<String, Object> attributes = exchange.getAttributes();
1014                        attributes.put(REQUEST_ATTRIBUTE, request);
1015                }
1016
1017                @SuppressWarnings("unchecked")
1018                private static <T extends ServerResponse> HandlerFunction<T> notFound() {
1019                        return (HandlerFunction<T>) NOT_FOUND_HANDLER;
1020                }
1021
1022                private static <T> Mono<T> wrapException(Supplier<Mono<T>> supplier) {
1023                        try {
1024                                return supplier.get();
1025                        }
1026                        catch (Throwable ex) {
1027                                return Mono.error(ex);
1028                        }
1029                }
1030        }
1031}