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.servlet.function;
018
019import java.util.Optional;
020import java.util.function.BiFunction;
021import java.util.function.Consumer;
022import java.util.function.Function;
023import java.util.function.Predicate;
024import java.util.function.Supplier;
025
026import org.apache.commons.logging.Log;
027import org.apache.commons.logging.LogFactory;
028
029import org.springframework.core.io.Resource;
030import org.springframework.util.Assert;
031
032/**
033 * <strong>Central entry point to Spring's functional web framework.</strong>
034 * Exposes routing functionality, such as to {@linkplain #route() create} a
035 * {@code RouterFunction} using a discoverable builder-style API, to
036 * {@linkplain #route(RequestPredicate, HandlerFunction) create} a {@code RouterFunction}
037 * given a {@code RequestPredicate} and {@code HandlerFunction}, and to do further
038 * {@linkplain #nest(RequestPredicate, RouterFunction) subrouting} on an existing routing
039 * function.
040 *
041 * @author Arjen Poutsma
042 * @since 5.2
043 */
044public abstract class RouterFunctions {
045
046        private static final Log logger = LogFactory.getLog(RouterFunctions.class);
047
048        /**
049         * Name of the request attribute that contains the {@link ServerRequest}.
050         */
051        public static final String REQUEST_ATTRIBUTE = RouterFunctions.class.getName() + ".request";
052
053        /**
054         * Name of the request attribute that contains the URI
055         * templates map, mapping variable names to values.
056         */
057        public static final String URI_TEMPLATE_VARIABLES_ATTRIBUTE =
058                        RouterFunctions.class.getName() + ".uriTemplateVariables";
059
060        /**
061         * Name of the request attribute that contains the matching pattern, as a
062         * {@link org.springframework.web.util.pattern.PathPattern}.
063         */
064        public static final String MATCHING_PATTERN_ATTRIBUTE =
065                        RouterFunctions.class.getName() + ".matchingPattern";
066
067
068        /**
069         * Offers a discoverable way to create router functions through a builder-style interface.
070         * @return a router function builder
071         */
072        public static Builder route() {
073                return new RouterFunctionBuilder();
074        }
075
076        /**
077         * Route to the given handler function if the given request predicate applies.
078         * <p>For instance, the following example routes GET requests for "/user" to the
079         * {@code listUsers} method in {@code userController}:
080         * <pre class="code">
081         * RouterFunction&lt;ServerResponse&gt; route =
082         *     RouterFunctions.route(RequestPredicates.GET("/user"), userController::listUsers);
083         * </pre>
084         * @param predicate the predicate to test
085         * @param handlerFunction the handler function to route to if the predicate applies
086         * @param <T> the type of response returned by the handler function
087         * @return a router function that routes to {@code handlerFunction} if
088         * {@code predicate} evaluates to {@code true}
089         * @see RequestPredicates
090         */
091        public static <T extends ServerResponse> RouterFunction<T> route(
092                        RequestPredicate predicate, HandlerFunction<T> handlerFunction) {
093
094                return new DefaultRouterFunction<>(predicate, handlerFunction);
095        }
096
097        /**
098         * Route to the given router function if the given request predicate applies. This method can be
099         * used to create <strong>nested routes</strong>, where a group of routes share a common path
100         * (prefix), header, or other request predicate.
101         * <p>For instance, the following example first creates a composed route that resolves to
102         * {@code listUsers} for a GET, and {@code createUser} for a POST. This composed route then gets
103         * nested with a "/user" path predicate, so that GET requests for "/user" will list users,
104         * and POST request for "/user" will create a new user.
105         * <pre class="code">
106         * RouterFunction&lt;ServerResponse&gt; userRoutes =
107         *   RouterFunctions.route(RequestPredicates.method(HttpMethod.GET), this::listUsers)
108         *     .andRoute(RequestPredicates.method(HttpMethod.POST), this::createUser);
109         * RouterFunction&lt;ServerResponse&gt; nestedRoute =
110         *   RouterFunctions.nest(RequestPredicates.path("/user"), userRoutes);
111         * </pre>
112         * @param predicate the predicate to test
113         * @param routerFunction the nested router function to delegate to if the predicate applies
114         * @param <T> the type of response returned by the handler function
115         * @return a router function that routes to {@code routerFunction} if
116         * {@code predicate} evaluates to {@code true}
117         * @see RequestPredicates
118         */
119        public static <T extends ServerResponse> RouterFunction<T> nest(
120                        RequestPredicate predicate, RouterFunction<T> routerFunction) {
121
122                return new DefaultNestedRouterFunction<>(predicate, routerFunction);
123        }
124
125        /**
126         * Route requests that match the given pattern to resources relative to the given root location.
127         * For instance
128         * <pre class="code">
129         * Resource location = new FileSystemResource("public-resources/");
130         * RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resources("/resources/**", location);
131     * </pre>
132         * @param pattern the pattern to match
133         * @param location the location directory relative to which resources should be resolved
134         * @return a router function that routes to resources
135         * @see #resourceLookupFunction(String, Resource)
136         */
137        public static RouterFunction<ServerResponse> resources(String pattern, Resource location) {
138                return resources(resourceLookupFunction(pattern, location));
139        }
140
141        /**
142         * Returns the resource lookup function used by {@link #resources(String, Resource)}.
143         * The returned function can be {@linkplain Function#andThen(Function) composed} on, for
144         * instance to return a default resource when the lookup function does not match:
145         * <pre class="code">
146         * Optional&lt;Resource&gt; defaultResource = Optional.of(new ClassPathResource("index.html"));
147         * Function&lt;ServerRequest, Optional&lt;Resource&gt;&gt; lookupFunction =
148         *   RouterFunctions.resourceLookupFunction("/resources/**", new FileSystemResource("public-resources/"))
149         *     .andThen(resource -&gt; resource.or(() -&gt; defaultResource));
150         * RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resources(lookupFunction);
151     * </pre>
152         * @param pattern the pattern to match
153         * @param location the location directory relative to which resources should be resolved
154         * @return the default resource lookup function for the given parameters.
155         */
156        public static Function<ServerRequest, Optional<Resource>> resourceLookupFunction(String pattern, Resource location) {
157                return new PathResourceLookupFunction(pattern, location);
158        }
159
160        /**
161         * Route to resources using the provided lookup function. If the lookup function provides a
162         * {@link Resource} for the given request, it will be it will be exposed using a
163         * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests.
164         * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest}
165         * @return a router function that routes to resources
166         */
167        public static RouterFunction<ServerResponse> resources(Function<ServerRequest, Optional<Resource>> lookupFunction) {
168                return new ResourcesRouterFunction(lookupFunction);
169        }
170
171
172        /**
173         * Represents a discoverable builder for router functions.
174         * Obtained via {@link RouterFunctions#route()}.
175         */
176        public interface Builder {
177
178                /**
179                 * Adds a route to the given handler function that handles all HTTP {@code GET} requests
180                 * that match the given pattern.
181                 * @param pattern the pattern to match to
182                 * @param handlerFunction the handler function to handle all {@code GET} requests that
183                 * match {@code pattern}
184                 * @return this builder
185                 */
186                Builder GET(String pattern, HandlerFunction<ServerResponse> handlerFunction);
187
188                /**
189                 * Adds a route to the given handler function that handles all HTTP {@code GET} requests
190                 * that match the given pattern and predicate.
191                 * <p>For instance, the following example routes GET requests for "/user" that accept JSON
192                 * to the {@code listUsers} method in {@code userController}:
193                 * <pre class="code">
194                 * RouterFunction&lt;ServerResponse&gt; route =
195                 *   RouterFunctions.route()
196                 *     .GET("/user", RequestPredicates.accept(MediaType.APPLICATION_JSON), userController::listUsers)
197                 *     .build();
198                 * </pre>
199                 * @param pattern the pattern to match to
200                 * @param predicate additional predicate to match
201                 * @param handlerFunction the handler function to handle all {@code GET} requests that
202                 * match {@code pattern}
203                 * @return this builder
204                 * @see RequestPredicates
205                 */
206                Builder GET(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
207
208                /**
209                 * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests
210                 * that match the given pattern.
211                 * @param pattern the pattern to match to
212                 * @param handlerFunction the handler function to handle all {@code HEAD} requests that
213                 * match {@code pattern}
214                 * @return this builder
215                 */
216                Builder HEAD(String pattern, HandlerFunction<ServerResponse> handlerFunction);
217
218                /**
219                 * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests
220                 * that match the given pattern and predicate.
221                 * @param pattern the pattern to match to
222                 * @param predicate additional predicate to match
223                 * @param handlerFunction the handler function to handle all {@code HEAD} requests that
224                 * match {@code pattern}
225                 * @return this builder
226                 */
227                Builder HEAD(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
228
229                /**
230                 * Adds a route to the given handler function that handles all HTTP {@code POST} requests
231                 * that match the given pattern.
232                 * @param pattern the pattern to match to
233                 * @param handlerFunction the handler function to handle all {@code POST} requests that
234                 * match {@code pattern}
235                 * @return this builder
236                 */
237                Builder POST(String pattern, HandlerFunction<ServerResponse> handlerFunction);
238
239                /**
240                 * Adds a route to the given handler function that handles all HTTP {@code POST} requests
241                 * that match the given pattern and predicate.
242                 * <p>For instance, the following example routes POST requests for "/user" that contain JSON
243                 * to the {@code addUser} method in {@code userController}:
244                 * <pre class="code">
245                 * RouterFunction&lt;ServerResponse&gt; route =
246                 *   RouterFunctions.route()
247                 *     .POST("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::addUser)
248                 *     .build();
249                 * </pre>
250                 * @param pattern the pattern to match to
251                 * @param predicate additional predicate to match
252                 * @param handlerFunction the handler function to handle all {@code POST} requests that
253                 * match {@code pattern}
254                 * @return this builder
255                 */
256                Builder POST(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
257
258                /**
259                 * Adds a route to the given handler function that handles all HTTP {@code PUT} requests
260                 * that match the given pattern.
261                 * @param pattern the pattern to match to
262                 * @param handlerFunction the handler function to handle all {@code PUT} requests that
263                 * match {@code pattern}
264                 * @return this builder
265                 */
266                Builder PUT(String pattern, HandlerFunction<ServerResponse> handlerFunction);
267
268                /**
269                 * Adds a route to the given handler function that handles all HTTP {@code PUT} requests
270                 * that match the given pattern and predicate.
271                 * <p>For instance, the following example routes PUT requests for "/user" that contain JSON
272                 * to the {@code editUser} method in {@code userController}:
273                 * <pre class="code">
274                 * RouterFunction&lt;ServerResponse&gt; route =
275                 *   RouterFunctions.route()
276                 *     .PUT("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
277                 *     .build();
278                 * </pre>
279                 * @param pattern the pattern to match to
280                 * @param predicate additional predicate to match
281                 * @param handlerFunction the handler function to handle all {@code PUT} requests that
282                 * match {@code pattern}
283                 * @return this builder
284                 */
285                Builder PUT(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
286
287                /**
288                 * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests
289                 * that match the given pattern.
290                 * @param pattern the pattern to match to
291                 * @param handlerFunction the handler function to handle all {@code PATCH} requests that
292                 * match {@code pattern}
293                 * @return this builder
294                 */
295                Builder PATCH(String pattern, HandlerFunction<ServerResponse> handlerFunction);
296
297                /**
298                 * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests
299                 * that match the given pattern and predicate.
300                 * <p>For instance, the following example routes PATCH requests for "/user" that contain JSON
301                 * to the {@code editUser} method in {@code userController}:
302                 * <pre class="code">
303                 * RouterFunction&lt;ServerResponse&gt; route =
304                 *   RouterFunctions.route()
305                 *     .PATCH("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
306                 *     .build();
307                 * </pre>
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 PATCH} requests that
311                 * match {@code pattern}
312                 * @return this builder
313                 */
314                Builder PATCH(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
315
316                /**
317                 * Adds a route to the given handler function that handles all HTTP {@code DELETE} 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 DELETE} requests that
321                 * match {@code pattern}
322                 * @return this builder
323                 */
324                Builder DELETE(String pattern, HandlerFunction<ServerResponse> handlerFunction);
325
326                /**
327                 * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests
328                 * that match the given pattern and predicate.
329                 * @param pattern the pattern to match to
330                 * @param predicate additional predicate to match
331                 * @param handlerFunction the handler function to handle all {@code DELETE} requests that
332                 * match {@code pattern}
333                 * @return this builder
334                 */
335                Builder DELETE(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
336
337                /**
338                 * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests
339                 * that match the given pattern.
340                 * @param pattern the pattern to match to
341                 * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that
342                 * match {@code pattern}
343                 * @return this builder
344                 */
345                Builder OPTIONS(String pattern, HandlerFunction<ServerResponse> handlerFunction);
346
347                /**
348                 * Adds a route to the given handler function that handles all requests that match the
349                 * given predicate.
350                 *
351                 * @param predicate the request predicate to match
352                 * @param handlerFunction the handler function to handle all requests that match the predicate
353                 * @return this builder
354                 * @see RequestPredicates
355                 */
356                Builder route(RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
357
358                /**
359                 * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests
360                 * that match the given pattern and predicate.
361                 * @param pattern the pattern to match to
362                 * @param predicate additional predicate to match
363                 * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that
364                 * match {@code pattern}
365                 * @return this builder
366                 */
367                Builder OPTIONS(String pattern, RequestPredicate predicate, HandlerFunction<ServerResponse> handlerFunction);
368
369                /**
370                 * Adds the given route to this builder. Can be used to merge externally defined router
371                 * functions into this builder, or can be combined with
372                 * {@link RouterFunctions#route(RequestPredicate, HandlerFunction)}
373                 * to allow for more flexible predicate matching.
374                 * <p>For instance, the following example adds the router function returned from
375                 * {@code OrderController.routerFunction()}.
376                 * to the {@code changeUser} method in {@code userController}:
377                 * <pre class="code">
378                 * RouterFunction&lt;ServerResponse&gt; route =
379                 *   RouterFunctions.route()
380                 *     .GET("/users", userController::listUsers)
381                 *     .add(orderController.routerFunction());
382                 *     .build();
383                 * </pre>
384                 * @param routerFunction the router function to be added
385                 * @return this builder
386                 * @see RequestPredicates
387                 */
388                Builder add(RouterFunction<ServerResponse> routerFunction);
389
390                /**
391                 * Route requests that match the given pattern to resources relative to the given root location.
392                 * For instance
393                 * <pre class="code">
394                 * Resource location = new FileSystemResource("public-resources/");
395                 * RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resources("/resources/**", location);
396             * </pre>
397                 * @param pattern the pattern to match
398                 * @param location the location directory relative to which resources should be resolved
399                 * @return this builder
400                 */
401                Builder resources(String pattern, Resource location);
402
403                /**
404                 * Route to resources using the provided lookup function. If the lookup function provides a
405                 * {@link Resource} for the given request, it will be it will be exposed using a
406                 * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests.
407                 * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest}
408                 * @return this builder
409                 */
410                Builder resources(Function<ServerRequest, Optional<Resource>> lookupFunction);
411
412                /**
413                 * Route to the supplied router function if the given request predicate applies. This method
414                 * can be used to create <strong>nested routes</strong>, where a group of routes share a
415                 * common path (prefix), header, or other request predicate.
416                 * <p>For instance, the following example creates a nested route with a "/user" path
417                 * predicate, so that GET requests for "/user" will list users,
418                 * and POST request for "/user" will create a new user.
419                 * <pre class="code">
420                 * RouterFunction&lt;ServerResponse&gt; nestedRoute =
421                 *   RouterFunctions.route()
422                 *     .nest(RequestPredicates.path("/user"), () ->
423                 *       RouterFunctions.route()
424                 *         .GET(this::listUsers)
425                 *         .POST(this::createUser)
426                 *         .build())
427                 *     .build();
428                 * </pre>
429                 * @param predicate the predicate to test
430                 * @param routerFunctionSupplier supplier for the nested router function to delegate to if
431                 * the predicate applies
432                 * @return this builder
433                 * @see RequestPredicates
434                 */
435                Builder nest(RequestPredicate predicate, Supplier<RouterFunction<ServerResponse>> routerFunctionSupplier);
436
437                /**
438                 * Route to a built router function if the given request predicate applies.
439                 * This method can be used to create <strong>nested routes</strong>, where a group of routes
440                 * share a common path (prefix), header, or other request predicate.
441                 * <p>For instance, the following example creates a nested route with a "/user" path
442                 * predicate, so that GET requests for "/user" will list users,
443                 * and POST request for "/user" will create a new user.
444                 * <pre class="code">
445                 * RouterFunction&lt;ServerResponse&gt; nestedRoute =
446                 *   RouterFunctions.route()
447                 *     .nest(RequestPredicates.path("/user"), builder ->
448                 *       builder.GET(this::listUsers)
449                 *              .POST(this::createUser))
450                 *     .build();
451                 * </pre>
452                 * @param predicate the predicate to test
453                 * @param builderConsumer consumer for a {@code Builder} that provides the nested router
454                 * function
455                 * @return this builder
456                 * @see RequestPredicates
457                 */
458                Builder nest(RequestPredicate predicate, Consumer<Builder> builderConsumer);
459
460                /**
461                 * Route to the supplied router function if the given path prefix pattern applies. This method
462                 * can be used to create <strong>nested routes</strong>, where a group of routes share a
463                 * common path prefix. Specifically, this method can be used to merge externally defined
464                 * router functions under a path prefix.
465                 * <p>For instance, the following example creates a nested route with a "/user" path
466                 * predicate that delegates to the router function defined in {@code userController},
467                 * and with a "/order" path that delegates to {@code orderController}.
468                 * <pre class="code">
469                 * RouterFunction&lt;ServerResponse&gt; nestedRoute =
470                 *   RouterFunctions.route()
471                 *     .path("/user", userController::routerFunction)
472                 *     .path("/order", orderController::routerFunction)
473                 *     .build();
474                 * </pre>
475                 * @param pattern the pattern to match to
476                 * @param routerFunctionSupplier supplier for the nested router function to delegate to if
477                 * the pattern matches
478                 * @return this builder
479                 */
480                Builder path(String pattern, Supplier<RouterFunction<ServerResponse>> routerFunctionSupplier);
481
482                /**
483                 * Route to a built router function if the given path prefix pattern applies.
484                 * This method can be used to create <strong>nested routes</strong>, where a group of routes
485                 * share a common path prefix.
486                 * <p>For instance, the following example creates a nested route with a "/user" path
487                 * predicate, so that GET requests for "/user" will list users,
488                 * and POST request for "/user" will create a new user.
489                 * <pre class="code">
490                 * RouterFunction&lt;ServerResponse&gt; nestedRoute =
491                 *   RouterFunctions.route()
492                 *     .path("/user", builder ->
493                 *       builder.GET(this::listUsers)
494                 *              .POST(this::createUser))
495                 *     .build();
496                 * </pre>
497                 * @param pattern the pattern to match to
498                 * @param builderConsumer consumer for a {@code Builder} that provides the nested router
499                 * function
500                 * @return this builder
501                 */
502                Builder path(String pattern, Consumer<Builder> builderConsumer);
503
504                /**
505                 * Filters all routes created by this builder with the given filter function. Filter
506                 * functions are typically used to address cross-cutting concerns, such as logging,
507                 * security, etc.
508                 * <p>For instance, the following example creates a filter that returns a 401 Unauthorized
509                 * response if the request does not contain the necessary authentication headers.
510                 * <pre class="code">
511                 * RouterFunction&lt;ServerResponse&gt; filteredRoute =
512                 *   RouterFunctions.route()
513                 *     .GET("/user", this::listUsers)
514                 *     .filter((request, next) -> {
515                 *       // check for authentication headers
516                 *       if (isAuthenticated(request)) {
517                 *         return next.handle(request);
518                 *       }
519                 *       else {
520                 *         return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
521                 *       }
522                 *     })
523                 *     .build();
524                 * </pre>
525                 * @param filterFunction the function to filter all routes built by this builder
526                 * @return this builder
527                 */
528                Builder filter(HandlerFilterFunction<ServerResponse, ServerResponse> filterFunction);
529
530                /**
531                 * Filter the request object for all routes created by this builder with the given request
532                 * processing function. Filters are typically used to address cross-cutting concerns, such
533                 * as logging, security, etc.
534                 * <p>For instance, the following example creates a filter that logs the request before
535                 * the handler function executes.
536                 * <pre class="code">
537                 * RouterFunction&lt;ServerResponse&gt; filteredRoute =
538                 *   RouterFunctions.route()
539                 *     .GET("/user", this::listUsers)
540                 *     .before(request -> {
541                 *       log(request);
542                 *       return request;
543                 *     })
544                 *     .build();
545                 * </pre>
546                 * @param requestProcessor a function that transforms the request
547                 * @return this builder
548                 */
549                Builder before(Function<ServerRequest, ServerRequest> requestProcessor);
550
551                /**
552                 * Filter the response object for all routes created by this builder with the given response
553                 * processing function. Filters are typically used to address cross-cutting concerns, such
554                 * as logging, security, etc.
555                 * <p>For instance, the following example creates a filter that logs the response after
556                 * the handler function executes.
557                 * <pre class="code">
558                 * RouterFunction&lt;ServerResponse&gt; filteredRoute =
559                 *   RouterFunctions.route()
560                 *     .GET("/user", this::listUsers)
561                 *     .after((request, response) -> {
562                 *       log(response);
563                 *       return response;
564                 *     })
565                 *     .build();
566                 * </pre>
567                 * @param responseProcessor a function that transforms the response
568                 * @return this builder
569                 */
570                Builder after(BiFunction<ServerRequest, ServerResponse, ServerResponse> responseProcessor);
571
572                /**
573                 * Filters all exceptions that match the predicate by applying the given response provider
574                 * function.
575                 * <p>For instance, the following example creates a filter that returns a 500 response
576                 * status when an {@code IllegalStateException} occurs.
577                 * <pre class="code">
578                 * RouterFunction&lt;ServerResponse&gt; filteredRoute =
579                 *   RouterFunctions.route()
580                 *     .GET("/user", this::listUsers)
581                 *     .onError(e -> e instanceof IllegalStateException,
582                 *       (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
583                 *     .build();
584                 * </pre>
585                 * @param predicate the type of exception to filter
586                 * @param responseProvider a function that creates a response
587                 * @return this builder
588                 */
589                Builder onError(Predicate<Throwable> predicate,
590                                BiFunction<Throwable, ServerRequest, ServerResponse> responseProvider);
591
592                /**
593                 * Filters all exceptions of the given type by applying the given response provider
594                 * function.
595                 * <p>For instance, the following example creates a filter that returns a 500 response
596                 * status when an {@code IllegalStateException} occurs.
597                 * <pre class="code">
598                 * RouterFunction&lt;ServerResponse&gt; filteredRoute =
599                 *   RouterFunctions.route()
600                 *     .GET("/user", this::listUsers)
601                 *     .onError(IllegalStateException.class,
602                 *       (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
603                 *     .build();
604                 * </pre>
605                 * @param exceptionType the type of exception to filter
606                 * @param responseProvider a function that creates a response
607                 * @return this builder
608                 */
609                Builder onError(Class<? extends Throwable> exceptionType,
610                                BiFunction<Throwable, ServerRequest, ServerResponse> responseProvider);
611
612                /**
613                 * Builds the {@code RouterFunction}. All created routes are
614                 * {@linkplain RouterFunction#and(RouterFunction) composed} with one another, and filters
615                 * (if any) are applied to the result.
616                 * @return the built router function
617                 */
618                RouterFunction<ServerResponse> build();
619        }
620        /**
621         * Receives notifications from the logical structure of router functions.
622         */
623        public interface Visitor {
624
625                /**
626                 * Receive notification of the beginning of a nested router function.
627                 * @param predicate the predicate that applies to the nested router functions
628                 * @see RouterFunctions#nest(RequestPredicate, RouterFunction)
629                 */
630                void startNested(RequestPredicate predicate);
631
632                /**
633                 * Receive notification of the end of a nested router function.
634                 * @param predicate the predicate that applies to the nested router functions
635                 * @see RouterFunctions#nest(RequestPredicate, RouterFunction)
636                 */
637                void endNested(RequestPredicate predicate);
638
639                /**
640                 * Receive notification of a standard predicated route to a handler function.
641                 * @param predicate the predicate that applies to the handler function
642                 * @param handlerFunction the handler function.
643                 * @see RouterFunctions#route(RequestPredicate, HandlerFunction)
644                 */
645                void route(RequestPredicate predicate, HandlerFunction<?> handlerFunction);
646
647                /**
648                 * Receive notification of a resource router function.
649                 * @param lookupFunction the lookup function for the resources
650                 * @see RouterFunctions#resources(Function)
651                 */
652                void resources(Function<ServerRequest, Optional<Resource>> lookupFunction);
653
654                /**
655                 * Receive notification of an unknown router function. This method is called for router
656                 * functions that were not created via the various {@link RouterFunctions} methods.
657                 * @param routerFunction the router function
658                 */
659                void unknown(RouterFunction<?> routerFunction);
660        }
661
662
663        abstract static class AbstractRouterFunction<T extends ServerResponse> implements RouterFunction<T> {
664
665                @Override
666                public String toString() {
667                        ToStringVisitor visitor = new ToStringVisitor();
668                        accept(visitor);
669                        return visitor.toString();
670                }
671        }
672
673        /**
674         * A composed routing function that first invokes one function, and then invokes the
675         * another function (of the same response type {@code T}) if this route had
676         * {@linkplain Optional#empty() no result}.
677         * @param <T> the server response type
678         */
679        static final class SameComposedRouterFunction<T extends ServerResponse> extends AbstractRouterFunction<T> {
680
681                private final RouterFunction<T> first;
682
683                private final RouterFunction<T> second;
684
685                public SameComposedRouterFunction(RouterFunction<T> first, RouterFunction<T> second) {
686                        this.first = first;
687                        this.second = second;
688                }
689
690                @Override
691                public Optional<HandlerFunction<T>> route(ServerRequest request) {
692                        Optional<HandlerFunction<T>> firstRoute = this.first.route(request);
693                        if (firstRoute.isPresent()) {
694                                return firstRoute;
695                        }
696                        else {
697                                return this.second.route(request);
698                        }
699                }
700
701                @Override
702                public void accept(Visitor visitor) {
703                        this.first.accept(visitor);
704                        this.second.accept(visitor);
705                }
706        }
707
708        /**
709         * A composed routing function that first invokes one function, and then invokes
710         * another function (of a different response type) if this route had
711         * {@linkplain Optional#empty() no result}.
712         */
713        static final class DifferentComposedRouterFunction extends AbstractRouterFunction<ServerResponse> {
714
715                private final RouterFunction<?> first;
716
717                private final RouterFunction<?> second;
718
719                public DifferentComposedRouterFunction(RouterFunction<?> first, RouterFunction<?> second) {
720                        this.first = first;
721                        this.second = second;
722                }
723
724                @Override
725                @SuppressWarnings("unchecked")
726                public Optional<HandlerFunction<ServerResponse>> route(ServerRequest request) {
727                        Optional<? extends HandlerFunction<?>> firstRoute = this.first.route(request);
728                        if (firstRoute.isPresent()) {
729                                return (Optional<HandlerFunction<ServerResponse>>) firstRoute;
730                        }
731                        else {
732                                Optional<? extends HandlerFunction<?>> secondRoute = this.second.route(request);
733                                return (Optional<HandlerFunction<ServerResponse>>) secondRoute;
734                        }
735                }
736
737                @Override
738                public void accept(Visitor visitor) {
739                        this.first.accept(visitor);
740                        this.second.accept(visitor);
741                }
742        }
743
744
745        /**
746         * Filter the specified {@linkplain HandlerFunction handler functions} with the given
747         * {@linkplain HandlerFilterFunction filter function}.
748         * @param <T> the type of the {@linkplain HandlerFunction handler function} to filter
749         * @param <S> the type of the response of the function
750         */
751        static final class FilteredRouterFunction<T extends ServerResponse, S extends ServerResponse>
752                        implements RouterFunction<S> {
753
754                private final RouterFunction<T> routerFunction;
755
756                private final HandlerFilterFunction<T, S> filterFunction;
757
758                public FilteredRouterFunction(
759                                RouterFunction<T> routerFunction,
760                                HandlerFilterFunction<T, S> filterFunction) {
761                        this.routerFunction = routerFunction;
762                        this.filterFunction = filterFunction;
763                }
764
765                @Override
766                public Optional<HandlerFunction<S>> route(ServerRequest request) {
767                        return this.routerFunction.route(request).map(this.filterFunction::apply);
768                }
769
770                @Override
771                public void accept(Visitor visitor) {
772                        this.routerFunction.accept(visitor);
773                }
774
775                @Override
776                public String toString() {
777                        return this.routerFunction.toString();
778                }
779        }
780
781        private static final class DefaultRouterFunction<T extends ServerResponse>
782                        extends AbstractRouterFunction<T> {
783
784                private final RequestPredicate predicate;
785
786                private final HandlerFunction<T> handlerFunction;
787
788                public DefaultRouterFunction(RequestPredicate predicate, HandlerFunction<T> handlerFunction) {
789                        Assert.notNull(predicate, "Predicate must not be null");
790                        Assert.notNull(handlerFunction, "HandlerFunction must not be null");
791                        this.predicate = predicate;
792                        this.handlerFunction = handlerFunction;
793                }
794
795                @Override
796                public Optional<HandlerFunction<T>> route(ServerRequest request) {
797                        if (this.predicate.test(request)) {
798                                if (logger.isTraceEnabled()) {
799                                        logger.trace(String.format("Predicate \"%s\" matches against \"%s\"", this.predicate, request));
800                                }
801                                return Optional.of(this.handlerFunction);
802                        }
803                        else {
804                                return Optional.empty();
805                        }
806                }
807
808                @Override
809                public void accept(Visitor visitor) {
810                        visitor.route(this.predicate, this.handlerFunction);
811                }
812
813        }
814
815        private static final class DefaultNestedRouterFunction<T extends ServerResponse>
816                        extends AbstractRouterFunction<T> {
817
818                private final RequestPredicate predicate;
819
820                private final RouterFunction<T> routerFunction;
821
822                public DefaultNestedRouterFunction(RequestPredicate predicate, RouterFunction<T> routerFunction) {
823                        Assert.notNull(predicate, "Predicate must not be null");
824                        Assert.notNull(routerFunction, "RouterFunction must not be null");
825                        this.predicate = predicate;
826                        this.routerFunction = routerFunction;
827                }
828
829                @Override
830                public Optional<HandlerFunction<T>> route(ServerRequest serverRequest) {
831                        return this.predicate.nest(serverRequest)
832                                        .map(nestedRequest -> {
833                                                                if (logger.isTraceEnabled()) {
834                                                                        logger.trace(
835                                                                                        String.format(
836                                                                                                        "Nested predicate \"%s\" matches against \"%s\"",
837                                                                                                        this.predicate, serverRequest));
838                                                                }
839                                                                Optional<HandlerFunction<T>> result =
840                                                                                this.routerFunction.route(nestedRequest);
841                                                                if (result.isPresent() && nestedRequest != serverRequest) {
842                                                                        serverRequest.attributes().clear();
843                                                                        serverRequest.attributes().putAll(nestedRequest.attributes());
844                                                                }
845                                                                return result;
846                                                        }
847                                        )
848                                        .orElseGet(Optional::empty);
849                }
850
851
852                @Override
853                public void accept(Visitor visitor) {
854                        visitor.startNested(this.predicate);
855                        this.routerFunction.accept(visitor);
856                        visitor.endNested(this.predicate);
857                }
858
859        }
860
861        private static class ResourcesRouterFunction extends  AbstractRouterFunction<ServerResponse> {
862
863                private final Function<ServerRequest, Optional<Resource>> lookupFunction;
864
865                public ResourcesRouterFunction(Function<ServerRequest, Optional<Resource>> lookupFunction) {
866                        Assert.notNull(lookupFunction, "Function must not be null");
867                        this.lookupFunction = lookupFunction;
868                }
869
870                @Override
871                public Optional<HandlerFunction<ServerResponse>> route(ServerRequest request) {
872                        return this.lookupFunction.apply(request).map(ResourceHandlerFunction::new);
873                }
874
875                @Override
876                public void accept(Visitor visitor) {
877                        visitor.resources(this.lookupFunction);
878                }
879        }
880
881
882}