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.server.handler;
018
019import java.util.Arrays;
020import java.util.Collections;
021import java.util.List;
022import java.util.ListIterator;
023
024import reactor.core.publisher.Mono;
025
026import org.springframework.lang.Nullable;
027import org.springframework.util.Assert;
028import org.springframework.web.server.ServerWebExchange;
029import org.springframework.web.server.WebFilter;
030import org.springframework.web.server.WebFilterChain;
031import org.springframework.web.server.WebHandler;
032
033/**
034 * Default implementation of {@link WebFilterChain}.
035 *
036 * <p>Each instance of this class represents one link in the chain. The public
037 * constructor {@link #DefaultWebFilterChain(WebHandler, List)}
038 * initializes the full chain and represents its first link.
039 *
040 * <p>This class is immutable and thread-safe. It can be created once and
041 * re-used to handle request concurrently.
042 *
043 * @author Rossen Stoyanchev
044 * @since 5.0
045 */
046public class DefaultWebFilterChain implements WebFilterChain {
047
048        private final List<WebFilter> allFilters;
049
050        private final WebHandler handler;
051
052        @Nullable
053        private final WebFilter currentFilter;
054
055        @Nullable
056        private final DefaultWebFilterChain chain;
057
058
059        /**
060         * Public constructor with the list of filters and the target handler to use.
061         * @param handler the target handler
062         * @param filters the filters ahead of the handler
063         * @since 5.1
064         */
065        public DefaultWebFilterChain(WebHandler handler, List<WebFilter> filters) {
066                Assert.notNull(handler, "WebHandler is required");
067                this.allFilters = Collections.unmodifiableList(filters);
068                this.handler = handler;
069                DefaultWebFilterChain chain = initChain(filters, handler);
070                this.currentFilter = chain.currentFilter;
071                this.chain = chain.chain;
072        }
073
074        private static DefaultWebFilterChain initChain(List<WebFilter> filters, WebHandler handler) {
075                DefaultWebFilterChain chain = new DefaultWebFilterChain(filters, handler, null, null);
076                ListIterator<? extends WebFilter> iterator = filters.listIterator(filters.size());
077                while (iterator.hasPrevious()) {
078                        chain = new DefaultWebFilterChain(filters, handler, iterator.previous(), chain);
079                }
080                return chain;
081        }
082
083        /**
084         * Private constructor to represent one link in the chain.
085         */
086        private DefaultWebFilterChain(List<WebFilter> allFilters, WebHandler handler,
087                        @Nullable WebFilter currentFilter, @Nullable DefaultWebFilterChain chain) {
088
089                this.allFilters = allFilters;
090                this.currentFilter = currentFilter;
091                this.handler = handler;
092                this.chain = chain;
093        }
094
095        /**
096         * Public constructor with the list of filters and the target handler to use.
097         * @param handler the target handler
098         * @param filters the filters ahead of the handler
099         * @deprecated as of 5.1 this constructor is deprecated in favor of
100         * {@link #DefaultWebFilterChain(WebHandler, List)}.
101         */
102        @Deprecated
103        public DefaultWebFilterChain(WebHandler handler, WebFilter... filters) {
104                this(handler, Arrays.asList(filters));
105        }
106
107
108        public List<WebFilter> getFilters() {
109                return this.allFilters;
110        }
111
112        public WebHandler getHandler() {
113                return this.handler;
114        }
115
116
117        @Override
118        public Mono<Void> filter(ServerWebExchange exchange) {
119                return Mono.defer(() ->
120                                this.currentFilter != null && this.chain != null ?
121                                                invokeFilter(this.currentFilter, this.chain, exchange) :
122                                                this.handler.handle(exchange));
123        }
124
125        private Mono<Void> invokeFilter(WebFilter current, DefaultWebFilterChain chain, ServerWebExchange exchange) {
126                String currentName = current.getClass().getName();
127                return current.filter(exchange, chain).checkpoint(currentName + " [DefaultWebFilterChain]");
128        }
129
130}