DelegatingFilterProxy autodetects a unique DispatcherServlet context
Issue: SPR-13191
This commit is contained in:
		
							parent
							
								
									e0329306df
								
							
						
					
					
						commit
						1fcd465f2d
					
				|  | @ -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}. | ||||
| 	 * <p>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}. | ||||
| 	 * <p>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). | ||||
| 	 * <p>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<String> 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") | ||||
|  |  | |||
|  | @ -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()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 { | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue