001/*
002 * Copyright 2002-2019 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.function.BiFunction;
020import java.util.function.Function;
021import java.util.function.Predicate;
022
023import org.springframework.util.Assert;
024
025/**
026 * Represents a function that filters a {@linkplain HandlerFunction handler function}.
027 *
028 * @author Arjen Poutsma
029 * @since 5.2
030 * @param <T> the type of the {@linkplain HandlerFunction handler function} to filter
031 * @param <R> the type of the response of the function
032 * @see RouterFunction#filter(HandlerFilterFunction)
033 */
034@FunctionalInterface
035public interface HandlerFilterFunction<T extends ServerResponse, R extends ServerResponse> {
036
037        /**
038         * Apply this filter to the given handler function. The given
039         * {@linkplain HandlerFunction handler function} represents the next entity in the chain,
040         * and can be {@linkplain HandlerFunction#handle(ServerRequest) invoked} in order to
041         * proceed to this entity, or not invoked to block the chain.
042         * @param request the request
043         * @param next the next handler or filter function in the chain
044         * @return the filtered response
045         */
046        R filter(ServerRequest request, HandlerFunction<T> next) throws Exception;
047
048        /**
049         * Return a composed filter function that first applies this filter, and then applies the
050         * {@code after} filter.
051         * @param after the filter to apply after this filter is applied
052         * @return a composed filter that first applies this function and then applies the
053         * {@code after} function
054         */
055        default HandlerFilterFunction<T, R> andThen(HandlerFilterFunction<T, T> after) {
056                Assert.notNull(after, "HandlerFilterFunction must not be null");
057                return (request, next) -> {
058                        HandlerFunction<T> nextHandler = handlerRequest -> after.filter(handlerRequest, next);
059                        return filter(request, nextHandler);
060                };
061        }
062
063        /**
064         * Apply this filter to the given handler function, resulting in a filtered handler function.
065         * @param handler the handler function to filter
066         * @return the filtered handler function
067         */
068        default HandlerFunction<R> apply(HandlerFunction<T> handler) {
069                Assert.notNull(handler, "HandlerFunction must not be null");
070                return request -> this.filter(request, handler);
071        }
072
073        /**
074         * Adapt the given request processor function to a filter function that only operates
075         * on the {@code ServerRequest}.
076         * @param requestProcessor the request processor
077         * @return the filter adaptation of the request processor
078         */
079        static <T extends ServerResponse> HandlerFilterFunction<T, T>
080        ofRequestProcessor(Function<ServerRequest, ServerRequest> requestProcessor) {
081
082                Assert.notNull(requestProcessor, "Function must not be null");
083                return (request, next) -> next.handle(requestProcessor.apply(request));
084        }
085
086        /**
087         * Adapt the given response processor function to a filter function that only operates
088         * on the {@code ServerResponse}.
089         * @param responseProcessor the response processor
090         * @return the filter adaptation of the request processor
091         */
092        static <T extends ServerResponse, R extends ServerResponse> HandlerFilterFunction<T, R>
093        ofResponseProcessor(BiFunction<ServerRequest, T, R> responseProcessor) {
094
095                Assert.notNull(responseProcessor, "Function must not be null");
096                return (request, next) -> responseProcessor.apply(request, next.handle(request));
097        }
098
099        /**
100         * Adapt the given predicate and response provider function to a filter function that returns
101         * a {@code ServerResponse} on a given exception.
102         * @param predicate the predicate to match an exception
103         * @param errorHandler the response provider
104         * @return the filter adaption of the error handler
105         */
106        static <T extends ServerResponse> HandlerFilterFunction<T, T>
107        ofErrorHandler(Predicate<Throwable> predicate, BiFunction<Throwable, ServerRequest, T> errorHandler) {
108
109                Assert.notNull(predicate, "Predicate must not be null");
110                Assert.notNull(errorHandler, "ErrorHandler must not be null");
111
112                return (request, next) -> {
113                        try {
114                                T t = next.handle(request);
115                                if (t instanceof DefaultServerResponseBuilder.AbstractServerResponse) {
116                                        ((DefaultServerResponseBuilder.AbstractServerResponse) t)
117                                                        .addErrorHandler(predicate, errorHandler);
118                                }
119                                return t;
120                        }
121                        catch (Throwable throwable) {
122                                if (predicate.test(throwable)) {
123                                        return errorHandler.apply(throwable, request);
124                                }
125                                else {
126                                        throw throwable;
127                                }
128                        }
129                };
130        }
131
132}