001/*
002 * Copyright 2012-2017 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 javax.servlet.Filter;
020import javax.servlet.ServletContext;
021import javax.servlet.ServletException;
022
023import org.springframework.beans.BeansException;
024import org.springframework.context.ApplicationContext;
025import org.springframework.context.ApplicationContextAware;
026import org.springframework.util.Assert;
027import org.springframework.web.context.WebApplicationContext;
028import org.springframework.web.filter.DelegatingFilterProxy;
029
030/**
031 * A {@link ServletContextInitializer} to register {@link DelegatingFilterProxy}s in a
032 * Servlet 3.0+ container. Similar to the {@link ServletContext#addFilter(String, Filter)
033 * registration} features provided by {@link ServletContext} but with a Spring Bean
034 * friendly design.
035 * <p>
036 * The bean name of the actual delegate {@link Filter} should be specified using the
037 * {@code targetBeanName} constructor argument. Unlike the {@link FilterRegistrationBean},
038 * referenced filters are not instantiated early. In fact, if the delegate filter bean is
039 * marked {@code @Lazy} it won't be instantiated at all until the filter is called.
040 * <p>
041 * Registrations can be associated with {@link #setUrlPatterns URL patterns} and/or
042 * servlets (either by {@link #setServletNames name} or via a
043 * {@link #setServletRegistrationBeans ServletRegistrationBean}s. When no URL pattern or
044 * servlets are specified the filter will be associated to '/*'. The targetBeanName will
045 * be used as the filter name if not otherwise specified.
046 *
047 * @author Phillip Webb
048 * @since 1.4.0
049 * @see ServletContextInitializer
050 * @see ServletContext#addFilter(String, Filter)
051 * @see FilterRegistrationBean
052 * @see DelegatingFilterProxy
053 */
054public class DelegatingFilterProxyRegistrationBean
055                extends AbstractFilterRegistrationBean<DelegatingFilterProxy>
056                implements ApplicationContextAware {
057
058        private ApplicationContext applicationContext;
059
060        private final String targetBeanName;
061
062        /**
063         * Create a new {@link DelegatingFilterProxyRegistrationBean} instance to be
064         * registered with the specified {@link ServletRegistrationBean}s.
065         * @param targetBeanName name of the target filter bean to look up in the Spring
066         * application context (must not be {@code null}).
067         * @param servletRegistrationBeans associate {@link ServletRegistrationBean}s
068         */
069        public DelegatingFilterProxyRegistrationBean(String targetBeanName,
070                        ServletRegistrationBean<?>... servletRegistrationBeans) {
071                super(servletRegistrationBeans);
072                Assert.hasLength(targetBeanName, "TargetBeanName must not be null or empty");
073                this.targetBeanName = targetBeanName;
074                setName(targetBeanName);
075        }
076
077        @Override
078        public void setApplicationContext(ApplicationContext applicationContext)
079                        throws BeansException {
080                this.applicationContext = applicationContext;
081        }
082
083        protected String getTargetBeanName() {
084                return this.targetBeanName;
085        }
086
087        @Override
088        public DelegatingFilterProxy getFilter() {
089                return new DelegatingFilterProxy(this.targetBeanName,
090                                getWebApplicationContext()) {
091
092                        @Override
093                        protected void initFilterBean() throws ServletException {
094                                // Don't initialize filter bean on init()
095                        }
096
097                };
098        }
099
100        private WebApplicationContext getWebApplicationContext() {
101                Assert.notNull(this.applicationContext, "ApplicationContext be injected");
102                Assert.isInstanceOf(WebApplicationContext.class, this.applicationContext);
103                return (WebApplicationContext) this.applicationContext;
104        }
105
106}