Modify <faces:resources> to add portlet variant

The ResourcesBeanDefinitionParser will now automatically register an
additional portlet resource resolver when a portlet environment and
and relevant Spring portlet classes are detected.

Issues: SWF-1500
This commit is contained in:
Phillip Webb
2012-06-14 12:21:13 -07:00
committed by Rossen Stoyanchev
parent c5471f4403
commit d904786083
3 changed files with 105 additions and 36 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2008 the original author or authors.
* Copyright 2004-2012 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.faces.config;
import java.util.Map;
@@ -22,6 +23,7 @@ import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.faces.webflow.JsfRuntimeInformation;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
@@ -31,51 +33,98 @@ import org.w3c.dom.Element;
* Parser for the resources tag.
*
* @author Rossen Stoyanchev
* @author Phillip Webb
* @since 2.2.0
*/
public class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
static final String RESOURCE_HANDLER_BEAN_NAME = "jsfResourceRequestHandler";
static final String RESOURCE_HANDLER_CLASS_NAME = "org.springframework.faces.webflow.JsfResourceRequestHandler";
static final String SERVLET_RESOURCE_HANDLER_BEAN_NAME = "jsfResourceRequestHandler";
static final String PORTLET_RESOURCE_HANDLER_BEAN_NAME = "jsfPortletResourceRequestHandler";
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
registerHandlerAdapterIfNecessary(parserContext, source);
registerResourceHandler(parserContext, source);
registerHandlerMappings(element, parserContext, source);
new ServletRegistrar(element, parserContext).register();
if (JsfRuntimeInformation.isSpringPortletPresent()) {
new PortletRegistrar(element, parserContext).register();
}
return null;
}
private void registerHandlerMappings(Element element, ParserContext parserContext, Object source) {
Map<String, String> urlMap = new ManagedMap<String, String>();
urlMap.put("/javax.faces.resource/**", RESOURCE_HANDLER_BEAN_NAME);
private static abstract class Registrar {
RootBeanDefinition beanDefinition = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
beanDefinition.getPropertyValues().add("urlMap", urlMap);
protected final Element element;
String order = element.getAttribute("order");
beanDefinition.getPropertyValues().add("order", StringUtils.hasText(order) ? order : 0);
parserContext.getReaderContext().registerWithGeneratedName(beanDefinition);
}
protected final ParserContext parserContext;
private void registerResourceHandler(ParserContext parserContext, Object source) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(RESOURCE_HANDLER_CLASS_NAME);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.getRegistry().registerBeanDefinition(RESOURCE_HANDLER_BEAN_NAME, beanDefinition);
}
protected final Object source;
private void registerHandlerAdapterIfNecessary(ParserContext parserContext, Object source) {
if (parserContext.getRegistry().containsBeanDefinition(
"org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter")) {
return;
public Registrar(Element element, ParserContext parserContext) {
this.element = element;
this.parserContext = parserContext;
this.source = parserContext.extractSource(element);
}
public abstract void register();
}
private static class ServletRegistrar extends Registrar {
public ServletRegistrar(Element element, ParserContext parserContext) {
super(element, parserContext);
}
@Override
public void register() {
registerHandlerAdapterIfNecessary();
registerResourceHandler();
registerHandlerMappings();
}
private void registerHandlerAdapterIfNecessary() {
if (parserContext.getRegistry().containsBeanDefinition("org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter")) {
return;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(HttpRequestHandlerAdapter.class);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.getReaderContext().registerWithGeneratedName(beanDefinition);
}
private void registerResourceHandler() {
RootBeanDefinition beanDefinition = new RootBeanDefinition("org.springframework.faces.webflow.JsfResourceRequestHandler");
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.getRegistry().registerBeanDefinition(SERVLET_RESOURCE_HANDLER_BEAN_NAME, beanDefinition);
}
private void registerHandlerMappings() {
Map<String, String> urlMap = new ManagedMap<String, String>();
urlMap.put("/javax.faces.resource/**", SERVLET_RESOURCE_HANDLER_BEAN_NAME);
RootBeanDefinition beanDefinition = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
beanDefinition.getPropertyValues().add("urlMap", urlMap);
String order = element.getAttribute("order");
beanDefinition.getPropertyValues().add("order", StringUtils.hasText(order) ? order : 0);
parserContext.getReaderContext().registerWithGeneratedName(beanDefinition);
}
}
private static class PortletRegistrar extends Registrar {
public PortletRegistrar(Element element, ParserContext parserContext) {
super(element, parserContext);
}
@Override
public void register() {
RootBeanDefinition beanDefinition = new RootBeanDefinition("org.springframework.faces.webflow.context.portlet.JsfResourceRequestHandler");
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.getRegistry().registerBeanDefinition(PORTLET_RESOURCE_HANDLER_BEAN_NAME, beanDefinition);
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(HttpRequestHandlerAdapter.class);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.getReaderContext().registerWithGeneratedName(beanDefinition);
}
}

View File

@@ -42,7 +42,13 @@ public class JsfRuntimeInformation {
private static final int jsfVersion;
private static final boolean myFacesPresent = ClassUtils.isPresent("org.apache.myfaces.webapp.MyFacesServlet", JsfUtils.class.getClassLoader());
private static final ClassLoader CLASS_LOADER = JsfUtils.class.getClassLoader();
private static final boolean myFacesPresent = ClassUtils.isPresent("org.apache.myfaces.webapp.MyFacesServlet", CLASS_LOADER);
private static boolean portletPresent = ClassUtils.isPresent("javax.portlet.Portlet", CLASS_LOADER);
private static boolean springPortletPresent = ClassUtils.isPresent("org.springframework.web.portlet.DispatcherPortlet", CLASS_LOADER);
static {
if (ReflectionUtils.findMethod(FacesContext.class, "isPostback") != null) {
@@ -82,6 +88,15 @@ public class JsfRuntimeInformation {
return myFacesPresent;
}
/**
* Determines if the container has support for portlets and if Spring MVC portlet support is available
*
* @return <tt>true</tt> if a portlet environment is detected
*/
public static boolean isSpringPortletPresent() {
return portletPresent && springPortletPresent;
}
/**
* Determine if the specified {@link FacesContext} is from a portlet request.
*

View File

@@ -24,16 +24,21 @@ public class ResourcesBeanDefinitionParserTests extends TestCase {
Map<String, ?> map = this.context.getBeansOfType(HttpRequestHandlerAdapter.class);
assertEquals(1, map.values().size());
Object resourceHandler = this.context.getBean(ResourcesBeanDefinitionParser.RESOURCE_HANDLER_BEAN_NAME);
Object resourceHandler = this.context.getBean(ResourcesBeanDefinitionParser.SERVLET_RESOURCE_HANDLER_BEAN_NAME);
assertNotNull(resourceHandler);
assertTrue(resourceHandler instanceof JsfResourceRequestHandler);
map = this.context.getBeansOfType(SimpleUrlHandlerMapping.class);
assertEquals(1, map.values().size());
SimpleUrlHandlerMapping handlerMapping = (SimpleUrlHandlerMapping) map.values().iterator().next();
assertEquals(ResourcesBeanDefinitionParser.RESOURCE_HANDLER_BEAN_NAME,
assertEquals(ResourcesBeanDefinitionParser.SERVLET_RESOURCE_HANDLER_BEAN_NAME,
handlerMapping.getUrlMap().get("/javax.faces.resource/**"));
assertEquals(0, handlerMapping.getOrder());
}
public void testConfigurePortlet() {
Object resourceHandler = this.context.getBean(ResourcesBeanDefinitionParser.PORTLET_RESOURCE_HANDLER_BEAN_NAME);
assertNotNull(resourceHandler);
assertTrue(resourceHandler instanceof org.springframework.faces.webflow.context.portlet.JsfResourceRequestHandler);
}
}