Remove remaining Portlet references

Issue: SWF-1692
This commit is contained in:
Rossen Stoyanchev
2017-01-06 11:58:05 -05:00
parent 5b0df65be4
commit 3a0857496e
25 changed files with 83 additions and 932 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2012 the original author or authors.
* Copyright 2004-2016 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.
@@ -18,17 +18,17 @@ package org.springframework.faces.config;
import java.util.Map;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.BeanDefinition;
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.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.w3c.dom.Element;
/**
* Parser for the resources tag.
@@ -39,101 +39,57 @@ import org.w3c.dom.Element;
*/
public class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
static final String SERVLET_RESOURCE_HANDLER_BEAN_NAME = "jsfResourceRequestHandler";
static final String PORTLET_RESOURCE_HANDLER_BEAN_NAME = "jsfPortletResourceRequestHandler";
private static final String SERVLET_RESOURCE_HANDLER_BEAN_NAME = "jsfResourceRequestHandler";
private static final boolean isRichFacesPresent =
ClassUtils.isPresent("org.richfaces.application.CoreConfiguration",
ResourcesBeanDefinitionParser.class.getClassLoader());
public BeanDefinition parse(Element element, ParserContext parserContext) {
new ServletRegistrar(element, parserContext).register();
if (JsfRuntimeInformation.isSpringPortletPresent()) {
new PortletRegistrar(element, parserContext).register();
}
Object source = parserContext.extractSource(element);
registerHandlerAdapterIfNecessary(source, parserContext);
registerResourceHandler(source, parserContext);
registerHandlerMappings(element, source, parserContext);
return null;
}
private static abstract class Registrar {
protected final Element element;
protected final ParserContext parserContext;
protected final Object source;
public Registrar(Element element, ParserContext parserContext) {
this.element = element;
this.parserContext = parserContext;
this.source = parserContext.extractSource(element);
private void registerHandlerAdapterIfNecessary(Object source, ParserContext parserContext) {
String beanName = "org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter";
if (parserContext.getRegistry().containsBeanDefinition(beanName)) {
return;
}
public abstract void register();
RootBeanDefinition beanDefinition = new RootBeanDefinition(HttpRequestHandlerAdapter.class);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.getReaderContext().registerWithGeneratedName(beanDefinition);
}
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);
if (isRichFacesPresent) {
urlMap.put("/rfRes/**", 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 void registerResourceHandler(Object source, ParserContext parserContext) {
String beanName = "org.springframework.faces.webflow.JsfResourceRequestHandler";
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanName);
beanDefinition.setSource(source);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.getRegistry().registerBeanDefinition(SERVLET_RESOURCE_HANDLER_BEAN_NAME, beanDefinition);
}
private static class PortletRegistrar extends Registrar {
private void registerHandlerMappings(Element element, Object source, ParserContext parserContext) {
Map<String, String> urlMap = new ManagedMap<String, String>();
urlMap.put("/javax.faces.resource/**", SERVLET_RESOURCE_HANDLER_BEAN_NAME);
public PortletRegistrar(Element element, ParserContext parserContext) {
super(element, parserContext);
if (isRichFacesPresent) {
urlMap.put("/rfRes/**", SERVLET_RESOURCE_HANDLER_BEAN_NAME);
}
@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(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);
}
}

View File

@@ -15,10 +15,7 @@
*/
package org.springframework.faces.mvc;
import static org.springframework.faces.webflow.JsfRuntimeInformation.isPortletRequest;
import java.util.Map;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
@@ -60,10 +57,7 @@ public class JsfView extends AbstractUrlBasedView {
JsfUtils.notifyBeforeListeners(PhaseId.RESTORE_VIEW, this.facesLifecycle, facesContext);
ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
if (!isPortletRequest(facesContext)) {
viewHandler.initView(facesContext);
}
viewHandler.initView(facesContext);
UIViewRoot viewRoot = viewHandler.createView(facesContext, getUrl());
Assert.notNull(viewRoot, "A JSF view could not be created for " + getUrl());

View File

@@ -66,8 +66,7 @@ public class FacesContextHelper {
}
/**
* Factory method that can be used to create a new default {@link FacesContext} instance for the running
* (Portlet/Servlet) environment.
* Factory method that can be used to create a new default {@link FacesContext} instance.
*
* @param context the native context
* @param request the native request

View File

@@ -20,10 +20,8 @@ import javax.faces.FacesWrapper;
import javax.faces.FactoryFinder;
import javax.faces.context.FacesContext;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.webflow.execution.RequestContext;
/**
* Helper class to provide information about the JSF runtime environment such as
@@ -80,12 +78,6 @@ public class JsfRuntimeInformation {
private static boolean myFacesInUse = isMyFacesContextFactoryInUse();
private static boolean portletPresent = ClassUtils.isPresent("javax.portlet.Portlet", CLASSLOADER);
private static boolean springPortletPresent =
ClassUtils.isPresent("org.springframework.web.portlet.DispatcherPortlet", CLASSLOADER);
public static boolean isAtLeastJsf22() {
return jsfVersion >= JSF_22;
@@ -143,46 +135,4 @@ public class JsfRuntimeInformation {
}
}
/**
* 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.
* @param context the faces context
* @return <tt>true</tt> if the request is from a portlet
*/
public static boolean isPortletRequest(FacesContext context) {
Assert.notNull(context, "Context must not be null");
return isPortletContext(context.getExternalContext().getContext());
}
/**
* Determine if the specified {@link RequestContext} is from a portlet request.
*
* @param context the request context
* @return <tt>true</tt> if the request is from a portlet
*/
public static boolean isPortletRequest(RequestContext context) {
Assert.notNull(context, "Context must not be null");
return isPortletContext(context.getExternalContext().getNativeContext());
}
/**
* Determine if the specified context object is from portlet.
*
* @param nativeContext the native context
* @return <tt>true</tt> if the context is from a portlet
*/
public static boolean isPortletContext(Object nativeContext) {
Assert.notNull(nativeContext, "Context must not be null");
return ClassUtils.getMethodIfAvailable(nativeContext.getClass(), "getPortletContextName") != null;
}
}

View File

@@ -41,7 +41,6 @@ import org.springframework.webflow.execution.View;
import org.springframework.webflow.execution.ViewFactory;
import static org.springframework.faces.webflow.JsfRuntimeInformation.isMojarraPresent;
import static org.springframework.faces.webflow.JsfRuntimeInformation.isPortletRequest;
/**
* JSF-specific {@link ViewFactory} implementation.
@@ -107,9 +106,7 @@ public class JsfViewFactory implements ViewFactory {
private ViewHandler getViewHandler(FacesContext facesContext) {
ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
if (!isPortletRequest(facesContext)) {
viewHandler.initView(facesContext);
}
viewHandler.initView(facesContext);
return viewHandler;
}

View File

@@ -13,7 +13,6 @@
<factory>
<application-factory>org.springframework.faces.webflow.FlowApplicationFactory</application-factory>
<faces-context-factory>org.springframework.faces.webflow.context.portlet.PortletFacesContextFactory</faces-context-factory>
</factory>
<lifecycle>

View File

@@ -26,7 +26,7 @@ public abstract class AbstractResourcesConfigurationTests extends TestCase {
Map<String, ?> map = this.context.getBeansOfType(HttpRequestHandlerAdapter.class);
assertEquals(1, map.values().size());
Object resourceHandler = this.context.getBean(ResourcesBeanDefinitionParser.SERVLET_RESOURCE_HANDLER_BEAN_NAME);
Object resourceHandler = this.context.getBean("jsfResourceRequestHandler");
assertNotNull(resourceHandler);
assertTrue(resourceHandler instanceof JsfResourceRequestHandler);

View File

@@ -61,7 +61,7 @@ public class AbstractFlowConfiguration implements ApplicationContextAware {
* @return the created builder
*/
protected FlowExecutorBuilder getFlowExecutorBuilder(FlowDefinitionLocator flowRegistry) {
return new FlowExecutorBuilder(flowRegistry, this.applicationContext);
return new FlowExecutorBuilder(flowRegistry);
}
/**
@@ -86,7 +86,7 @@ public class AbstractFlowConfiguration implements ApplicationContextAware {
* @return the created builder
*/
protected FlowBuilderServicesBuilder getFlowBuilderServicesBuilder() {
return new FlowBuilderServicesBuilder(this.applicationContext);
return new FlowBuilderServicesBuilder();
}
}

View File

@@ -52,21 +52,17 @@ public class FlowBuilderServicesBuilder {
private boolean enableDevelopmentMode;
public FlowBuilderServicesBuilder() {
this.viewFactoryCreator = new MvcViewFactoryCreator();
}
/**
* Create a new instance with the given ApplicationContext.
*
* @param applicationContext the ApplicationContext to use to initialize a
* default ViewFactoryCreator instance with.
* @deprecated as of 2.5 an ApplicationContext is no longer required
*/
public FlowBuilderServicesBuilder(ApplicationContext applicationContext) {
Assert.notNull(applicationContext, "applicationContext is required");
this.viewFactoryCreator = initViewFactoryCreator(applicationContext);
}
private static ViewFactoryCreator initViewFactoryCreator(ApplicationContext applicationContext) {
MvcViewFactoryCreator viewFactoryCreator = new MvcViewFactoryCreator();
viewFactoryCreator.setApplicationContext(applicationContext);
return viewFactoryCreator;
this.viewFactoryCreator = new MvcViewFactoryCreator();
}

View File

@@ -17,7 +17,6 @@ package org.springframework.webflow.config;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -67,7 +66,7 @@ public class FlowDefinitionRegistryBuilder {
/**
* Create a new instance with the given ApplicationContext.
*
* @param applicationContext the ApplicationContext to use for initializing the
* @param appContext the ApplicationContext to use for initializing the
* FlowDefinitionResourceFactory and FlowBuilderServices instances with
*/
public FlowDefinitionRegistryBuilder(ApplicationContext appContext) {
@@ -77,7 +76,7 @@ public class FlowDefinitionRegistryBuilder {
/**
* Create a new instance with the given ApplicationContext and {@link FlowBuilderServices}.
*
* @param applicationContext the ApplicationContext to use for initializing the
* @param appContext the ApplicationContext to use for initializing the
* FlowDefinitionResourceFactory and FlowBuilderServices instances with
* @param builderServices a {@link FlowBuilderServices} instance to configure
* on the FlowDefinitionRegistry
@@ -89,7 +88,7 @@ public class FlowDefinitionRegistryBuilder {
this.flowBuilderServices = builderServices;
}
else {
this.flowBuilderServices = new FlowBuilderServicesBuilder(appContext).build();
this.flowBuilderServices = new FlowBuilderServicesBuilder().build();
this.flowBuilderServices.setApplicationContext(appContext);
}
}

View File

@@ -32,7 +32,6 @@ import org.springframework.webflow.execution.repository.snapshot.SerializedFlowE
import org.springframework.webflow.execution.repository.snapshot.SimpleFlowExecutionSnapshotFactory;
import org.springframework.webflow.executor.FlowExecutor;
import org.springframework.webflow.executor.FlowExecutorImpl;
import org.springframework.webflow.mvc.builder.MvcEnvironment;
/**
* A builder for {@link FlowExecutor} instances designed for programmatic use in
@@ -50,8 +49,6 @@ public class FlowExecutorBuilder {
private Integer maxFlowExecutionSnapshots;
private MvcEnvironment environment;
private LocalAttributeMap<Object> executionAttributes = new LocalAttributeMap<Object>();
private ConditionalFlowExecutionListenerLoader listenerLoader;
@@ -61,18 +58,21 @@ public class FlowExecutorBuilder {
private ConversationManager conversationManager;
public FlowExecutorBuilder(FlowDefinitionLocator flowRegistry) {
Assert.notNull(flowRegistry, "FlowDefinitionLocator is required");
this.flowRegistry = flowRegistry;
}
/**
* Create a new instance with the given flow registry and ApplicationContext.
*
* @param flowRegistry the flow registry that will locate flow definitions
* @param applicationContext the Spring ApplicationContext to use for
* initializing an instance of {@link MvcEnvironment}
* @param applicationContext the Spring ApplicationContext
* @deprecated as of 2.5 an ApplicationContext is no longer required
*/
public FlowExecutorBuilder(FlowDefinitionLocator flowRegistry, ApplicationContext applicationContext) {
Assert.notNull(flowRegistry, "FlowDefinitionLocator is required");
Assert.notNull(applicationContext, "applicationContext is required");
this.flowRegistry = flowRegistry;
this.environment = MvcEnvironment.environmentFor(applicationContext);
}
@@ -216,10 +216,10 @@ public class FlowExecutorBuilder {
private LocalAttributeMap<Object> getExecutionAttributes() {
LocalAttributeMap<Object> attributes = new LocalAttributeMap<Object>(this.executionAttributes.asMap());
if (!attributes.contains("alwaysRedirectOnPause")) {
attributes.put("alwaysRedirectOnPause", (this.environment != MvcEnvironment.PORTLET));
attributes.put("alwaysRedirectOnPause", true);
}
if (!attributes.contains("redirectInSameState")) {
attributes.put("redirectInSameState", (this.environment != MvcEnvironment.PORTLET));
attributes.put("redirectInSameState", true);
}
return attributes;
}

View File

@@ -17,15 +17,12 @@ package org.springframework.webflow.config;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.convert.service.DefaultConversionService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.webflow.conversation.ConversationManager;
@@ -45,7 +42,6 @@ import org.springframework.webflow.execution.repository.snapshot.SerializedFlowE
import org.springframework.webflow.execution.repository.snapshot.SimpleFlowExecutionSnapshotFactory;
import org.springframework.webflow.executor.FlowExecutor;
import org.springframework.webflow.executor.FlowExecutorImpl;
import org.springframework.webflow.mvc.builder.MvcEnvironment;
/**
* This factory encapsulates the construction and assembly of a {@link FlowExecutor}, including the provision of its
@@ -57,8 +53,7 @@ import org.springframework.webflow.mvc.builder.MvcEnvironment;
* @author Keith Donald
* @author Erwin Vervaet
*/
class FlowExecutorFactoryBean implements FactoryBean<FlowExecutor>, ApplicationContextAware, BeanClassLoaderAware,
InitializingBean {
class FlowExecutorFactoryBean implements FactoryBean<FlowExecutor>, BeanClassLoaderAware, InitializingBean {
private static final String ALWAYS_REDIRECT_ON_PAUSE = "alwaysRedirectOnPause";
@@ -80,8 +75,6 @@ class FlowExecutorFactoryBean implements FactoryBean<FlowExecutor>, ApplicationC
private FlowExecutor flowExecutor;
private MvcEnvironment environment;
private ClassLoader classLoader;
/**
@@ -133,12 +126,6 @@ class FlowExecutorFactoryBean implements FactoryBean<FlowExecutor>, ApplicationC
this.conversationManager = conversationManager;
}
// implementing ApplicationContextAware
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
environment = MvcEnvironment.environmentFor(applicationContext);
}
// implement BeanClassLoaderAware
public void setBeanClassLoader(ClassLoader classLoader) {
@@ -186,12 +173,10 @@ class FlowExecutorFactoryBean implements FactoryBean<FlowExecutor>, ApplicationC
private void putDefaultFlowExecutionAttributes(LocalAttributeMap<Object> executionAttributes) {
if (!executionAttributes.contains(ALWAYS_REDIRECT_ON_PAUSE)) {
Boolean redirect = (environment != MvcEnvironment.PORTLET);
executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, redirect);
executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, true);
}
if (!executionAttributes.contains(REDIRECT_IN_SAME_STATE)) {
Boolean redirect = (environment != MvcEnvironment.PORTLET);
executionAttributes.put(REDIRECT_IN_SAME_STATE, redirect);
executionAttributes.put(REDIRECT_IN_SAME_STATE, true);
}
}

View File

@@ -73,8 +73,7 @@ public interface ExternalContext {
* session and accessible to both internal and external SWF artifacts.
* <p>
* Note: most external context implementations do not distinguish between the concept of a "local" user session
* scope and a "global" session scope. The Portlet world does, but not the Servlet for example. In those cases
* calling this method returns the same map as calling {@link #getSessionMap()}.
* scope and a "global" session scope. Otherwise this method returns the same map as calling {@link #getSessionMap()}.
* @return the mutable global session attribute map
*/
public SharedAttributeMap<Object> getGlobalSessionMap();
@@ -140,8 +139,7 @@ public interface ExternalContext {
/**
* Is a <i>render</i> response allowed to be written for this request? Always return false after a response has been
* completed. May return false before that to indicate a response is not allowed to be completed. For example, in a
* Portlet environment, render responses are only allowed in render requests.
* completed. May return false before that to indicate a response is not allowed to be completed.
* @return true if yes, false otherwise
*/
public boolean isResponseAllowed();
@@ -215,4 +213,4 @@ public interface ExternalContext {
*/
public boolean isResponseCompleteFlowExecutionRedirect();
}
}

View File

@@ -15,7 +15,7 @@
*/
/**
* Shared classes used by the Servlet and Portlet ExternalContext implementations.
* Shared classes used with Servlet or alternative ExternalContext implementations.
*/
package org.springframework.webflow.context.web;

View File

@@ -80,7 +80,7 @@ import org.springframework.webflow.execution.RequestContext;
* <p>
* This class and the rest of the Spring Web Flow (SWF) engine have been designed with minimal dependencies on other
* libraries. Spring Web Flow is usable in a standalone fashion. The engine system is fully usable outside an HTTP
* servlet environment, for example in portlets, tests, or standalone applications. One of the major architectural
* servlet environment, for example in tests, or standalone applications. One of the major architectural
* benefits of Spring Web Flow is the ability to design reusable, high-level controller modules that may be executed in
* <i>any</i> environment.
* <p>

View File

@@ -49,7 +49,7 @@ import org.springframework.webflow.definition.TransitionDefinition;
* The web flow system will ensure that a RequestContext object is local to the current thread. It can be safely
* manipulated without needing to worry about concurrent access.
* <p>
* Note: this request context is in no way linked to an HTTP or Portlet request. It uses the familiar "request" naming
* Note: this request context is in no way linked to an HTTP request. It uses the familiar "request" naming
* convention to indicate a single call to manipulate a runtime execution of a flow definition.
*
* @author Keith Donald
@@ -151,7 +151,7 @@ public interface RequestContext {
* constructs within that environment.
* <p>
* In addition, this context may be downcastable to a specific context type for a specific client environment, such
* as Servlets or Portlets. Such downcasting will give you full access to a native HttpServletRequest, for example.
* as Servlets. Such downcasting will give you full access to a native HttpServletRequest, for example.
* With that said, for portability reasons you should avoid coupling your flow artifacts to a specific deployment
* environment when possible.
* @return the originating external context, the one that triggered the current execution request
@@ -208,4 +208,4 @@ public interface RequestContext {
*/
public String getFlowExecutionUrl() throws IllegalStateException;
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright 2004-2008 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.webflow.mvc.builder;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;
/**
* Supported Spring Web MVC environments.
*
* @author Keith Donald
*/
public enum MvcEnvironment {
/**
* Spring Web Servlet MVC.
*/
SERVLET,
/**
* Spring Web Portlet MVC.
*/
PORTLET;
/**
* Calculates the web environment from the state of the provided application context.
* @param applicationContext the application context
* @return the web environment the context is running in, or null if not running in a web environment
*/
public static MvcEnvironment environmentFor(ApplicationContext applicationContext) {
if (applicationContext instanceof WebApplicationContext) {
return MvcEnvironment.SERVLET;
} else {
return null;
}
}
}

View File

@@ -22,8 +22,6 @@ import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.beanwrapper.BeanWrapperExpressionParser;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.StringUtils;
import org.springframework.validation.DefaultMessageCodesResolver;
import org.springframework.validation.MessageCodesResolver;
@@ -43,9 +41,6 @@ import org.springframework.webflow.validation.WebFlowMessageCodesResolver;
* Returns {@link ViewFactory view factories} that create native Spring MVC-based views. Used by a FlowBuilder to
* configure a flow's view states with Spring MVC-based view factories.
* <p>
* This implementation detects whether it is running in a Servlet or Portlet MVC environment, and returns instances of
* the default view factory implementation for that environment.
* <p>
* By default, this implementation creates view factories that resolve their views by loading flow-relative resources,
* such as .jsp templates located in a flow working directory. This class also supports rendering views resolved by
* pre-existing Spring MVC {@link ViewResolver view resolvers}.
@@ -57,9 +52,7 @@ import org.springframework.webflow.validation.WebFlowMessageCodesResolver;
* @author Keith Donald
* @author Scott Andrews
*/
public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationContextAware {
private MvcEnvironment environment;
public class MvcViewFactoryCreator implements ViewFactoryCreator {
private FlowViewResolver flowViewResolver = new FlowResourceFlowViewResolver();
@@ -162,11 +155,6 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon
this.messageCodesResolver = messageCodesResolver;
}
// implementing ApplicationContextAware
public void setApplicationContext(ApplicationContext applicationContext) {
environment = MvcEnvironment.environmentFor(applicationContext);
}
public ViewFactory createViewFactory(Expression viewId, ExpressionParser expressionParser,
ConversionService conversionService, BinderConfiguration binderConfiguration,
@@ -188,17 +176,13 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon
}
/**
* Creates a concrete instance of an AbstractMvcViewFactory according to the runtime environment (Servlet or
* Portlet).
* Creates a concrete instance of an AbstractMvcViewFactory.
*/
protected AbstractMvcViewFactory createMvcViewFactory(Expression viewId, ExpressionParser expressionParser,
ConversionService conversionService, BinderConfiguration binderConfiguration) {
if (environment == MvcEnvironment.SERVLET) {
return new ServletMvcViewFactory(viewId, flowViewResolver, expressionParser, conversionService,
binderConfiguration, messageCodesResolver);
} else {
throw new IllegalStateException("Web MVC Environment " + environment + " not supported ");
}
return new ServletMvcViewFactory(viewId, flowViewResolver, expressionParser, conversionService,
binderConfiguration, messageCodesResolver);
}
public String getViewIdByConvention(String viewStateId) {

View File

@@ -60,7 +60,7 @@ import org.springframework.webflow.validation.ValidationHelper;
import org.springframework.webflow.validation.ValidationHintResolver;
/**
* Base view implementation for the Spring Web MVC Servlet and Spring Web MVC Portlet frameworks.
* Base view implementation for the Spring Web MVC Servlet frameworks.
*
* @author Keith Donald
*/

View File

@@ -47,8 +47,8 @@ import org.springframework.webflow.test.MockExternalContext;
* <p>
* A flow execution test can effectively automate and validate the orchestration required to drive an end-to-end
* business task that spans several steps involving the user to complete. Such tests are a good way to test your system
* top-down starting at the web-tier and pushing through all the way to the DB without having to deploy to a servlet or
* portlet container. In addition, they can be used to effectively test a flow's execution (the web layer) standalone,
* top-down starting at the web-tier and pushing through all the way to the DB without having to deploy to a servlet
* container. In addition, they can be used to effectively test a flow's execution (the web layer) standalone,
* typically with a mock service layer.
*
* @author Keith Donald

View File

@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<book xml:id="spring-framework-reference"
xmlns="http://docbook.org/ns/docbook" version="5.0"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
xmlns="http://docbook.org/ns/docbook" version="5.0"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd">
<info>
<title>Spring Web Flow Reference Guide</title>
@@ -96,9 +93,7 @@
<xi:include href="spring-mvc.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="spring-js.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="spring-faces.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="portlet.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="testing.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="upgrade-guide.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="flow-definition-field-mappings.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</book>

View File

@@ -1,286 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="portlet"
xmlns="http://docbook.org/ns/docbook" version="5.0"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
<title>Portlet Integration</title>
<sect1 xml:id="portlet-introduction">
<title>Introduction</title>
<para>
This chapter shows how to use Web Flow in a Portlet environment.
Spring Web Flow requires Portlet API 2.0 to run with.
The <code>booking-portlet-mvc</code> sample application is a good reference for using Web Flow within a portlet.
This application is a simplified travel site that allows users to search for and book hotel rooms.
</para>
</sect1>
<sect1 xml:id="portlet-config-core">
<title>Configuring web.xml and portlet.xml</title>
<para>
The configuration for a portlet depends on the portlet container used.
The sample applications, included with Web Flow, are both configured to use <link xl:href="http://portals.apache.org/pluto/">Apache Pluto</link>.
</para>
<para>
In general, the configuration requires adding a servlet mapping in the <code>web.xml</code> file to dispatch request to the portlet container.
</para>
<programlisting language="xml"><![CDATA[
<servlet>
<servlet-name>swf-booking-mvc</servlet-name>
<servlet-class>org.apache.pluto.core.PortletServlet</servlet-class>
<init-param>
<param-name>portlet-name</param-name>
<param-value>swf-booking-mvc</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>swf-booking-mvc</servlet-name>
<url-pattern>/PlutoInvoker/swf-booking-mvc</url-pattern>
</servlet-mapping>
]]></programlisting>
<para>
The <code>portlet.xml</code> configuration is a standard portlet configuration.
The <code>portlet-class</code> needs to be set along with a pair of <code>init-param</code>s.
Setting the <code>expiration-cache</code> to <code>0</code> is recommended to force Web Flow to always render a fresh view.
</para>
<programlisting language="xml"><![CDATA[
<portlet>
...
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/web-application-config.xml</value>
</init-param>
<init-param>
<name>viewRendererUrl</name>
<value>/WEB-INF/servlet/view</value>
</init-param>
<expiration-cache>0</expiration-cache>
...
</portlet>
]]></programlisting>
</sect1>
<sect1 xml:id="portlet-config-spring">
<title>Configuring Spring</title>
<sect2 xml:id="portlet-config-spring-handler">
<title>Flow Handlers</title>
<para>
The only supported mechanism for bridging a portlet request to Web Flow is a <code>FlowHandler</code>.
The <code>PortletFlowController</code> used in Web Flow 1.0 is no longer supported.
</para>
<para>
The flow handler, similar to the servlet flow handler, provides hooks that can:
<itemizedlist>
<listitem>
<para>select the flow to execute</para>
</listitem>
<listitem>
<para>pass input parameters to the flow on initialization</para>
</listitem>
<listitem>
<para>handle the flow execution outcome</para>
</listitem>
<listitem>
<para>handle exceptions</para>
</listitem>
</itemizedlist>
</para>
<para>
The <code>AbstractFlowHandler</code> class is an implementation of <code>FlowHandler</code> that provides default implementations for these hooks.
</para>
<para>
In a portlet environment the targeted flow id can not be inferred from the URL and must be defined explicitly in the handler.
</para>
<programlisting language="java"><![CDATA[
public class ViewFlowHandler extends AbstractFlowHandler {
public String getFlowId() {
return "view";
}
}
]]></programlisting>
</sect2>
<sect2 xml:id="portlet-config-spring-mappings">
<title>Handler Mappings</title>
<para>
Spring Portlet MVC provides a rich set of methods to map portlet requests.
Complete documentation is available in the <link xl:href="http://static.springframework.org/spring/docs/current/reference/portlet.html#portlet-handlermapping">Spring Reference Documentation</link>.
</para>
<para>
The <code>booking-portlet-mvc</code> sample application uses a <code>PortletModeHandlerMapping</code> to map portlet requests.
The sample application only supports <code>view</code> mode, but support for other portlet modes is available.
Other modes can be added and point to the same flow as <code>view</code> mode, or any other flow.
</para>
<programlisting language="xml"><![CDATA[
<bean id="portletModeHandlerMapping"
class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="portletModeMap">
<map>
<entry key="view">
<bean class="org.springframework.webflow.samples.booking.ViewFlowHandler" />
</entry>
</map>
</property>
</bean>
]]></programlisting>
</sect2>
<sect2 xml:id="portlet-config-spring-handler-adapter">
<title>Flow Handler Adapter</title>
<para>
A <code>FlowHandlerAdapter</code> converts the handler mappings to the flow handlers.
The flow executor is required as a constructor argument.
</para>
<programlisting language="xml"><![CDATA[
<bean id="flowHandlerAdapter"
class="org.springframework.webflow.mvc.portlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor" />
</bean>
]]></programlisting>
</sect2>
</sect1>
<sect1 xml:id="portlet-views">
<title>Portlet Views</title>
<para>
In order to facilitate view rendering, a <code>ViewRendererServlet</code> must be added to the <code>web.xml</code> file.
This servlet is not invoked directly, but it used by Web Flow to render views in a portlet environment.
</para>
<programlisting language="xml"><![CDATA[
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
]]></programlisting>
</sect1>
<sect1 xml:id="portlet-modes">
<title>Portlet Modes and Window States</title>
<sect2 xml:id="portlet-modes-state">
<title>Window State</title>
<para>
The Portlet API defined three window states: normal, minimized and maximized.
The portlet implementation must decide what to render for each of these window states.
Web Flow exposes the string value of the window state under <code>portletWindowState</code> via the request map on the external context.
</para>
<programlisting language="java"><![CDATA[
requestContext.getExternalContext().getRequestMap().get("portletWindowState");
]]></programlisting>
<programlisting><![CDATA[
externalContext.requestMap.portletWindowState
]]></programlisting>
</sect2>
<sect2 xml:id="portlet-modes-mode">
<title>Portlet Mode</title>
<para>
The Portlet API defined three portlet modes: view, edit and help.
The portlet implementation must decide what to render for each of these modes.
Web Flow exposes the string value of the portlet mode under <code>portletMode</code> via the request map on the external context.
</para>
<programlisting language="java"><![CDATA[
requestContext.getExternalContext().getRequestMap().get("portletMode");
]]></programlisting>
<programlisting><![CDATA[
externalContext.requestMap.portletMode
]]></programlisting>
</sect2>
</sect1>
<sect1 xml:id="portlet-jsf">
<title>Using Portlets with JSF</title>
<sect2 xml:id="portlet-jsf-using-portlet-jsf">
<para>
Prior to version 2.1 of Spring Web Flow, support for JSF Portlets was considered
experimental and relied on a Portlet Bridge for JSF implementation.
Furthermore JSR-329 (the latest specification in this area), which targets
Portlet API 2.0 and JSF 1.2 environments at the time of writing is not yet
final causing portlet bridge implementations to also remain incomplete.
</para>
<para>
A closer comparison of Spring Web Flow and a Portlet Bridge for JSF shows
the two have significant overlap. They both drive the
JSF lifecycle and they both shield JSF from knowledge about Portlet action
and render requests.
</para>
<para>
Considering all of the above, starting with version 2.2, Spring Web Flow
provides support for JSF Portlets using its own internal Portlet integration rather
than a Portlet Bridge for JSF. We believe this will provide value for Web Flow users
by reducing the number of dependencies in what is already a fairly complex
combination of technologies with specifications lagging behind.
</para>
<para>
What this practically means is the configuration required for JSF Portlets is
very similar to what is alread documented in the rest of this chapter
with the exception of <xref linkend="portlet-views"/>, which is not necessary
with JSF.
</para>
<para>
Review the <code>swf-booking-portlet-faces</code> sample in the Web Flow distribution
for a working JSF Portlets example with complete configuration details. The main
things to ensure are that the <code>&lt;faces:resources&gt;</code> elements is
included as part of your Spring configuration and that your
<code>faces-config.xml</code> configuration includes a <code>PortletViewHandler</code>:
</para>
<programlisting language="java"><![CDATA[<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config>
<application>
<view-handler>
org.springframework.faces.webflow.context.portlet.PortletViewHandler
</view-handler>
</application>
</faces-config>
]]></programlisting>
<para>
The JSF Portlet support provided with Spring Web Flow requires JSF v2.0 or above. If
you are upgrading from a previous release you should ensure that your <code>faces-config.xml</code>
references <code>org.springframework.faces.webflow.context.portlet.PortletViewHandler</code> instead
of <code>org.springframework.faces.webflow.application.portlet.PortletFaceletViewHandler</code>. You
should also ensure that you have added <code>&lt;faces:resources&gt;</code> to you Spring configuration.
</para>
<para>
Although JSF v2.0 is a minimum requirement, this has been primarily driven to provide better support in
a Servlet environment. Many of the more advanced JSF 2.0 features (for example 'Partial State Saving')
are not supported by Spring Web Flow in a Portlet environment.
</para>
</sect2>
</sect1>
<sect1 xml:id="portlet-issues">
<title>Issues in a Portlet Environment</title>
<sect2 xml:id="portlet-issues-redirects">
<title>Redirects</title>
<para>
The Portlet API only allows redirects to be requested from an action request.
Because views are rendered on the render request, views and <code>view-state</code>s cannot trigger a redirect.
</para>
<para>
The <code>externalRedirect:</code> view prefix is a convenience for Servlet based flows.
An <code>IllegalStateException</code> is thrown if a redirect is requested from a render request.
</para>
<para>
<code>end-state</code> redirects can be achieved by implementing <code>FlowHandler.handleExecutionOutcome</code>.
This callback provides the <code>ActionResponse</code> object which supports redirects.
</para>
</sect2>
<sect2 xml:id="portlet-issues-modes">
<title>Switching Portlet Modes</title>
<para>
The portlet container passes the execution key from the previous flow when switching to a new mode.
Even if the mode is mapped to a different <code>FlowHandler</code> the flow execution will resume the previous execution.
You may switch the mode programatically in your FlowHandler after ending a flow in an ActionRequest.
</para>
<para>
One way to start a new flow is to create a URL targeting the mode without the execution key.
</para>
</sect2>
</sect1>
</chapter>

View File

@@ -23,10 +23,6 @@ xsi:schemaLocation="
JSF v2.0 or above. Both Sun Mojarra and Apache MyFaces runtime environments
are supported.</para>
<para>Spring Web Flow also supports using JSF in a portlet environment.
Spring Web Flow's portlet integration supports Portlets API 2.0.
See <xref linkend="portlet" /> for more on Spring Web Flow's portlet
integration.</para>
</sect1>
<sect1 xml:id="spring-faces-integration">

View File

@@ -1,278 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="upgrade-guide"
xmlns="http://docbook.org/ns/docbook" version="5.0"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
<title>Upgrading from 1.0</title>
<sect1 xml:id="upgrade-guide-introduction">
<title>Introduction</title>
<para>
This chapter shows you how to upgrade existing Web Flow 1 application to Web Flow 2.
</para>
</sect1>
<sect1 xml:id="upgrade-guide-definition-language">
<title>Flow Definition Language</title>
<para>
The core concepts behind the flow definition language have not changed between Web Flow 1 and 2.
However, some of the element and attribute names have changed.
These changes allow for the language to be both more concise and expressive.
A complete list of <link linkend="field-mappings">mapping changes</link> is available as an appendix.
</para>
<sect2 xml:id="upgrade-guide-definition-language-tool">
<title>Flow Definition Updater Tool</title>
<para>
An automated tool is available to aid in the conversion of existing 1.x flows to the new 2.x style.
The tool will convert all the old tag names to their new equivalents, if needed.
While the tool will make a best effort attempt at conversion, there is not a one-to-one mapping for all version 1 concepts.
If the tool was unable to convert a portion of the flow, it will be marked with a <code>WARNING</code> comment in the resulting flow.
</para>
<para>
The conversion tool requires spring-webflow.jar, spring-core.jar and an XSLT 1.0 engine.
<link xl:href="http://saxon.sourceforge.net/">Saxon 6.5.5</link> is recommended.
</para>
<para>
The tool can be run from the command line with the following command.
Required libraries must be available on the classpath.
The source must be a single flow to convert.
The resulting converted flow will be sent to standard output.
</para>
<programlisting>
java org.springframework.webflow.upgrade.WebFlowUpgrader flow-to-upgrade.xml
</programlisting>
<sect3 xml:id="upgrade-guide-definition-language-tool-warnings">
<title>Flow Definition Updater Tool Warnings</title>
<sect4 xml:id="upgrade-guide-definition-language-tool-warnings-argument-parameter-type">
<title>argument parameter-type no longer supported</title>
<para>
Bean actions have been deprecated in favor of EL based evaluate expressions.
The EL expression is able to accept method parameters directly, so there is no longer a need for the argument tag.
A side effect of this change is that method arguments must be of the correct type before invoking the action.
</para>
</sect4>
<sect4 xml:id="upgrade-guide-definition-language-tool-warnings-inline-flow">
<title>inline-flow is no longer supported</title>
<para>
Inline flows are no longer supported.
The contents of the inline flow must be moved into a new top-level flow.
The inline flow's content has been converted for your convenience.
</para>
</sect4>
<sect4 xml:id="upgrade-guide-definition-language-tool-warnings-mapping-target-collection">
<title>mapping target-collection is no longer supported</title>
<para>
Output mappings can no longer add an item to a collection.
Only assignment is supported.
</para>
</sect4>
<sect4 xml:id="upgrade-guide-definition-language-tool-warnings-var-bean">
<title>var bean is no longer supported</title>
<para>
The var bean attribute is no longer needed.
All spring beans can be resolved via EL.
</para>
</sect4>
<sect4 xml:id="upgrade-guide-definition-language-tool-warnings-var-scope">
<title>var scope is no longer supported</title>
<para>
The var element will place all variable into flow scope.
Conversation scope was previously allowed.
</para>
</sect4>
</sect3>
</sect2>
<sect2 xml:id="upgrade-guide-definition-language-el">
<title>EL Expressions</title>
<para>
EL expressions are used heavily throughout the flow definition language.
Many of the attributes that appear to be plain text are actually interpreted as EL.
The standard EL delimiters (either ${} or #{} in Web Flow 2.0 or just #{} in Web Flow 2.1) are not necessary and will often cause an exception if they are included.
</para>
<para>
EL delimiters should be removed where necessary by the updater tool.
</para>
</sect2>
</sect1>
<sect1 xml:id="upgrade-guide-webflow-config">
<title>Web Flow Configuration</title>
<para>
In Web Flow 1 there were two options available for configuring Web Flow, one using standard spring bean XML and the other using the <code>webflow-config-1.0</code> schema.
The schema configuration option simplifies the configuration process by keeping long internal class names hidden and enabling contextual auto-complete.
The schema configuration option is the only way to configure Web Flow 2.
</para>
<sect2 xml:id="upgrade-guide-webflow-config-beans">
<title>Web Flow Bean Configuration</title>
<para>
The <code>FactoryBean</code> bean XML configuration method used in Web Flow 1 is no longer supported.
The schema configuration method should be used instead.
In particular beans defining <code>FlowExecutorFactoryBean</code> and <code>XmlFlowRegistryFactoryBean</code> should be updated.
Continue reading Web Flow Schema Configuration for details.
</para>
</sect2>
<sect2 xml:id="upgrade-guide-webflow-config-schema">
<title>Web Flow Schema Configuration</title>
<para>
The <code>webflow-config</code> configuration schema has also changed slightly from version 1 to 2.
The simplest way to update your application is modify the version of the schema to 2.0 then fix any errors in a schema aware XML editor.
The most common change is add 'flow-' to the beginning of the elements defined by the schema.
</para>
<programlisting language="xml"><![CDATA[
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.4.xsd">
]]></programlisting>
<sect3 xml:id="upgrade-guide-webflow-config-schema-executor">
<title>flow-executor</title>
<para>
The flow executor is the core Web Flow configuration element.
This element replaces previous <code>FlowExecutorFactoryBean</code> bean definitions.
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-executor id="flowExecutor" />
]]></programlisting>
</sect3>
<sect3 xml:id="upgrade-guide-webflow-config-schema-listeners">
<title>flow-execution-listeners</title>
<para>
Flow execution listeners are also defined in the flow executor.
Listeners are defined using standard bean definitions and added by reference.
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
<webflow:flow-execution-listeners>
<webflow:listener ref="securityFlowExecutionListener"/>
</webflow:flow-execution-listeners>
</webflow:flow-executor>
<bean id="securityFlowExecutionListener"
class="org.springframework.webflow.security.SecurityFlowExecutionListener" />
]]></programlisting>
</sect3>
<sect3 xml:id="upgrade-guide-webflow-config-schema-registry">
<title>flow-registry</title>
<para>
The <code>flow-registry</code> contains a set of <code>flow-location</code>s.
Every flow definition used by Web Flow must be added to the registry.
This element replaces previous <code>XmlFlowRegistryFactoryBean</code> bean definitions.
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-registry id="flowRegistry">
<webflow:flow-location path="/WEB-INF/hotels/booking/booking.xml" />
</webflow:flow-registry>
]]></programlisting>
</sect3>
</sect2>
<sect2 xml:id="upgrade-guide-java-controller">
<title>Flow Controller</title>
<para>
The package name for flow controllers has changed from <code>org.springframework.webflow.executor.mvc.FlowController</code> and is now <code>org.springframework.webflow.mvc.servlet.FlowController</code> for Servlet MVC requests.
The portlet flow controller <code>org.springframework.webflow.executor.mvc.PortletFlowController</code> has been replaced by a flow handler adapter available at <code>org.springframework.webflow.mvc.portlet.FlowHandlerAdapter</code>.
They will need to be updated in the bean definitions.
</para>
</sect2>
<sect2 xml:id="upgrade-guide-java-url-handler">
<title>Flow URL Handler</title>
<para>
The default URL handler has changed in Web Flow 2.
The flow identifier is now derived from the URL rather then passed explicitly.
In order to maintain comparability with existing views and URL structures a <code>WebFlow1FlowUrlHandler</code> is available.
</para>
<programlisting language="xml"><![CDATA[
<bean name="/pos.htm" class="org.springframework.webflow.mvc.servlet.FlowController">
<property name="flowExecutor" ref="flowExecutor" />
<property name="flowUrlHandler">
<bean class="org.springframework.webflow.context.servlet.WebFlow1FlowUrlHandler" />
</property>
</bean>
]]></programlisting>
</sect2>
<sect2 xml:id="upgrade-guide-webflow-config-view-resolver">
<title>View Resolution</title>
<para>
Web Flow 2 by default will both select and render views.
View were previously selected by Web Flow 1 and then rendered by an external view resolver.
</para>
<para>
In order for version 1 flows to work in Web Flow 2 the default view resolver must be overridden.
A common use case is to use <link xl:href="http://tiles.apache.org/">Apache Tiles</link> for view resolution.
The following configuration will replace the default view resolver with a Tiles view resolver.
The <code>tilesViewResolver</code> in this example can be replaced with any other view resolver.
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
<web:flow-location path="..." />
...
</webflow:flow-registry>
<webflow:flow-builder-services id="flowBuilderServices"
view-factory-creator="viewFactoryCreator"/>
<bean id="viewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers" ref="tilesViewResolver" />
</bean>
<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles.TilesJstlView" />
</bean>
<bean class="org.springframework.web.servlet.view.tiles.TilesConfigurer">
<property name="definitions" value="/WEB-INF/tiles-def.xml" />
</bean>
]]></programlisting>
</sect2>
</sect1>
<sect1 xml:id="upgrade-guide-webflow-concepts">
<title>New Web Flow Concepts</title>
<sect2 xml:id="upgrade-guide-webflow-concepts-binding">
<title>Automatic Model Binding</title>
<para>
Web Flow 1 required Spring MVC based flows to manually call <code>FormAction</code> methods, notably:
<code>setupForm</code>, <code>bindAndValidate</code> to process form views.
Web Flow 2 now provides automatic model setup and binding using the <code>model</code> attribute for <code>view-state</code>s.
Please see the <link linkend="view-model">Binding to a Model</link> section for details.
</para>
</sect2>
<sect2 xml:id="upgrade-guide-webflow-concepts-el-v-ognl">
<title>OGNL vs Spring EL</title>
<para>
Web Flow 1 used OGNL exclusively for expressions within the flow definitions.
Web Flow 2 adds support for Unified EL.
Web Flow 2.1 uses Spring EL by default.
United EL and OGNL can still be plugged in.
Please see <xref linkend="el"/> for details.
</para>
</sect2>
<sect2 xml:id="upgrade-guide-webflow-concepts-flash-scope">
<title>Flash Scope</title>
<para>
Flash scope in Web Flow 1 lived across the current request and into the next request.
This was conceptually similar to Web Flow 2's view scope concept, but the semantics were not as well defined.
In Web Flow 2, flash scope is cleared after every view render.
This makes flashScope semantics in Web Flow consistent with other web frameworks.
</para>
</sect2>
<sect2 xml:id="upgrade-guide-webflow-concepts-jsf">
<title>JSF</title>
<para>
Web Flow 2 offers significantly improved integration with JSF.
Please see <xref linkend="spring-faces"/> for details.
</para>
</sect2>
<sect2 xml:id="upgrade-guide-webflow-concepts-redirects">
<title>External Redirects</title>
<para>
External redirects in Web Flow 1 were always considered context relative.
In Web Flow 2, if the redirect URL begins with a slash, it is considered servlet-relative instead of context-relative.
URLs without a leading slash are still context relative.
</para>
</sect2>
</sect1>
</chapter>

View File

@@ -77,9 +77,6 @@
Upgraded projects will need to ensure that the <code>&lt;faces:resources&gt;</code> elements is
included as part of their Spring configuration.
</para>
<para>
See <xref linkend="portlet-jsf"/>.
</para>
</sect2>
<sect2 xml:id="whatsnew-deprecation">
<title>Deprecations</title>
@@ -97,83 +94,4 @@
</para>
</sect2>
</sect1>
<sect1 xml:id="whatsnew-swf-230">
<title>Spring Web Flow 2.3</title>
<sect2 xml:id="whatsnew-swf-embedded-flow">
<title>Embedding A Flow On A Page</title>
<para>
By default Web Flow does a client-side redirect upon entering every view state.
That makes it impossible to embed a flow on a page or within a modal dialog and execute more than one view state without causing a full-page refresh.
Web Flow now supports launching a flow in "embedded" mode.
In this mode a flow can transition to other view states without a client-side redirect during Ajax requests.
See <xref linkend="spring-mvc-embedded-flow"/> and <xref linkend="spring-faces-embedded-mode"/>.
</para>
</sect2>
<sect2 xml:id="whatsnew-jsr303">
<title>Support For JSR-303 Bean Validation</title>
<para>
Support for the JSR-303 Bean Validation API is now available building on equivalent support available in Spring MVC.
See <xref linkend="view-validate"/> for more details.
</para>
</sect2>
<sect2 xml:id="whatsnew-pc-propagation">
<title>Flow-Managed Persistence Context Propagation</title>
<para>
Starting with Web Flow 2.3 a flow managed <code>PersistenceContext</code> is automatically extended (propagated) to sub-flows assuming the subflow also has the feature enabled as well.
See <xref linkend="flow-managed-persistence-propagation"/>.
</para>
</sect2>
<sect2 xml:id="whatsnew-portlet-resource-requests">
<title>Portlet 2.0 Resource Requests</title>
<para>
Support for Portlet 2.0 resource requests has now been added enabling Ajax requests with partial rendering.
URLs for such requests can be prepared with the <code>&lt;portlet:resourceURL&gt;</code> tag in JSP pages.
Server-side processing is similar to a combined an action and a render requests but combined in a single request.
Unlike a render request, the response from a resource request includes content from the target portlet only.
</para>
</sect2>
<sect2 xml:id="whatsnew-conversation-manager">
<title>Custom ConversationManager</title>
<para>
The <code>&lt;flow-execution-repository&gt;</code> element now provides a conversation-manager attribute accepting a reference to a ConversationManager instance.
</para>
</sect2>
<sect2 xml:id="whatsnew-redirect-in-same-state">
<title>Redirect In Same State</title>
<para>
By default Web Flow does a client-side redirect when remaining in the same view state as long as the current request is not an Ajax request.
This is useful after form validation failure.
Hitting Refresh or Back won't result in browser warnings.
Hence this behavior is usually desirable.
However a new flow execution attribute makes it possible to disable it and that may also be necessary in some cases specific to JSF applications.
See <xref linkend="spring-faces-redirect-in-same-state"/>.
</para>
</sect2>
<sect2 xml:id="whatsnew-samples">
<title>Samples</title>
<para>
The process for building the samples included with the distribution has been simplified.
Maven can be used to build all samples in one step.
Eclipse settings include source code references to simplify debugging.
</para>
<para>
Additional samples can be accessed as follows:
<programlisting language="xml">mkdir spring-samples
cd spring-samples
svn co https://src.springframework.org/svn/spring-samples/webflow-primefaces-showcase
cd webflow-primefaces-showcase
mvn package
# import into Eclipse
</programlisting>
<programlisting language="xml">mkdir spring-samples
cd spring-samples
svn co https://src.springframework.org/svn/spring-samples/webflow-showcase
cd webflow-showcase
mvn package
# import into Eclipse
</programlisting>
</para>
</sect2>
</sect1>
</chapter>