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}