Skip to content

Commit 908d370

Browse files
author
Rob Winch
committed
DelegatingFilterProxy looks at "registered" WebApplicationContexts
Previously when users registered an additional Filter in the DispatcherServlet the DelegatingFilterProxy would not find it unless the context attribute was set. The value for which was difficult to remember and added quite a bit of additional "if" statements to setting up Spring Security successfully. This change allows registering additional known WebApplicationContext instances. The DispatcherServlet uses this mechanism to register its context. With that change DelegatingFilterProxy searches for the first registered WebApplicationContext that contains the bean name. This change also sets up the ability for Spring Security to lookup Beans defined in the child context within the Tag libs. Issue: SPR-13191
1 parent cd9b390 commit 908d370

File tree

7 files changed

+365
-6
lines changed

7 files changed

+365
-6
lines changed

spring-web/src/main/java/org/springframework/web/context/support/WebApplicationContextUtils.java

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,9 +17,12 @@
1717
package org.springframework.web.context.support;
1818

1919
import java.io.Serializable;
20+
import java.util.ArrayList;
2021
import java.util.Collections;
2122
import java.util.Enumeration;
2223
import java.util.HashMap;
24+
import java.util.LinkedHashSet;
25+
import java.util.List;
2326
import java.util.Map;
2427
import javax.faces.context.ExternalContext;
2528
import javax.faces.context.FacesContext;
@@ -55,6 +58,7 @@
5558
* This helper class is just the most generic way to access the root context.
5659
*
5760
* @author Juergen Hoeller
61+
* @author Rob Winch
5862
* @see org.springframework.web.context.ContextLoader
5963
* @see org.springframework.web.servlet.FrameworkServlet
6064
* @see org.springframework.web.servlet.DispatcherServlet
@@ -63,6 +67,13 @@
6367
*/
6468
public abstract class WebApplicationContextUtils {
6569

70+
/**
71+
* The attribute that all attribute names for all registered WebApplicationContext is
72+
* stored. This only includes WebApplicationContext that are stored using
73+
* registerWebApplicationContext
74+
*/
75+
private static final String APPLICATION_CONTEXT_ATTRIBUTES_ATTRIBUTE = WebApplicationContextUtils.class.getName().concat(".APPLICATION_CONTEXT_ATTRIBUTES_ATTRIBUTE");
76+
6677
private static final boolean jsfPresent =
6778
ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
6879

@@ -125,6 +136,63 @@ public static WebApplicationContext getWebApplicationContext(ServletContext sc,
125136
return (WebApplicationContext) attr;
126137
}
127138

139+
/**
140+
* Register a custom {@link WebApplicationContext} for this web app.
141+
* @param sc ServletContext to find the web application context for
142+
* @param attrName the name of the ServletContext attribute to use
143+
* @param context the desired WebApplicationContext to store
144+
* @since 4.2
145+
*/
146+
public static void registerWebApplicationContext(ServletContext sc, String attrName, WebApplicationContext context) {
147+
Assert.notNull(sc, "ServletContext must not be null");
148+
Assert.notNull(attrName, "attrName must not be null");
149+
Assert.notNull(context, "WebApplicationContext must not be null");
150+
151+
sc.setAttribute(attrName, context);
152+
153+
@SuppressWarnings("unchecked")
154+
LinkedHashSet<String> attrNames = (LinkedHashSet<String>) sc.getAttribute(APPLICATION_CONTEXT_ATTRIBUTES_ATTRIBUTE);
155+
if (attrNames == null) {
156+
attrNames = new LinkedHashSet<String>();
157+
}
158+
159+
attrNames.add(attrName);
160+
sc.setAttribute(APPLICATION_CONTEXT_ATTRIBUTES_ATTRIBUTE, attrNames);
161+
}
162+
163+
/**
164+
* Gets all the known {@link WebApplicationContext} for this web app. The order is the
165+
* root context (if specified) followed by any context registered using
166+
* registerWebApplicationContext in the order they were registered.
167+
*
168+
* @param sc ServletContext to find the web application context for. Cannot be null.
169+
* @return the known {@link WebApplicationContext} for this web app. Cannot be null,
170+
* but may be empty.
171+
* @since 4.2
172+
*/
173+
public static List<WebApplicationContext> getRegisteredWebApplicationContexts(ServletContext sc) {
174+
Assert.notNull(sc, "ServletContext must not be null");
175+
176+
List<WebApplicationContext> result = new ArrayList<WebApplicationContext>();
177+
178+
WebApplicationContext root = getWebApplicationContext(sc);
179+
if (root != null) {
180+
result.add(root);
181+
}
182+
183+
@SuppressWarnings("unchecked")
184+
LinkedHashSet<String> attrNames = (LinkedHashSet<String>) sc.getAttribute(APPLICATION_CONTEXT_ATTRIBUTES_ATTRIBUTE);
185+
if (attrNames == null) {
186+
return result;
187+
}
188+
189+
for (String attrName : attrNames) {
190+
WebApplicationContext context = getWebApplicationContext(sc, attrName);
191+
result.add(context);
192+
}
193+
194+
return result;
195+
}
128196

129197
/**
130198
* Register web-specific scopes ("request", "session", "globalSession")

spring-web/src/main/java/org/springframework/web/filter/DelegatingFilterProxy.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.web.filter;
1818

1919
import java.io.IOException;
20+
import java.util.List;
2021
import javax.servlet.Filter;
2122
import javax.servlet.FilterChain;
2223
import javax.servlet.ServletException;
@@ -66,6 +67,7 @@
6667
* @author Juergen Hoeller
6768
* @author Sam Brannen
6869
* @author Chris Beams
70+
* @author Rob Winch
6971
* @since 1.2
7072
* @see #setTargetBeanName
7173
* @see #setTargetFilterLifecycle
@@ -275,7 +277,9 @@ public void destroy() {
275277
* Otherwise, attempt to retrieve a {@code WebApplicationContext} from the
276278
* {@code ServletContext} attribute with the {@linkplain #setContextAttribute
277279
* configured name} if set. Otherwise look up a {@code WebApplicationContext} under
278-
* the well-known "root" application context attribute. The
280+
* the well-known "root" application context attribute. If no "root" application
281+
* context exists or the bean name is undefined in the "root", then the first "registered"
282+
* application context that contains the bean name is used. The
279283
* {@code WebApplicationContext} must have already been loaded and stored in the
280284
* {@code ServletContext} before this filter gets initialized (or invoked).
281285
* <p>Subclasses may override this method to provide a different
@@ -301,9 +305,14 @@ protected WebApplicationContext findWebApplicationContext() {
301305
if (attrName != null) {
302306
return WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
303307
}
304-
else {
305-
return WebApplicationContextUtils.getWebApplicationContext(getServletContext());
308+
309+
List<WebApplicationContext> registered = WebApplicationContextUtils.getRegisteredWebApplicationContexts(getServletContext());
310+
for (WebApplicationContext context : registered) {
311+
if (context.containsBean(targetBeanName)) {
312+
return context;
313+
}
306314
}
315+
return null;
307316
}
308317

309318
/**
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright 2002-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package org.springframework.web.context.support;
17+
18+
import java.util.Arrays;
19+
import java.util.Collections;
20+
21+
import static org.junit.Assert.*;
22+
import org.junit.Before;
23+
import org.junit.Test;
24+
25+
import org.springframework.mock.web.test.MockServletContext;
26+
import org.springframework.web.context.WebApplicationContext;
27+
28+
/**
29+
* @author Rob Winch
30+
*/
31+
public class WebApplicationContextUtilsTests {
32+
private MockServletContext sc;
33+
34+
private String attrName;
35+
private String attrName2;
36+
37+
private AnnotationConfigWebApplicationContext rootContext;
38+
private AnnotationConfigWebApplicationContext context;
39+
private AnnotationConfigWebApplicationContext context2;
40+
41+
@Before
42+
public void setup() {
43+
sc = new MockServletContext();
44+
attrName = "attrName";
45+
attrName2 = "attrName2";
46+
rootContext = new AnnotationConfigWebApplicationContext();
47+
context = new AnnotationConfigWebApplicationContext();
48+
context2 = new AnnotationConfigWebApplicationContext();
49+
}
50+
51+
@Test(expected = IllegalArgumentException.class)
52+
public void registerWebApplicationContextNullSc() {
53+
WebApplicationContextUtils.registerWebApplicationContext(null, attrName, context);
54+
}
55+
56+
@Test(expected = IllegalArgumentException.class)
57+
public void registerWebApplicationContextNullAttrName() {
58+
WebApplicationContextUtils.registerWebApplicationContext(sc, null, context);
59+
}
60+
61+
@Test(expected = IllegalArgumentException.class)
62+
public void registerWebApplicationContextNullContext() {
63+
WebApplicationContextUtils.registerWebApplicationContext(sc, attrName, null);
64+
}
65+
66+
@Test
67+
public void registerWebApplicationContextNoRoot() {
68+
WebApplicationContextUtils.registerWebApplicationContext(sc, attrName, context);
69+
70+
assertEquals(Arrays.asList(context),
71+
WebApplicationContextUtils.getRegisteredWebApplicationContexts(sc));
72+
}
73+
74+
@Test
75+
public void registerWebApplicationContextWithRoot() {
76+
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, rootContext);
77+
WebApplicationContextUtils.registerWebApplicationContext(sc, attrName, context);
78+
79+
assertEquals(Arrays.asList(rootContext, context),
80+
WebApplicationContextUtils.getRegisteredWebApplicationContexts(sc));
81+
}
82+
83+
@Test
84+
public void registerWebApplicationContextMultiChild() {
85+
WebApplicationContextUtils.registerWebApplicationContext(sc, attrName, context);
86+
WebApplicationContextUtils.registerWebApplicationContext(sc, attrName2, context2);
87+
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, rootContext);
88+
89+
assertEquals(Arrays.asList(rootContext, context, context2),
90+
WebApplicationContextUtils.getRegisteredWebApplicationContexts(sc));
91+
}
92+
93+
@Test
94+
public void registerWebApplicationContextMultiWithSameAttr() {
95+
WebApplicationContextUtils.registerWebApplicationContext(sc, attrName, context);
96+
WebApplicationContextUtils.registerWebApplicationContext(sc, attrName, context2);
97+
98+
assertEquals(Arrays.asList(context2),
99+
WebApplicationContextUtils.getRegisteredWebApplicationContexts(sc));
100+
}
101+
102+
@Test(expected = IllegalArgumentException.class)
103+
public void getRegisteredWebApplicationContextNull() {
104+
WebApplicationContextUtils.getRegisteredWebApplicationContexts(null);
105+
}
106+
107+
@Test
108+
public void getRegisteredWebApplicationContext() {
109+
assertEquals(Collections.emptyList(),
110+
WebApplicationContextUtils.getRegisteredWebApplicationContexts(sc));
111+
}
112+
}

0 commit comments

Comments
 (0)