diff --git a/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationContextUtils.java b/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationContextUtils.java
index 725dc9b197..ae75fbe4e8 100644
--- a/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationContextUtils.java
+++ b/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationContextUtils.java
@@ -68,7 +68,7 @@ public abstract class WebApplicationContextUtils {
/**
- * Find the root {@link WebApplicationContext} for this web app, typically
+ * Find the root {@code WebApplicationContext} for this web app, typically
* loaded via {@link org.springframework.web.context.ContextLoaderListener}.
*
Will rethrow an exception that happened on root context startup,
* to differentiate between a failed context startup and no context at all.
@@ -86,7 +86,7 @@ public abstract class WebApplicationContextUtils {
}
/**
- * Find the root {@link WebApplicationContext} for this web app, typically
+ * Find the root {@code WebApplicationContext} for this web app, typically
* loaded via {@link org.springframework.web.context.ContextLoaderListener}.
*
Will rethrow an exception that happened on root context startup,
* to differentiate between a failed context startup and no context at all.
@@ -99,7 +99,7 @@ public abstract class WebApplicationContextUtils {
}
/**
- * Find a custom {@link WebApplicationContext} for this web app.
+ * Find a custom {@code WebApplicationContext} for this web app.
* @param sc ServletContext to find the web application context for
* @param attrName the name of the ServletContext attribute to look for
* @return the desired WebApplicationContext for this web app, or {@code null} if none
@@ -125,6 +125,40 @@ public abstract class WebApplicationContextUtils {
return (WebApplicationContext) attr;
}
+ /**
+ * Find a unique {@code WebApplicationContext} for this web app: either the
+ * root web app context (preferred) or a unique {@code WebApplicationContext}
+ * among the registered {@code ServletContext} attributes (typically coming
+ * from a single {@code DispatcherServlet} in the current web application).
+ *
Note that {@code DispatcherServlet}'s exposure of its context can be
+ * controlled through its {@code publishContext} property, which is {@code true}
+ * by default but can be selectively switched to only publish a single context
+ * despite multiple {@code DispatcherServlet} registrations in the web app.
+ * @param sc ServletContext to find the web application context for
+ * @return the desired WebApplicationContext for this web app, or {@code null} if none
+ * @since 4.2
+ * @see #getWebApplicationContext(ServletContext)
+ * @see ServletContext#getAttributeNames()
+ */
+ public static WebApplicationContext findWebApplicationContext(ServletContext sc) {
+ WebApplicationContext wac = getWebApplicationContext(sc);
+ if (wac == null) {
+ Enumeration attrNames = sc.getAttributeNames();
+ while (attrNames.hasMoreElements()) {
+ String attrName = attrNames.nextElement();
+ Object attrValue = sc.getAttribute(attrName);
+ if (attrValue instanceof WebApplicationContext) {
+ if (wac != null) {
+ throw new IllegalStateException("No unique WebApplicationContext found: more than one " +
+ "DispatcherServlet registered with publishContext=true?");
+ }
+ wac = (WebApplicationContext) attrValue;
+ }
+ }
+ }
+ return wac;
+ }
+
/**
* Register web-specific scopes ("request", "session", "globalSession")
diff --git a/spring-web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java b/spring-web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java
index 47899bef01..ba5bb5813b 100644
--- a/spring-web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java
+++ b/spring-web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java
@@ -249,7 +249,8 @@ public class DelegatingFilterProxy extends GenericFilterBean {
if (this.delegate == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
- throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
+ throw new IllegalStateException("No WebApplicationContext found: " +
+ "no ContextLoaderListener or DispatcherServlet registered?");
}
this.delegate = initDelegate(wac);
}
@@ -288,11 +289,12 @@ public class DelegatingFilterProxy extends GenericFilterBean {
*/
protected WebApplicationContext findWebApplicationContext() {
if (this.webApplicationContext != null) {
- // the user has injected a context at construction time -> use it
+ // 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();
+ ConfigurableApplicationContext cac = (ConfigurableApplicationContext) this.webApplicationContext;
+ if (!cac.isActive()) {
+ // The context has not yet been refreshed -> do so before returning it...
+ cac.refresh();
}
}
return this.webApplicationContext;
@@ -302,7 +304,7 @@ public class DelegatingFilterProxy extends GenericFilterBean {
return WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
}
else {
- return WebApplicationContextUtils.getWebApplicationContext(getServletContext());
+ return WebApplicationContextUtils.findWebApplicationContext(getServletContext());
}
}
diff --git a/spring-web/src/test/java/org/springframework/web/filter/CompositeFilterTests.java b/spring-web/src/test/java/org/springframework/web/filter/CompositeFilterTests.java
index 75a2eae17e..fc1d3e5f08 100644
--- a/spring-web/src/test/java/org/springframework/web/filter/CompositeFilterTests.java
+++ b/spring-web/src/test/java/org/springframework/web/filter/CompositeFilterTests.java
@@ -1,6 +1,5 @@
/*
- * Copyright 2004, 2005 Acegi Technology Pty Limited
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -44,9 +43,7 @@ public class CompositeFilterTests {
@Test
public void testCompositeFilter() throws ServletException, IOException {
ServletContext sc = new MockServletContext();
-
MockFilter targetFilter = new MockFilter();
-
MockFilterConfig proxyConfig = new MockFilterConfig(sc);
CompositeFilter filterProxy = new CompositeFilter();
@@ -75,7 +72,7 @@ public class CompositeFilterTests {
}
@Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) {
request.setAttribute("called", Boolean.TRUE);
}
diff --git a/spring-web/src/test/java/org/springframework/web/filter/DelegatingFilterProxyTests.java b/spring-web/src/test/java/org/springframework/web/filter/DelegatingFilterProxyTests.java
index e68581d07b..8dc6724132 100644
--- a/spring-web/src/test/java/org/springframework/web/filter/DelegatingFilterProxyTests.java
+++ b/spring-web/src/test/java/org/springframework/web/filter/DelegatingFilterProxyTests.java
@@ -1,6 +1,5 @@
/*
- * Copyright 2004, 2005 Acegi Technology Pty Limited
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -40,6 +39,7 @@ import static org.junit.Assert.*;
/**
* @author Juergen Hoeller
* @author Chris Beams
+ * @author Rob Winch
* @since 08.05.2005
*/
public class DelegatingFilterProxyTests {
@@ -268,6 +268,128 @@ public class DelegatingFilterProxyTests {
assertNull(targetFilter.filterConfig);
}
+ @Test
+ public void testDelegatingFilterProxyWithFrameworkServletContext() throws ServletException, IOException {
+ ServletContext sc = new MockServletContext();
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ wac.setServletContext(sc);
+ wac.registerSingleton("targetFilter", MockFilter.class);
+ wac.refresh();
+ sc.setAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher", wac);
+
+ MockFilter targetFilter = (MockFilter) wac.getBean("targetFilter");
+
+ MockFilterConfig proxyConfig = new MockFilterConfig(sc);
+ proxyConfig.addInitParameter("targetBeanName", "targetFilter");
+ 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 testDelegatingFilterProxyInjectedPreferred() throws ServletException, IOException {
+ ServletContext sc = new MockServletContext();
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ wac.setServletContext(sc);
+ wac.refresh();
+ sc.setAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher", wac);
+
+ StaticWebApplicationContext injectedWac = new StaticWebApplicationContext();
+ injectedWac.setServletContext(sc);
+ String beanName = "targetFilter";
+ injectedWac.registerSingleton(beanName, MockFilter.class);
+ injectedWac.refresh();
+
+ MockFilter targetFilter = (MockFilter) injectedWac.getBean(beanName);
+
+ DelegatingFilterProxy filterProxy = new DelegatingFilterProxy(beanName, injectedWac);
+
+ 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 testDelegatingFilterProxyNotInjectedWacServletAttrPreferred() throws ServletException, IOException {
+ ServletContext sc = new MockServletContext();
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ wac.setServletContext(sc);
+ wac.refresh();
+ sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
+ sc.setAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher", wac);
+
+ StaticWebApplicationContext wacToUse = new StaticWebApplicationContext();
+ wacToUse.setServletContext(sc);
+ String beanName = "targetFilter";
+ String attrName = "customAttrName";
+ wacToUse.registerSingleton(beanName, MockFilter.class);
+ wacToUse.refresh();
+ sc.setAttribute(attrName, wacToUse);
+
+ MockFilter targetFilter = (MockFilter) wacToUse.getBean(beanName);
+
+ DelegatingFilterProxy filterProxy = new DelegatingFilterProxy(beanName);
+ filterProxy.setContextAttribute(attrName);
+ filterProxy.setServletContext(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 testDelegatingFilterProxyNotInjectedWithRootPreferred() throws ServletException, IOException {
+ ServletContext sc = new MockServletContext();
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ wac.setServletContext(sc);
+ wac.refresh();
+ sc.setAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher", wac);
+ sc.setAttribute("another", wac);
+
+ StaticWebApplicationContext wacToUse = new StaticWebApplicationContext();
+ wacToUse.setServletContext(sc);
+ String beanName = "targetFilter";
+ wacToUse.registerSingleton(beanName, MockFilter.class);
+ wacToUse.refresh();
+ sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wacToUse);
+
+ MockFilter targetFilter = (MockFilter) wacToUse.getBean(beanName);
+
+ DelegatingFilterProxy filterProxy = new DelegatingFilterProxy(beanName);
+ filterProxy.setServletContext(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);
+ }
+
public static class MockFilter implements Filter {