Introduce DelegatingFilterProxy constructors
Issue: SPR-7672
This commit is contained in:
@@ -23,6 +23,8 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
@@ -50,22 +52,38 @@ import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
* of the {@code Filter.init} and {@code Filter.destroy} lifecycle methods
|
||||
* on the target bean, letting the servlet container manage the filter lifecycle.
|
||||
*
|
||||
* <p>This class is inspired by Acegi Security's FilterToBeanProxy class,
|
||||
* written by Ben Alex.
|
||||
* <p>As of Spring 3.1, {@code DelegatingFilterProxy} has been updated to optionally accept
|
||||
* constructor parameters when using Servlet 3.0's instance-based filter registration
|
||||
* methods, usually in conjunction with Spring 3.1's
|
||||
* {@link org.springframework.web.WebApplicationInitializer} SPI. These constructors allow
|
||||
* for providing the delegate Filter bean directly, or providing the application context
|
||||
* and bean name to fetch, avoiding the need to look up the application context from the
|
||||
* ServletContext.
|
||||
*
|
||||
* <p>This class was originally inspired by Spring Security's {@code FilterToBeanProxy}
|
||||
* class, written by Ben Alex.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @author Chris Beams
|
||||
* @since 1.2
|
||||
* @see #setTargetBeanName
|
||||
* @see #setTargetFilterLifecycle
|
||||
* @see javax.servlet.Filter#doFilter
|
||||
* @see javax.servlet.Filter#init
|
||||
* @see javax.servlet.Filter#destroy
|
||||
* @see #DelegatingFilterProxy(Filter)
|
||||
* @see #DelegatingFilterProxy(String)
|
||||
* @see #DelegatingFilterProxy(String, WebApplicationContext)
|
||||
* @see javax.servlet.ServletContext#addFilter(String, Filter)
|
||||
* @see org.springframework.web.WebApplicationInitializer
|
||||
*/
|
||||
public class DelegatingFilterProxy extends GenericFilterBean {
|
||||
|
||||
private String contextAttribute;
|
||||
|
||||
private WebApplicationContext webApplicationContext;
|
||||
|
||||
private String targetBeanName;
|
||||
|
||||
private boolean targetFilterLifecycle = false;
|
||||
@@ -75,6 +93,78 @@ public class DelegatingFilterProxy extends GenericFilterBean {
|
||||
private final Object delegateMonitor = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code DelegatingFilterProxy}. For traditional (pre-Servlet 3.0) use
|
||||
* in {@code web.xml}.
|
||||
* @see #setTargetBeanName(String)
|
||||
*/
|
||||
public DelegatingFilterProxy() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code DelegatingFilterProxy} with the given {@link Filter} delegate.
|
||||
* Bypasses entirely the need for interacting with a Spring application context,
|
||||
* specifying the {@linkplain #setTargetBeanName target bean name}, etc.
|
||||
* <p>For use in Servlet 3.0+ environments where instance-based registration of
|
||||
* filters is supported.
|
||||
* @param delegate the {@code Filter} instance that this proxy will delegate to and
|
||||
* manage the lifecycle for (must not be {@code null}).
|
||||
* @see #doFilter(ServletRequest, ServletResponse, FilterChain)
|
||||
* @see #invokeDelegate(Filter, ServletRequest, ServletResponse, FilterChain)
|
||||
* @see #destroy()
|
||||
* @see #setEnvironment(org.springframework.core.env.Environment)
|
||||
*/
|
||||
public DelegatingFilterProxy(Filter delegate) {
|
||||
Assert.notNull(delegate, "delegate Filter object must not be null");
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code DelegatingFilterProxy} that will retrieve the named target
|
||||
* bean from the Spring {@code WebApplicationContext} found in the {@code ServletContext}
|
||||
* (either the 'root' application context or the context named by
|
||||
* {@link #setContextAttribute}).
|
||||
* <p>For use in Servlet 3.0+ environments where instance-based registration of
|
||||
* filters is supported.
|
||||
* <p>The target bean must implement the standard Servlet Filter.
|
||||
* @param targetBeanName name of the target filter bean to look up in the Spring
|
||||
* application context (must not be {@code null}).
|
||||
* @see #findWebApplicationContext()
|
||||
* @see #setEnvironment(org.springframework.core.env.Environment)
|
||||
*/
|
||||
public DelegatingFilterProxy(String targetBeanName) {
|
||||
this(targetBeanName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code DelegatingFilterProxy} that will retrieve the named target
|
||||
* bean from the given Spring {@code WebApplicationContext}.
|
||||
* <p>For use in Servlet 3.0+ environments where instance-based registration of
|
||||
* filters is supported.
|
||||
* <p>The target bean must implement the standard Servlet Filter interface.
|
||||
* <p>The given {@code WebApplicationContext} may or may not be refreshed when passed
|
||||
* in. If it has not, and if the context implements {@link ConfigurableApplicationContext},
|
||||
* a {@link ConfigurableApplicationContext#refresh() refresh()} will be attempted before
|
||||
* retrieving the named target bean.
|
||||
* <p>This proxy's {@code Environment} will be inherited from the given
|
||||
* {@code WebApplicationContext}.
|
||||
* @param targetBeanName name of the target filter bean in the Spring application
|
||||
* context (must not be {@code null}).
|
||||
* @param wac the application context from which the target filter will be retrieved;
|
||||
* if {@code null}, an application context will be looked up from {@code ServletContext}
|
||||
* as a fallback.
|
||||
* @see #findWebApplicationContext()
|
||||
* @see #setEnvironment(org.springframework.core.env.Environment)
|
||||
*/
|
||||
public DelegatingFilterProxy(String targetBeanName, WebApplicationContext wac) {
|
||||
Assert.hasText(targetBeanName, "target Filter bean name must not be null or empty");
|
||||
this.setTargetBeanName(targetBeanName);
|
||||
this.webApplicationContext = wac;
|
||||
if (wac != null) {
|
||||
this.setEnvironment(wac.getEnvironment());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the ServletContext attribute which should be used to retrieve the
|
||||
* {@link WebApplicationContext} from which to load the delegate {@link Filter} bean.
|
||||
@@ -131,18 +221,20 @@ public class DelegatingFilterProxy extends GenericFilterBean {
|
||||
|
||||
@Override
|
||||
protected void initFilterBean() throws ServletException {
|
||||
// If no target bean name specified, use filter name.
|
||||
if (this.targetBeanName == null) {
|
||||
this.targetBeanName = getFilterName();
|
||||
}
|
||||
|
||||
// Fetch Spring root application context and initialize the delegate early,
|
||||
// if possible. If the root application context will be started after this
|
||||
// filter proxy, we'll have to resort to lazy initialization.
|
||||
synchronized (this.delegateMonitor) {
|
||||
WebApplicationContext wac = findWebApplicationContext();
|
||||
if (wac != null) {
|
||||
this.delegate = initDelegate(wac);
|
||||
if (this.delegate == null) {
|
||||
// If no target bean name specified, use filter name.
|
||||
if (this.targetBeanName == null) {
|
||||
this.targetBeanName = getFilterName();
|
||||
}
|
||||
|
||||
// Fetch Spring root application context and initialize the delegate early,
|
||||
// if possible. If the root application context will be started after this
|
||||
// filter proxy, we'll have to resort to lazy initialization.
|
||||
WebApplicationContext wac = findWebApplicationContext();
|
||||
if (wac != null) {
|
||||
this.delegate = initDelegate(wac);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,16 +272,33 @@ public class DelegatingFilterProxy extends GenericFilterBean {
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a <code>WebApplicationContext</code> from the <code>ServletContext</code>
|
||||
* attribute with the {@link #setContextAttribute configured name}. The
|
||||
* <code>WebApplicationContext</code> must have already been loaded and stored in the
|
||||
* <code>ServletContext</code> before this filter gets initialized (or invoked).
|
||||
* Return the {@code WebApplicationContext} passed in at construction time, if available.
|
||||
* Otherwise, attempt to retrieve a {@code WebApplicationContext} from the
|
||||
* {@code ServletContext} attribute with the {@linkplain #setContextAttribute
|
||||
* configured name} if set. Otherwise look up a {@code WebApplicationContext} under
|
||||
* the well-known "root" application context attribute. The
|
||||
* {@code WebApplicationContext} must have already been loaded and stored in the
|
||||
* {@code ServletContext} before this filter gets initialized (or invoked).
|
||||
* <p>Subclasses may override this method to provide a different
|
||||
* <code>WebApplicationContext</code> retrieval strategy.
|
||||
* @return the WebApplicationContext for this proxy, or <code>null</code> if not found
|
||||
* {@code WebApplicationContext} retrieval strategy.
|
||||
* @return the {@code WebApplicationContext} for this proxy, or {@code null} if not
|
||||
* found
|
||||
* @see #DelegatingFilterProxy(String, WebApplicationContext)
|
||||
* @see #getContextAttribute()
|
||||
* @see WebApplicationContextUtils#getWebApplicationContext(javax.servlet.ServletContext)
|
||||
* @see WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
|
||||
*/
|
||||
protected WebApplicationContext findWebApplicationContext() {
|
||||
if (this.webApplicationContext != null) {
|
||||
// the user has injected a context at construction time -> use it
|
||||
if (this.webApplicationContext instanceof ConfigurableApplicationContext) {
|
||||
if (!((ConfigurableApplicationContext)this.webApplicationContext).isActive()) {
|
||||
// the context has not yet been refreshed -> do so before returning it
|
||||
((ConfigurableApplicationContext)this.webApplicationContext).refresh();
|
||||
}
|
||||
}
|
||||
return this.webApplicationContext;
|
||||
}
|
||||
String attrName = getContextAttribute();
|
||||
if (attrName != null) {
|
||||
return WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
||||
/*
|
||||
* Copyright 2004, 2005 Acegi Technology Pty Limited
|
||||
* Copyright 2006-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,8 +27,8 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockFilterConfig;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@@ -36,10 +38,12 @@ import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 08.05.2005
|
||||
*/
|
||||
public class DelegatingFilterProxyTests extends TestCase {
|
||||
public class DelegatingFilterProxyTests {
|
||||
|
||||
@Test
|
||||
public void testDelegatingFilterProxy() throws ServletException, IOException {
|
||||
ServletContext sc = new MockServletContext();
|
||||
|
||||
@@ -67,6 +71,118 @@ public class DelegatingFilterProxyTests extends TestCase {
|
||||
assertNull(targetFilter.filterConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegatingFilterProxyAndCustomContextAttribute() throws ServletException, IOException {
|
||||
ServletContext sc = new MockServletContext();
|
||||
|
||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||
wac.setServletContext(sc);
|
||||
wac.registerSingleton("targetFilter", MockFilter.class);
|
||||
wac.refresh();
|
||||
sc.setAttribute("CUSTOM_ATTR", wac);
|
||||
|
||||
MockFilter targetFilter = (MockFilter) wac.getBean("targetFilter");
|
||||
|
||||
MockFilterConfig proxyConfig = new MockFilterConfig(sc);
|
||||
proxyConfig.addInitParameter("targetBeanName", "targetFilter");
|
||||
proxyConfig.addInitParameter("contextAttribute", "CUSTOM_ATTR");
|
||||
DelegatingFilterProxy filterProxy = new DelegatingFilterProxy();
|
||||
filterProxy.init(proxyConfig);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filterProxy.doFilter(request, response, null);
|
||||
|
||||
assertNull(targetFilter.filterConfig);
|
||||
assertEquals(Boolean.TRUE, request.getAttribute("called"));
|
||||
|
||||
filterProxy.destroy();
|
||||
assertNull(targetFilter.filterConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegatingFilterProxyWithFilterDelegateInstance() throws ServletException, IOException {
|
||||
MockFilter targetFilter = new MockFilter();
|
||||
|
||||
DelegatingFilterProxy filterProxy = new DelegatingFilterProxy(targetFilter);
|
||||
filterProxy.init(new MockFilterConfig(new MockServletContext()));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filterProxy.doFilter(request, response, null);
|
||||
|
||||
assertNull(targetFilter.filterConfig);
|
||||
assertEquals(Boolean.TRUE, request.getAttribute("called"));
|
||||
|
||||
filterProxy.destroy();
|
||||
assertNull(targetFilter.filterConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegatingFilterProxyWithTargetBeanName() throws ServletException, IOException {
|
||||
MockServletContext sc = new MockServletContext();
|
||||
|
||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||
wac.setServletContext(sc);
|
||||
wac.registerSingleton("targetFilter", MockFilter.class);
|
||||
wac.refresh();
|
||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||
|
||||
MockFilter targetFilter = (MockFilter) wac.getBean("targetFilter");
|
||||
|
||||
DelegatingFilterProxy filterProxy = new DelegatingFilterProxy("targetFilter");
|
||||
filterProxy.init(new MockFilterConfig(sc));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filterProxy.doFilter(request, response, null);
|
||||
|
||||
assertNull(targetFilter.filterConfig);
|
||||
assertEquals(Boolean.TRUE, request.getAttribute("called"));
|
||||
|
||||
filterProxy.destroy();
|
||||
assertNull(targetFilter.filterConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegatingFilterProxyWithTargetBeanNameAndNotYetRefreshedApplicationContext() throws ServletException, IOException {
|
||||
MockServletContext sc = new MockServletContext();
|
||||
|
||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||
wac.setServletContext(sc);
|
||||
wac.registerSingleton("targetFilter", MockFilter.class);
|
||||
// wac.refresh();
|
||||
// note that the context is not set as the ROOT attribute in the ServletContext!
|
||||
|
||||
DelegatingFilterProxy filterProxy = new DelegatingFilterProxy("targetFilter", wac);
|
||||
filterProxy.init(new MockFilterConfig(sc));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filterProxy.doFilter(request, response, null);
|
||||
|
||||
MockFilter targetFilter = (MockFilter) wac.getBean("targetFilter");
|
||||
|
||||
assertNull(targetFilter.filterConfig);
|
||||
assertEquals(Boolean.TRUE, request.getAttribute("called"));
|
||||
|
||||
filterProxy.destroy();
|
||||
assertNull(targetFilter.filterConfig);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testDelegatingFilterProxyWithTargetBeanNameAndNoApplicationContext() throws ServletException, IOException {
|
||||
MockServletContext sc = new MockServletContext();
|
||||
|
||||
DelegatingFilterProxy filterProxy = new DelegatingFilterProxy("targetFilter", null);
|
||||
filterProxy.init(new MockFilterConfig(sc));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
filterProxy.doFilter(request, response, null); // throws
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegatingFilterProxyWithFilterName() throws ServletException, IOException {
|
||||
ServletContext sc = new MockServletContext();
|
||||
|
||||
@@ -93,6 +209,7 @@ public class DelegatingFilterProxyTests extends TestCase {
|
||||
assertNull(targetFilter.filterConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegatingFilterProxyWithLazyContextStartup() throws ServletException, IOException {
|
||||
ServletContext sc = new MockServletContext();
|
||||
|
||||
@@ -120,6 +237,7 @@ public class DelegatingFilterProxyTests extends TestCase {
|
||||
assertNull(targetFilter.filterConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegatingFilterProxyWithTargetFilterLifecycle() throws ServletException, IOException {
|
||||
ServletContext sc = new MockServletContext();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user