001/* 002 * Copyright 2012-2018 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 * http://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.boot.web.servlet; 018 019import java.util.Arrays; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.EnumSet; 023import java.util.LinkedHashSet; 024import java.util.Set; 025 026import javax.servlet.DispatcherType; 027import javax.servlet.Filter; 028import javax.servlet.FilterRegistration; 029import javax.servlet.FilterRegistration.Dynamic; 030import javax.servlet.ServletContext; 031 032import org.springframework.util.Assert; 033import org.springframework.util.StringUtils; 034 035/** 036 * Abstract base {@link ServletContextInitializer} to register {@link Filter}s in a 037 * Servlet 3.0+ container. 038 * 039 * @param <T> the type of {@link Filter} to register 040 * @author Phillip Webb 041 * @author Brian Clozel 042 * @since 2.0.1 043 */ 044public abstract class AbstractFilterRegistrationBean<T extends Filter> 045 extends DynamicRegistrationBean<Dynamic> { 046 047 /** 048 * Filters that wrap the servlet request should be ordered less than or equal to this. 049 * @deprecated since 2.1.0 in favor of 050 * {@code OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER} 051 */ 052 @Deprecated 053 protected static final int REQUEST_WRAPPER_FILTER_MAX_ORDER = 0; 054 055 private static final String[] DEFAULT_URL_MAPPINGS = { "/*" }; 056 057 private Set<ServletRegistrationBean<?>> servletRegistrationBeans = new LinkedHashSet<>(); 058 059 private Set<String> servletNames = new LinkedHashSet<>(); 060 061 private Set<String> urlPatterns = new LinkedHashSet<>(); 062 063 private EnumSet<DispatcherType> dispatcherTypes; 064 065 private boolean matchAfter = false; 066 067 /** 068 * Create a new instance to be registered with the specified 069 * {@link ServletRegistrationBean}s. 070 * @param servletRegistrationBeans associate {@link ServletRegistrationBean}s 071 */ 072 AbstractFilterRegistrationBean( 073 ServletRegistrationBean<?>... servletRegistrationBeans) { 074 Assert.notNull(servletRegistrationBeans, 075 "ServletRegistrationBeans must not be null"); 076 Collections.addAll(this.servletRegistrationBeans, servletRegistrationBeans); 077 } 078 079 /** 080 * Set {@link ServletRegistrationBean}s that the filter will be registered against. 081 * @param servletRegistrationBeans the Servlet registration beans 082 */ 083 public void setServletRegistrationBeans( 084 Collection<? extends ServletRegistrationBean<?>> servletRegistrationBeans) { 085 Assert.notNull(servletRegistrationBeans, 086 "ServletRegistrationBeans must not be null"); 087 this.servletRegistrationBeans = new LinkedHashSet<>(servletRegistrationBeans); 088 } 089 090 /** 091 * Return a mutable collection of the {@link ServletRegistrationBean} that the filter 092 * will be registered against. {@link ServletRegistrationBean}s. 093 * @return the Servlet registration beans 094 * @see #setServletNames 095 * @see #setUrlPatterns 096 */ 097 public Collection<ServletRegistrationBean<?>> getServletRegistrationBeans() { 098 return this.servletRegistrationBeans; 099 } 100 101 /** 102 * Add {@link ServletRegistrationBean}s for the filter. 103 * @param servletRegistrationBeans the servlet registration beans to add 104 * @see #setServletRegistrationBeans 105 */ 106 public void addServletRegistrationBeans( 107 ServletRegistrationBean<?>... servletRegistrationBeans) { 108 Assert.notNull(servletRegistrationBeans, 109 "ServletRegistrationBeans must not be null"); 110 Collections.addAll(this.servletRegistrationBeans, servletRegistrationBeans); 111 } 112 113 /** 114 * Set servlet names that the filter will be registered against. This will replace any 115 * previously specified servlet names. 116 * @param servletNames the servlet names 117 * @see #setServletRegistrationBeans 118 * @see #setUrlPatterns 119 */ 120 public void setServletNames(Collection<String> servletNames) { 121 Assert.notNull(servletNames, "ServletNames must not be null"); 122 this.servletNames = new LinkedHashSet<>(servletNames); 123 } 124 125 /** 126 * Return a mutable collection of servlet names that the filter will be registered 127 * against. 128 * @return the servlet names 129 */ 130 public Collection<String> getServletNames() { 131 return this.servletNames; 132 } 133 134 /** 135 * Add servlet names for the filter. 136 * @param servletNames the servlet names to add 137 */ 138 public void addServletNames(String... servletNames) { 139 Assert.notNull(servletNames, "ServletNames must not be null"); 140 this.servletNames.addAll(Arrays.asList(servletNames)); 141 } 142 143 /** 144 * Set the URL patterns that the filter will be registered against. This will replace 145 * any previously specified URL patterns. 146 * @param urlPatterns the URL patterns 147 * @see #setServletRegistrationBeans 148 * @see #setServletNames 149 */ 150 public void setUrlPatterns(Collection<String> urlPatterns) { 151 Assert.notNull(urlPatterns, "UrlPatterns must not be null"); 152 this.urlPatterns = new LinkedHashSet<>(urlPatterns); 153 } 154 155 /** 156 * Return a mutable collection of URL patterns, as defined in the Servlet 157 * specification, that the filter will be registered against. 158 * @return the URL patterns 159 */ 160 public Collection<String> getUrlPatterns() { 161 return this.urlPatterns; 162 } 163 164 /** 165 * Add URL patterns, as defined in the Servlet specification, that the filter will be 166 * registered against. 167 * @param urlPatterns the URL patterns 168 */ 169 public void addUrlPatterns(String... urlPatterns) { 170 Assert.notNull(urlPatterns, "UrlPatterns must not be null"); 171 Collections.addAll(this.urlPatterns, urlPatterns); 172 } 173 174 /** 175 * Convenience method to {@link #setDispatcherTypes(EnumSet) set dispatcher types} 176 * using the specified elements. 177 * @param first the first dispatcher type 178 * @param rest additional dispatcher types 179 */ 180 public void setDispatcherTypes(DispatcherType first, DispatcherType... rest) { 181 this.dispatcherTypes = EnumSet.of(first, rest); 182 } 183 184 /** 185 * Sets the dispatcher types that should be used with the registration. If not 186 * specified the types will be deduced based on the value of 187 * {@link #isAsyncSupported()}. 188 * @param dispatcherTypes the dispatcher types 189 */ 190 public void setDispatcherTypes(EnumSet<DispatcherType> dispatcherTypes) { 191 this.dispatcherTypes = dispatcherTypes; 192 } 193 194 /** 195 * Set if the filter mappings should be matched after any declared filter mappings of 196 * the ServletContext. Defaults to {@code false} indicating the filters are supposed 197 * to be matched before any declared filter mappings of the ServletContext. 198 * @param matchAfter if filter mappings are matched after 199 */ 200 public void setMatchAfter(boolean matchAfter) { 201 this.matchAfter = matchAfter; 202 } 203 204 /** 205 * Return if filter mappings should be matched after any declared Filter mappings of 206 * the ServletContext. 207 * @return if filter mappings are matched after 208 */ 209 public boolean isMatchAfter() { 210 return this.matchAfter; 211 } 212 213 @Override 214 protected String getDescription() { 215 Filter filter = getFilter(); 216 Assert.notNull(filter, "Filter must not be null"); 217 return "filter " + getOrDeduceName(filter); 218 } 219 220 @Override 221 protected Dynamic addRegistration(String description, ServletContext servletContext) { 222 Filter filter = getFilter(); 223 return servletContext.addFilter(getOrDeduceName(filter), filter); 224 } 225 226 /** 227 * Configure registration settings. Subclasses can override this method to perform 228 * additional configuration if required. 229 * @param registration the registration 230 */ 231 @Override 232 protected void configure(FilterRegistration.Dynamic registration) { 233 super.configure(registration); 234 EnumSet<DispatcherType> dispatcherTypes = this.dispatcherTypes; 235 if (dispatcherTypes == null) { 236 dispatcherTypes = EnumSet.of(DispatcherType.REQUEST); 237 } 238 Set<String> servletNames = new LinkedHashSet<>(); 239 for (ServletRegistrationBean<?> servletRegistrationBean : this.servletRegistrationBeans) { 240 servletNames.add(servletRegistrationBean.getServletName()); 241 } 242 servletNames.addAll(this.servletNames); 243 if (servletNames.isEmpty() && this.urlPatterns.isEmpty()) { 244 registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter, 245 DEFAULT_URL_MAPPINGS); 246 } 247 else { 248 if (!servletNames.isEmpty()) { 249 registration.addMappingForServletNames(dispatcherTypes, this.matchAfter, 250 StringUtils.toStringArray(servletNames)); 251 } 252 if (!this.urlPatterns.isEmpty()) { 253 registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter, 254 StringUtils.toStringArray(this.urlPatterns)); 255 } 256 } 257 } 258 259 /** 260 * Return the {@link Filter} to be registered. 261 * @return the filter 262 */ 263 public abstract T getFilter(); 264 265 @Override 266 public String toString() { 267 StringBuilder builder = new StringBuilder(getOrDeduceName(this)); 268 if (this.servletNames.isEmpty() && this.urlPatterns.isEmpty()) { 269 builder.append(" urls=").append(Arrays.toString(DEFAULT_URL_MAPPINGS)); 270 } 271 else { 272 if (!this.servletNames.isEmpty()) { 273 builder.append(" servlets=").append(this.servletNames); 274 } 275 if (!this.urlPatterns.isEmpty()) { 276 builder.append(" urls=").append(this.urlPatterns); 277 } 278 } 279 return builder.toString(); 280 } 281 282}