Browse Source

Introduce DelegatingFilterProxy constructors

Issue: SPR-7672
pull/7/head
Chris Beams 14 years ago
parent
commit
948aa4f589
  1. 147
      org.springframework.web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java
  2. 126
      org.springframework.web/src/test/java/org/springframework/web/filter/DelegatingFilterProxyTests.java

147
org.springframework.web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java

@ -23,6 +23,8 @@ import javax.servlet.ServletException; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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);

126
org.springframework.web/src/test/java/org/springframework/web/filter/DelegatingFilterProxyTests.java

@ -1,4 +1,6 @@ @@ -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; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -120,6 +237,7 @@ public class DelegatingFilterProxyTests extends TestCase {
assertNull(targetFilter.filterConfig);
}
@Test
public void testDelegatingFilterProxyWithTargetFilterLifecycle() throws ServletException, IOException {
ServletContext sc = new MockServletContext();

Loading…
Cancel
Save