Rossen Stoyanchev
14 years ago
4 changed files with 371 additions and 32 deletions
@ -0,0 +1,158 @@
@@ -0,0 +1,158 @@
|
||||
/* |
||||
* Copyright 2002-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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.web.servlet.config; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder; |
||||
import org.springframework.beans.factory.parsing.ProblemCollector; |
||||
import org.springframework.context.config.AbstractFeatureSpecification; |
||||
import org.springframework.context.config.FeatureSpecificationExecutor; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.web.context.request.WebRequestInterceptor; |
||||
import org.springframework.web.servlet.HandlerInterceptor; |
||||
import org.springframework.web.servlet.handler.MappedInterceptor; |
||||
|
||||
/** |
||||
* Specifies the Spring MVC "interceptors" container feature. The feature |
||||
* registers one or more {@link MappedInterceptor} bean definitions. A |
||||
* MappedInterceptor encapsulates an interceptor and one or more (optional) |
||||
* path patterns to which the interceptor is mapped. The interceptor can be |
||||
* of type {@link HandlerInterceptor} or {@link WebRequestInterceptor}. |
||||
* An interceptor can also be provided without path patterns in which case |
||||
* it applies globally to all handler invocations. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 3.1 |
||||
*/ |
||||
public class MvcInterceptors extends AbstractFeatureSpecification { |
||||
|
||||
private static final Class<? extends FeatureSpecificationExecutor> EXECUTOR_TYPE = MvcInterceptorsExecutor.class; |
||||
|
||||
private Map<Object, String[]> interceptorMappings = new LinkedHashMap<Object, String[]>(); |
||||
|
||||
/** |
||||
* Creates an MvcInterceptors instance. |
||||
*/ |
||||
public MvcInterceptors() { |
||||
super(EXECUTOR_TYPE); |
||||
} |
||||
|
||||
/** |
||||
* Add one or more {@link HandlerInterceptor HandlerInterceptors} that should |
||||
* intercept all handler invocations. |
||||
* |
||||
* @param interceptors one or more interceptors |
||||
*/ |
||||
public MvcInterceptors globalInterceptors(HandlerInterceptor... interceptors) { |
||||
addInterceptorMappings(null, interceptors); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add one or more {@link WebRequestInterceptor WebRequestInterceptors} that should |
||||
* intercept all handler invocations. |
||||
* |
||||
* @param interceptors one or more interceptors |
||||
*/ |
||||
public MvcInterceptors globalInterceptors(WebRequestInterceptor... interceptors) { |
||||
addInterceptorMappings(null, interceptors); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add one or more interceptors by bean name that should intercept all handler |
||||
* invocations. |
||||
* |
||||
* @param interceptors interceptor bean names |
||||
*/ |
||||
public MvcInterceptors globalInterceptors(String... interceptors) { |
||||
addInterceptorMappings(null, interceptors); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add one or more {@link HandlerInterceptor HandlerInterceptors} and map |
||||
* them to the specified path patterns. |
||||
* |
||||
* @param pathPatterns the pathPatterns to map the interceptor to |
||||
* @param interceptors the interceptors |
||||
*/ |
||||
public MvcInterceptors mappedInterceptors(String[] pathPatterns, HandlerInterceptor... interceptors) { |
||||
addInterceptorMappings(pathPatterns, interceptors); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add one or more {@link WebRequestInterceptor WebRequestInterceptors} and |
||||
* map them to the specified path patterns. |
||||
* |
||||
* @param pathPatterns the pathPatterns to map the interceptor to |
||||
* @param interceptors the interceptors |
||||
*/ |
||||
public MvcInterceptors mappedInterceptors(String[] pathPatterns, WebRequestInterceptor... interceptors) { |
||||
addInterceptorMappings(pathPatterns, interceptors); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Add one or more interceptors by bean name and map them to the specified |
||||
* path patterns. |
||||
* |
||||
* @param pathPatterns the pathPatterns to map to |
||||
* @param interceptors the interceptors |
||||
*/ |
||||
public MvcInterceptors mappedInterceptors(String[] pathPatterns, String... interceptors) { |
||||
addInterceptorMappings(pathPatterns, interceptors); |
||||
return this; |
||||
} |
||||
|
||||
void interceptor(String[] pathPatterns, BeanDefinitionHolder interceptor) { |
||||
addInterceptorMappings(pathPatterns, new Object[] { interceptor }); |
||||
} |
||||
|
||||
Map<Object, String[]> interceptorMappings() { |
||||
return Collections.unmodifiableMap(interceptorMappings); |
||||
} |
||||
|
||||
private void addInterceptorMappings(String[] pathPatterns, Object[] interceptors) { |
||||
for (Object interceptor : interceptors) { |
||||
interceptorMappings.put(interceptor, pathPatterns); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected void doValidate(ProblemCollector problems) { |
||||
if (interceptorMappings.size() == 0) { |
||||
problems.error("No interceptors defined."); |
||||
} |
||||
for (Object interceptor : interceptorMappings.keySet()) { |
||||
if (interceptor == null) { |
||||
problems.error("Null interceptor provided."); |
||||
} |
||||
if (interceptorMappings.get(interceptor) != null) { |
||||
for (String pattern : interceptorMappings.get(interceptor)) { |
||||
if (!StringUtils.hasText(pattern)) { |
||||
problems.error("Empty path pattern specified for " + interceptor); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
/* |
||||
* Copyright 2002-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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.web.servlet.config; |
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition; |
||||
import org.springframework.beans.factory.parsing.ComponentRegistrar; |
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition; |
||||
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||
import org.springframework.context.config.AbstractSpecificationExecutor; |
||||
import org.springframework.context.config.SpecificationContext; |
||||
import org.springframework.web.servlet.handler.MappedInterceptor; |
||||
|
||||
/** |
||||
* Executes {@link MvcInterceptors} specification, creating and registering |
||||
* bean definitions as appropriate based on the configuration within. |
||||
* |
||||
* @author Keith Donald |
||||
* @author Rossen Stoyanchev |
||||
* |
||||
* @since 3.1 |
||||
*/ |
||||
final class MvcInterceptorsExecutor extends AbstractSpecificationExecutor<MvcInterceptors> { |
||||
|
||||
@Override |
||||
protected void doExecute(MvcInterceptors spec, SpecificationContext specContext) { |
||||
ComponentRegistrar registrar = specContext.getRegistrar(); |
||||
Object source = spec.source(); |
||||
|
||||
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(spec.sourceName(), source); |
||||
|
||||
for (Object interceptor : spec.interceptorMappings().keySet()) { |
||||
RootBeanDefinition beanDef = new RootBeanDefinition(MappedInterceptor.class); |
||||
beanDef.setSource(source); |
||||
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); |
||||
beanDef.getConstructorArgumentValues().addIndexedArgumentValue(0, |
||||
spec.interceptorMappings().get(interceptor)); |
||||
beanDef.getConstructorArgumentValues().addIndexedArgumentValue(1, interceptor); |
||||
|
||||
String beanName = registrar.registerWithGeneratedName(beanDef); |
||||
compDefinition.addNestedComponent(new BeanComponentDefinition(beanDef, beanName)); |
||||
} |
||||
|
||||
registrar.registerComponent(compDefinition); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,126 @@
@@ -0,0 +1,126 @@
|
||||
/* |
||||
* Copyright 2002-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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.web.servlet.config; |
||||
|
||||
import static org.easymock.EasyMock.capture; |
||||
import static org.easymock.EasyMock.createMock; |
||||
import static org.easymock.EasyMock.replay; |
||||
import static org.junit.Assert.assertArrayEquals; |
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
import static org.junit.Assert.assertNull; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
import org.easymock.Capture; |
||||
import org.junit.Test; |
||||
import org.springframework.beans.factory.parsing.Problem; |
||||
import org.springframework.beans.factory.parsing.ProblemReporter; |
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||
import org.springframework.context.annotation.Feature; |
||||
import org.springframework.context.annotation.FeatureConfiguration; |
||||
import org.springframework.web.servlet.HandlerInterceptor; |
||||
import org.springframework.web.servlet.handler.MappedInterceptor; |
||||
import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor; |
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; |
||||
import org.springframework.web.servlet.theme.ThemeChangeInterceptor; |
||||
|
||||
/** |
||||
* Test fixture for {@link MvcInterceptors}. |
||||
* @author Rossen Stoyanchev |
||||
*/ |
||||
public class MvcInterceptorsTests { |
||||
|
||||
@Test |
||||
public void testInterceptors() { |
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); |
||||
ctx.register(MvcInterceptorsFeature.class); |
||||
ctx.refresh(); |
||||
|
||||
Iterator<MappedInterceptor> itr = ctx.getBeansOfType(MappedInterceptor.class).values().iterator(); |
||||
|
||||
MappedInterceptor interceptor = itr.next(); |
||||
assertTrue(interceptor.getInterceptor() instanceof UserRoleAuthorizationInterceptor); |
||||
assertNull(interceptor.getPathPatterns()); |
||||
|
||||
interceptor = itr.next(); |
||||
assertTrue(interceptor.getInterceptor() instanceof LocaleChangeInterceptor); |
||||
assertArrayEquals(new String[] { "/locale", "/locale/**" }, interceptor.getPathPatterns()); |
||||
|
||||
interceptor = itr.next(); |
||||
assertTrue(interceptor.getInterceptor() instanceof ThemeChangeInterceptor); |
||||
assertArrayEquals(new String[] { "/theme", "/theme/**" }, interceptor.getPathPatterns()); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void validateNoInterceptors() { |
||||
ProblemReporter reporter = createMock(ProblemReporter.class); |
||||
Capture<Problem> captured = new Capture<Problem>(); |
||||
reporter.error(capture(captured)); |
||||
replay(reporter); |
||||
|
||||
boolean result = new MvcInterceptors().validate(reporter); |
||||
|
||||
assertFalse(result); |
||||
assertEquals("No interceptors defined.", captured.getValue().getMessage()); |
||||
} |
||||
|
||||
@Test |
||||
public void validateNullHandler() { |
||||
ProblemReporter reporter = createMock(ProblemReporter.class); |
||||
Capture<Problem> captured = new Capture<Problem>(); |
||||
reporter.error(capture(captured)); |
||||
replay(reporter); |
||||
|
||||
HandlerInterceptor[] interceptors = new HandlerInterceptor[] { null }; |
||||
boolean result = new MvcInterceptors().globalInterceptors(interceptors).validate(reporter); |
||||
|
||||
assertFalse(result); |
||||
assertTrue(captured.getValue().getMessage().contains("Null interceptor")); |
||||
} |
||||
|
||||
@Test |
||||
public void validateEmptyPath() { |
||||
ProblemReporter reporter = createMock(ProblemReporter.class); |
||||
Capture<Problem> captured = new Capture<Problem>(); |
||||
reporter.error(capture(captured)); |
||||
replay(reporter); |
||||
|
||||
HandlerInterceptor[] interceptors = new HandlerInterceptor[] { new LocaleChangeInterceptor() }; |
||||
String[] patterns = new String[] { "" }; |
||||
boolean result = new MvcInterceptors().mappedInterceptors(patterns, interceptors).validate(reporter); |
||||
|
||||
assertFalse(result); |
||||
assertTrue(captured.getValue().getMessage().startsWith("Empty path pattern specified for ")); |
||||
} |
||||
|
||||
@FeatureConfiguration |
||||
private static class MvcInterceptorsFeature { |
||||
|
||||
@SuppressWarnings("unused") |
||||
@Feature |
||||
public MvcInterceptors interceptors() { |
||||
return new MvcInterceptors() |
||||
.globalInterceptors(new UserRoleAuthorizationInterceptor()) |
||||
.mappedInterceptors(new String[] { "/locale", "/locale/**" }, new LocaleChangeInterceptor()) |
||||
.mappedInterceptors(new String[] { "/theme", "/theme/**"}, new ThemeChangeInterceptor()); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue