made documentation related to webflow-config consistent with implementation
This commit is contained in:
@@ -22,7 +22,7 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
*
|
||||
* @author Jeremy Grelle
|
||||
*/
|
||||
public class FacesConfigNamespaceHandler extends NamespaceHandlerSupport {
|
||||
public class FacesNamespaceHandler extends NamespaceHandlerSupport {
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("flow-builder-services", new FacesFlowBuilderServicesBeanDefinitionParser());
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
http\://www.springframework.org/schema/faces=org.springframework.faces.config.FacesConfigNamespaceHandler
|
||||
http\://www.springframework.org/schema/faces=org.springframework.faces.config.FacesNamespaceHandler
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version='1.0' encoding="iso-8859-1"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY overview SYSTEM "overview.xml">
|
||||
<!ENTITY defining-flows SYSTEM "defining-flows.xml">
|
||||
|
||||
@@ -207,24 +207,18 @@
|
||||
Use the <code>flow-execution-repository</code> element to tune flow execution persistence settings:
|
||||
</para>
|
||||
<programlisting type="xml"><![CDATA[
|
||||
<flow-execution-repository max-conversations="5" max-snapshots="30" />]]>
|
||||
<flow-execution-repository max-executions="5" max-execution-snapshots="30" />]]>
|
||||
</programlisting>
|
||||
<sect3 id="repository-max-conversations">
|
||||
<title>max-conversations</title>
|
||||
<para>
|
||||
Tune the <code>max-conversations</code> attribute to place a cap on the number of conversations that can be created per user session.
|
||||
Tune the <code>max-executions</code> attribute to place a cap on the number of flow executions that can be created per user session.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3 id="repository-max-snapshots">
|
||||
<title>max-snapshots</title>
|
||||
<para>
|
||||
Tune the <code>max-snapshots</code> attribute to place a cap on the number of flow execution snapshots that can be taken per conversation.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3 id="repository-conversation-manager">
|
||||
<title>conversation-manager</title>
|
||||
<para>
|
||||
Set a custom <code>ConversationManager</code> to completely customize where conversational flow state is persisted.
|
||||
Tune the <code>max-execution-snapshots</code> attribute to place a cap on the number of history snapshots that can be taken per flow execution.
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
@@ -32,9 +32,6 @@
|
||||
|
||||
<!-- Executes flows: the central entry point into the Spring Web Flow system -->
|
||||
<webflow:flow-executor id="flowExecutor">
|
||||
<webflow:flow-execution-attributes>
|
||||
<webflow:always-redirect-on-pause value="false"/>
|
||||
</webflow:flow-execution-attributes>
|
||||
<webflow:flow-execution-listeners>
|
||||
<webflow:listener ref="jpaFlowExecutionListener" />
|
||||
</webflow:flow-execution-listeners>
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package org.springframework.webflow.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
@@ -36,22 +34,6 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
private static final String FORMATTER_REGISTRY_ATTRIBUTE = "formatter-registry";
|
||||
|
||||
private static final String CONVERSION_SERVICE_ATTRIBUTE = "conversion-service";
|
||||
|
||||
private static final String EXPRESSION_PARSER_ATTRIBUTE = "expression-parser";
|
||||
|
||||
private static final String VIEW_FACTORY_CREATOR_ATTRIBUTE = "view-factory-creator";
|
||||
|
||||
private static final String FORMATTER_REGISTRY_PROPERTY = "formatterRegistry";
|
||||
|
||||
private static final String CONVERSION_SERVICE_PROPERTY = "conversionService";
|
||||
|
||||
private static final String EXPRESSION_PARSER_PROPERTY = "expressionParser";
|
||||
|
||||
private static final String VIEW_FACTORY_CREATOR_PROPERTY = "viewFactoryCreator";
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return FlowBuilderServices.class;
|
||||
}
|
||||
@@ -64,66 +46,41 @@ class FlowBuilderServicesBeanDefinitionParser extends AbstractSingleBeanDefiniti
|
||||
}
|
||||
|
||||
private void parseFormatterRegistry(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) {
|
||||
String formatterRegistry = element.getAttribute(FORMATTER_REGISTRY_ATTRIBUTE);
|
||||
String formatterRegistry = element.getAttribute("formatter-registry");
|
||||
if (StringUtils.hasText(formatterRegistry)) {
|
||||
definitionBuilder.addPropertyReference(FORMATTER_REGISTRY_PROPERTY, formatterRegistry);
|
||||
definitionBuilder.addPropertyReference("formatterRegistry", formatterRegistry);
|
||||
} else {
|
||||
definitionBuilder.addPropertyValue(FORMATTER_REGISTRY_PROPERTY, DefaultFormatterRegistry
|
||||
.getSharedInstance());
|
||||
definitionBuilder.addPropertyValue("formatterRegistry", DefaultFormatterRegistry.getSharedInstance());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseConversionService(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) {
|
||||
String conversionService = element.getAttribute(CONVERSION_SERVICE_ATTRIBUTE);
|
||||
String conversionService = element.getAttribute("conversion-service");
|
||||
if (StringUtils.hasText(conversionService)) {
|
||||
definitionBuilder.addPropertyReference(CONVERSION_SERVICE_PROPERTY, conversionService);
|
||||
definitionBuilder.addPropertyReference("conversionService", conversionService);
|
||||
} else {
|
||||
definitionBuilder.addPropertyValue(CONVERSION_SERVICE_PROPERTY, DefaultConversionService
|
||||
.getSharedInstance());
|
||||
definitionBuilder.addPropertyValue("conversionService", DefaultConversionService.getSharedInstance());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseExpressionParser(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) {
|
||||
String expressionParser = element.getAttribute(EXPRESSION_PARSER_ATTRIBUTE);
|
||||
String expressionParser = element.getAttribute("expression-parser");
|
||||
if (StringUtils.hasText(expressionParser)) {
|
||||
definitionBuilder.addPropertyReference(EXPRESSION_PARSER_PROPERTY, expressionParser);
|
||||
definitionBuilder.addPropertyReference("expressionParser", expressionParser);
|
||||
} else {
|
||||
definitionBuilder.addPropertyValue(EXPRESSION_PARSER_PROPERTY, DefaultExpressionParserFactory
|
||||
.getExpressionParser());
|
||||
definitionBuilder
|
||||
.addPropertyValue("expressionParser", DefaultExpressionParserFactory.getExpressionParser());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseViewFactoryCreator(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext context) {
|
||||
String viewFactoryCreator = element.getAttribute(VIEW_FACTORY_CREATOR_ATTRIBUTE);
|
||||
String viewFactoryCreator = element.getAttribute("view-factory-creator");
|
||||
if (StringUtils.hasText(viewFactoryCreator)) {
|
||||
definitionBuilder.addPropertyReference(VIEW_FACTORY_CREATOR_PROPERTY, viewFactoryCreator);
|
||||
definitionBuilder.addPropertyReference("viewFactoryCreator", viewFactoryCreator);
|
||||
} else {
|
||||
definitionBuilder.addPropertyReference(VIEW_FACTORY_CREATOR_PROPERTY, createBeanDefinitionForClass(
|
||||
MvcViewFactoryCreator.class, context).getBeanName());
|
||||
definitionBuilder.addPropertyValue("viewFactoryCreator", BeanDefinitionBuilder.genericBeanDefinition(
|
||||
MvcViewFactoryCreator.class).getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
private BeanDefinitionHolder createBeanDefinitionForClass(Class clazz, ParserContext context) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
|
||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(builder.getBeanDefinition(), BeanDefinitionReaderUtils
|
||||
.generateBeanName(builder.getBeanDefinition(), context.getRegistry()));
|
||||
registerBeanDefinition(holder, context.getRegistry());
|
||||
return holder;
|
||||
}
|
||||
|
||||
public static BeanDefinitionHolder registerDefaultFlowBuilderServicesBeanDefinition(ParserContext context) {
|
||||
FlowBuilderServicesBeanDefinitionParser parser = new FlowBuilderServicesBeanDefinitionParser();
|
||||
BeanDefinitionBuilder defaultBuilder = BeanDefinitionBuilder.genericBeanDefinition(FlowBuilderServices.class);
|
||||
defaultBuilder.addPropertyValue(FORMATTER_REGISTRY_PROPERTY, DefaultFormatterRegistry.getSharedInstance());
|
||||
defaultBuilder.addPropertyValue(CONVERSION_SERVICE_PROPERTY, DefaultConversionService.getSharedInstance());
|
||||
defaultBuilder.addPropertyValue(EXPRESSION_PARSER_PROPERTY, DefaultExpressionParserFactory
|
||||
.getExpressionParser());
|
||||
defaultBuilder.addPropertyReference(VIEW_FACTORY_CREATOR_PROPERTY, parser.createBeanDefinitionForClass(
|
||||
MvcViewFactoryCreator.class, context).getBeanName());
|
||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(defaultBuilder.getBeanDefinition(),
|
||||
BeanDefinitionReaderUtils.generateBeanName(defaultBuilder.getBeanDefinition(), context.getRegistry()));
|
||||
parser.registerBeanDefinition(holder, context.getRegistry());
|
||||
return holder;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -28,31 +28,19 @@ import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinitionParser} for the <code><execution-listeners></code> tag.
|
||||
* {@link BeanDefinitionParser} for the <code><flow-execution-listeners></code> tag.
|
||||
*
|
||||
* @author Ben Hale
|
||||
*/
|
||||
class FlowExecutionListenerLoaderBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
// elements and attributes
|
||||
|
||||
private static final String LISTENER_ELEMENT = "listener";
|
||||
|
||||
private static final String CRITERIA_ATTRIBUTE = "criteria";
|
||||
|
||||
private static final String REF_ATTRIBUTE = "ref";
|
||||
|
||||
// properties
|
||||
|
||||
private static final String LISTENERS_PROPERTY = "listeners";
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return FlowExecutionListenerLoaderFactoryBean.class;
|
||||
}
|
||||
|
||||
protected void doParse(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
List listenerElements = DomUtils.getChildElementsByTagName(element, LISTENER_ELEMENT);
|
||||
definitionBuilder.addPropertyValue(LISTENERS_PROPERTY, getListenersWithCriteria(listenerElements));
|
||||
List listenerElements = DomUtils.getChildElementsByTagName(element, "listener");
|
||||
definitionBuilder.addPropertyValue("listeners", parseListenersWithCriteria(listenerElements));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,12 +49,12 @@ class FlowExecutionListenerLoaderBeanDefinitionParser extends AbstractSingleBean
|
||||
* @return a map containing keys that are references to given listeners and values of string that represent the
|
||||
* criteria
|
||||
*/
|
||||
private Map getListenersWithCriteria(List listeners) {
|
||||
private Map parseListenersWithCriteria(List listeners) {
|
||||
Map listenersWithCriteria = new ManagedMap(listeners.size());
|
||||
for (Iterator i = listeners.iterator(); i.hasNext();) {
|
||||
Element listenerElement = (Element) i.next();
|
||||
RuntimeBeanReference ref = new RuntimeBeanReference(listenerElement.getAttribute(REF_ATTRIBUTE));
|
||||
String criteria = listenerElement.getAttribute(CRITERIA_ATTRIBUTE);
|
||||
RuntimeBeanReference ref = new RuntimeBeanReference(listenerElement.getAttribute("ref"));
|
||||
String criteria = listenerElement.getAttribute("criteria");
|
||||
listenersWithCriteria.put(ref, criteria);
|
||||
}
|
||||
return listenersWithCriteria;
|
||||
|
||||
@@ -35,129 +35,19 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
class FlowExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
// elements and attributes
|
||||
|
||||
private static final String CONVERSATION_MANAGER_REF_ATTRIBUTE = "conversation-manager";
|
||||
|
||||
private static final String EXECUTION_ATTRIBUTES_ELEMENT = "flow-execution-attributes";
|
||||
|
||||
private static final String ALWAYS_REDIRECT_ON_PAUSE_ELEMENT = "always-redirect-on-pause";
|
||||
|
||||
private static final String ATTRIBUTE_ELEMENT = "attribute";
|
||||
|
||||
private static final String NAME_ATTRIBUTE = "name";
|
||||
|
||||
private static final String VALUE_ATTRIBUTE = "value";
|
||||
|
||||
private static final String TYPE_ATTRIBUTE = "type";
|
||||
|
||||
private static final String EXECUTION_LISTENERS_ELEMENT = "flow-execution-listeners";
|
||||
|
||||
private static final String MAX_CONTINUATIONS_ATTRIBUTE = "max-continuations";
|
||||
|
||||
private static final String MAX_CONVERSATIONS_ATTRIBUTE = "max-conversations";
|
||||
|
||||
private static final String REGISTRY_ATTRIBUTE = "flow-registry";
|
||||
|
||||
private static final String REPOSITORY_ELEMENT = "flow-execution-repository";
|
||||
|
||||
// properties
|
||||
|
||||
private static final String CONVERSATION_MANAGER_PROPERTY = "conversationManager";
|
||||
|
||||
private static final String DEFINITION_LOCATOR_PROPERTY = "flowDefinitionLocator";
|
||||
|
||||
private static final String REPOSITORY_TYPE_PROPERTY = "flowExecutionRepositoryType";
|
||||
|
||||
private static final String EXECUTION_ATTRIBUTES_PROPERTY = "flowExecutionAttributes";
|
||||
|
||||
private static final String EXECUTION_LISTENER_LOADER_PROPERTY = "flowExecutionListenerLoader";
|
||||
|
||||
private static final String MAX_CONTINUATIONS_PROPERTY = "maxContinuations";
|
||||
|
||||
private static final String MAX_CONVERSATIONS_PROPERTY = "maxConversations";
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return FlowExecutorFactoryBean.class;
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder definitionBuilder) {
|
||||
definitionBuilder.addPropertyReference(DEFINITION_LOCATOR_PROPERTY, getRegistry(element, parserContext));
|
||||
definitionBuilder.addPropertyValue(EXECUTION_ATTRIBUTES_PROPERTY, parseAttributes(element));
|
||||
addExecutionListenerLoader(element, parserContext, definitionBuilder);
|
||||
configureRepository(element, definitionBuilder, parserContext);
|
||||
definitionBuilder.addPropertyReference("flowDefinitionLocator", getFlowRegistry(element, parserContext));
|
||||
addFlowExecutionRepositoryProperties(element, definitionBuilder, parserContext);
|
||||
definitionBuilder.addPropertyValue("flowExecutionAttributes", parseFlowExecutionAttributes(element));
|
||||
addFlowExecutionListenerLoader(element, parserContext, definitionBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a repository based on the <code>repository-type</code> attribute or a <code>repository</code> tag.
|
||||
* @param element the root element to extract repository configuration from
|
||||
* @param definitionBuilder the builder
|
||||
* @param parserContext the parserContext
|
||||
*/
|
||||
private void configureRepository(Element element, BeanDefinitionBuilder definitionBuilder,
|
||||
ParserContext parserContext) {
|
||||
Element repositoryElement = DomUtils.getChildElementByTagName(element, REPOSITORY_ELEMENT);
|
||||
if (repositoryElement != null) {
|
||||
String type = getType(element);
|
||||
if (StringUtils.hasText(type)) {
|
||||
definitionBuilder.addPropertyValue(REPOSITORY_TYPE_PROPERTY, type);
|
||||
}
|
||||
configureContinuations(repositoryElement, definitionBuilder, parserContext);
|
||||
configureConversationManager(repositoryElement, definitionBuilder, parserContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the max continuations setting.
|
||||
* @param repositoryElement the repository element
|
||||
* @param definitionBuilder the builder
|
||||
* @param parserContext the parserContext
|
||||
*/
|
||||
private void configureContinuations(Element repositoryElement, BeanDefinitionBuilder definitionBuilder,
|
||||
ParserContext parserContext) {
|
||||
String maxContinuations = getMaxContinuations(repositoryElement);
|
||||
if (StringUtils.hasText(maxContinuations)) {
|
||||
String type = getType(repositoryElement);
|
||||
if (StringUtils.hasText(type) && !type.toLowerCase().equals("CONTINUATION")) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The 'max-continuations' attribute of the 'flow-execution-repository' element must not "
|
||||
+ "have a value if the 'type' attribute is not 'continuation'", repositoryElement);
|
||||
}
|
||||
definitionBuilder.addPropertyValue(MAX_CONTINUATIONS_PROPERTY, maxContinuations);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the conversation manager
|
||||
* @param repositoryElement the repository element
|
||||
* @param definitionBuilder the builder
|
||||
* @param parserContext the parserContext
|
||||
*/
|
||||
private void configureConversationManager(Element repositoryElement, BeanDefinitionBuilder definitionBuilder,
|
||||
ParserContext parserContext) {
|
||||
String conversationManagerRef = getConversationManagerRef(repositoryElement);
|
||||
String maxConversations = getMaxConversations(repositoryElement);
|
||||
if (StringUtils.hasText(conversationManagerRef)) {
|
||||
if (StringUtils.hasText(maxConversations)) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The 'max-conversations' attribute of the 'flow-execution-repository' element must not "
|
||||
+ "have a value if there is a value for the 'conversation-manager' attribute",
|
||||
repositoryElement);
|
||||
}
|
||||
definitionBuilder.addPropertyReference(CONVERSATION_MANAGER_PROPERTY, conversationManagerRef);
|
||||
} else if (StringUtils.hasText(maxConversations)) {
|
||||
definitionBuilder.addPropertyValue(MAX_CONVERSATIONS_PROPERTY, maxConversations);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the registry detailed in the bean definition.
|
||||
* @param element the element to extract the registry name from
|
||||
* @return the name of the registry
|
||||
* @param parserContext the parserContext
|
||||
*/
|
||||
private String getRegistry(Element element, ParserContext parserContext) {
|
||||
String registry = element.getAttribute(REGISTRY_ATTRIBUTE);
|
||||
private String getFlowRegistry(Element element, ParserContext parserContext) {
|
||||
String registry = element.getAttribute("flow-registry");
|
||||
if (!StringUtils.hasText(registry)) {
|
||||
return "flowRegistry";
|
||||
} else {
|
||||
@@ -165,70 +55,45 @@ class FlowExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionParse
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the repository type enum field detailed in the bean definition.
|
||||
* @param element the element to extract the repository type from
|
||||
* @return the type of the repository
|
||||
*/
|
||||
private String getType(Element element) {
|
||||
return element.getAttribute(TYPE_ATTRIBUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of continuations detailed in the bean definition.
|
||||
* @param element the element to extract the max continuations from
|
||||
* @return the max continuations
|
||||
*/
|
||||
private String getMaxContinuations(Element element) {
|
||||
return element.getAttribute(MAX_CONTINUATIONS_ATTRIBUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of conversations detailed in the bean definition.
|
||||
* @param element the element to extract the max conversations from
|
||||
* @return the max conversations
|
||||
*/
|
||||
private String getMaxConversations(Element element) {
|
||||
return element.getAttribute(MAX_CONVERSATIONS_ATTRIBUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the conversation manager detailed in the bean definition.
|
||||
* @param element the element to extract the conversation manager name from
|
||||
* @return the name of the conversation manager
|
||||
*/
|
||||
private String getConversationManagerRef(Element element) {
|
||||
return element.getAttribute(CONVERSATION_MANAGER_REF_ATTRIBUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse execution listener definitions contained in given element.
|
||||
*/
|
||||
private void addExecutionListenerLoader(Element element, ParserContext parserContext,
|
||||
BeanDefinitionBuilder definitionBuilder) {
|
||||
Element listenersElement = DomUtils.getChildElementByTagName(element, EXECUTION_LISTENERS_ELEMENT);
|
||||
if (listenersElement != null) {
|
||||
definitionBuilder.addPropertyValue(EXECUTION_LISTENER_LOADER_PROPERTY, parserContext.getDelegate()
|
||||
.parseCustomElement(listenersElement, definitionBuilder.getBeanDefinition()));
|
||||
private void addFlowExecutionRepositoryProperties(Element element, BeanDefinitionBuilder definitionBuilder,
|
||||
ParserContext parserContext) {
|
||||
Element repositoryElement = DomUtils.getChildElementByTagName(element, "flow-execution-repository");
|
||||
if (repositoryElement != null) {
|
||||
addMaxExecutions(repositoryElement, definitionBuilder, parserContext);
|
||||
addMaxSnapshots(repositoryElement, definitionBuilder, parserContext);
|
||||
}
|
||||
}
|
||||
|
||||
private Set parseAttributes(Element element) {
|
||||
Element executionAttributesElement = DomUtils.getChildElementByTagName(element, EXECUTION_ATTRIBUTES_ELEMENT);
|
||||
private void addMaxExecutions(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext parserContext) {
|
||||
String maxConversations = element.getAttribute("max-executions");
|
||||
if (StringUtils.hasText(maxConversations)) {
|
||||
definitionBuilder.addPropertyValue("maxFlowExecutions", maxConversations);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMaxSnapshots(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext parserContext) {
|
||||
String maxSnapshots = element.getAttribute("max-execution-snapshots");
|
||||
if (StringUtils.hasText(maxSnapshots)) {
|
||||
definitionBuilder.addPropertyValue("maxFlowExecutionSnapshots", maxSnapshots);
|
||||
}
|
||||
}
|
||||
|
||||
private Set parseFlowExecutionAttributes(Element element) {
|
||||
Element executionAttributesElement = DomUtils.getChildElementByTagName(element, "flow-execution-attributes");
|
||||
if (executionAttributesElement != null) {
|
||||
HashSet attributes = new HashSet();
|
||||
Element redirectElement = DomUtils.getChildElementByTagName(executionAttributesElement,
|
||||
ALWAYS_REDIRECT_ON_PAUSE_ELEMENT);
|
||||
"always-redirect-on-pause");
|
||||
if (redirectElement != null) {
|
||||
String value = redirectElement.getAttribute(VALUE_ATTRIBUTE);
|
||||
String value = redirectElement.getAttribute("value");
|
||||
attributes.add(new FlowElementAttribute("alwaysRedirectOnPause", value, "boolean"));
|
||||
}
|
||||
List attributeElements = DomUtils.getChildElementsByTagName(executionAttributesElement, ATTRIBUTE_ELEMENT);
|
||||
List attributeElements = DomUtils.getChildElementsByTagName(executionAttributesElement, "attribute");
|
||||
for (Iterator it = attributeElements.iterator(); it.hasNext();) {
|
||||
Element attributeElement = (Element) it.next();
|
||||
String name = attributeElement.getAttribute(NAME_ATTRIBUTE);
|
||||
String value = attributeElement.getAttribute(VALUE_ATTRIBUTE);
|
||||
String type = attributeElement.getAttribute(TYPE_ATTRIBUTE);
|
||||
String name = attributeElement.getAttribute("name");
|
||||
String value = attributeElement.getAttribute("value");
|
||||
String type = attributeElement.getAttribute("type");
|
||||
attributes.add(new FlowElementAttribute(name, value, type));
|
||||
}
|
||||
return attributes;
|
||||
@@ -236,4 +101,13 @@ class FlowExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionParse
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void addFlowExecutionListenerLoader(Element element, ParserContext parserContext,
|
||||
BeanDefinitionBuilder definitionBuilder) {
|
||||
Element listenersElement = DomUtils.getChildElementByTagName(element, "flow-execution-listeners");
|
||||
if (listenersElement != null) {
|
||||
definitionBuilder.addPropertyValue("flowExecutionListenerLoader", parserContext.getDelegate()
|
||||
.parseCustomElement(listenersElement, definitionBuilder.getBeanDefinition()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,14 @@ package org.springframework.webflow.config;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
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.webflow.conversation.ConversationManager;
|
||||
import org.springframework.webflow.conversation.impl.SessionBindingConversationManager;
|
||||
@@ -41,73 +44,38 @@ import org.springframework.webflow.execution.repository.impl.DefaultFlowExecutio
|
||||
import org.springframework.webflow.execution.repository.support.FlowExecutionStateRestorer;
|
||||
import org.springframework.webflow.executor.FlowExecutor;
|
||||
import org.springframework.webflow.executor.FlowExecutorImpl;
|
||||
import org.springframework.webflow.mvc.builder.MvcEnvironment;
|
||||
|
||||
/**
|
||||
* The default flow executor factory implementation. As a <code>FactoryBean</code>, this class has been designed for
|
||||
* use as a Spring managed bean.
|
||||
* <p>
|
||||
* This factory encapsulates the construction and assembly of a {@link FlowExecutor}, including the provision of its
|
||||
* {@link FlowExecutionRepository} strategy.
|
||||
* {@link FlowExecutionRepository} strategy. As a <code>FactoryBean</code>, this class has been designed for use as a
|
||||
* Spring managed bean.
|
||||
* <p>
|
||||
* The definition locator property is required, all other properties are optional.
|
||||
* <p>
|
||||
* This class has been designed with subclassing in mind. If you want to do advanced Spring Web Flow customization, e.g.
|
||||
* using a custom {@link org.springframework.webflow.executor.FlowExecutor} implementation, consider subclassing this
|
||||
* class and overriding one or more of the provided hook methods.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, InitializingBean {
|
||||
|
||||
private static final String ALWAYS_REDIRECT_ON_PAUSE = "alwaysRedirectOnPause";
|
||||
|
||||
/**
|
||||
* The locator the executor will use to access flow definitions registered in a central registry. Required.
|
||||
*/
|
||||
private FlowDefinitionLocator flowDefinitionLocator;
|
||||
|
||||
/**
|
||||
* Execution attributes to apply.
|
||||
*/
|
||||
private Integer maxFlowExecutions;
|
||||
|
||||
private Integer maxFlowExecutionSnapshots;
|
||||
|
||||
private Set flowExecutionAttributes;
|
||||
|
||||
/**
|
||||
* The loader that will determine which listeners to attach to flow definition executions.
|
||||
*/
|
||||
private FlowExecutionListenerLoader flowExecutionListenerLoader;
|
||||
|
||||
/**
|
||||
* The conversation manager to be used by the flow execution repository to store state associated with conversations
|
||||
* driven by Spring Web Flow.
|
||||
*/
|
||||
private ConversationManager conversationManager;
|
||||
|
||||
/**
|
||||
* The maximum number of allowed concurrent conversations in the session.
|
||||
*/
|
||||
private Integer maxConversations;
|
||||
|
||||
/**
|
||||
* The type of execution repository to configure with executors created by this factory. Optional. Will fallback to
|
||||
* default value if not set.
|
||||
*/
|
||||
private FlowExecutionRepositoryType flowExecutionRepositoryType;
|
||||
|
||||
/**
|
||||
* The maximum number of allowed continuations for a single conversation. Only used when the repository type is
|
||||
* {@link FlowExecutionRepositoryType#CONTINUATION}.
|
||||
*/
|
||||
private Integer maxContinuations;
|
||||
|
||||
/**
|
||||
* The conversion service to use for type conversion of flow execution attribute values.
|
||||
*/
|
||||
private ConversionService conversionService = DefaultConversionService.getSharedInstance();
|
||||
|
||||
/**
|
||||
* The flow executor this factory bean creates.
|
||||
*/
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
private MvcEnvironment environment;
|
||||
|
||||
/**
|
||||
* Sets the flow definition locator that will locate flow definitions needed for execution. Typically also a
|
||||
* {@link FlowDefinitionRegistry}. Required.
|
||||
@@ -117,6 +85,20 @@ class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
this.flowDefinitionLocator = flowDefinitionLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of allowed flow executions allowed per user.
|
||||
*/
|
||||
public void setMaxFlowExecutions(int maxFlowExecutions) {
|
||||
this.maxFlowExecutions = new Integer(maxFlowExecutions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of history snapshots allowed per flow execution.
|
||||
*/
|
||||
public void setMaxFlowExecutionSnapshots(int maxFlowExecutionSnapshots) {
|
||||
this.maxFlowExecutionSnapshots = new Integer(maxFlowExecutionSnapshots);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the system attributes that apply to flow executions launched by the executor created by this factory.
|
||||
* Execution attributes may affect flow execution behavior.
|
||||
@@ -135,84 +117,20 @@ class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
this.flowExecutionListenerLoader = flowExecutionListenerLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of flow execution repository that should be configured for the flow executors created by this
|
||||
* factory. This factory encapsulates the construction of the repository implementation corresponding to the
|
||||
* provided type.
|
||||
* @param repositoryType the flow execution repository type
|
||||
*/
|
||||
public void setFlowExecutionRepositoryType(FlowExecutionRepositoryType repositoryType) {
|
||||
this.flowExecutionRepositoryType = repositoryType;
|
||||
}
|
||||
// implementing ApplicationContextAware
|
||||
|
||||
/**
|
||||
* Set the maximum number of continuation snapshots allowed for a single conversation when using the
|
||||
*/
|
||||
public void setMaxContinuations(int maxContinuations) {
|
||||
this.maxContinuations = new Integer(maxContinuations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of allowed concurrent conversations in the session. This is a convenience setter to allow
|
||||
* easy configuration of the maxConversations property of the default {@link SessionBindingConversationManager}. Do
|
||||
* not use this when an explicit conversation manager is configured.
|
||||
* @see SessionBindingConversationManager#setMaxConversations(int)
|
||||
*/
|
||||
public void setMaxConversations(int maxConversations) {
|
||||
this.maxConversations = new Integer(maxConversations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy for managing conversations that should be configured for flow executors created by this
|
||||
* factory.
|
||||
* <p>
|
||||
* The conversation manager is used by the flow execution repository subsystem to begin and end new conversations
|
||||
* that store execution state.
|
||||
* <p>
|
||||
* By default, a {@link SessionBindingConversationManager} is used. Do not use setMaxConversations when using this
|
||||
* method.
|
||||
*/
|
||||
public void setConversationManager(ConversationManager conversationManager) {
|
||||
this.conversationManager = conversationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO never called. Sets the conversion service for converting string-encoded flow execution attributes to typed
|
||||
* values.
|
||||
* @param conversionService the conversion service
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
environment = MvcEnvironment.environmentFor(applicationContext);
|
||||
}
|
||||
|
||||
// implementing InitializingBean
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(flowDefinitionLocator, "The flow definition locator property is required");
|
||||
|
||||
// apply defaults
|
||||
FlowExecutorSystemDefaults defaults = new FlowExecutorSystemDefaults();
|
||||
|
||||
MutableAttributeMap executionAttributes = defaults.applyExecutionAttributes(createExecutionAttributeMap());
|
||||
flowExecutionRepositoryType = defaults.applyIfNecessary(flowExecutionRepositoryType);
|
||||
|
||||
// pass all available parameters to the hook methods so that they
|
||||
// can participate in the construction process
|
||||
|
||||
// a strategy to restore deserialized flow executions
|
||||
FlowExecutionStateRestorer executionStateRestorer = createFlowExecutionStateRestorer(flowDefinitionLocator,
|
||||
executionAttributes, flowExecutionListenerLoader);
|
||||
|
||||
// a repository to store flow executions
|
||||
FlowExecutionRepository executionRepository = createFlowExecutionRepository(flowExecutionRepositoryType,
|
||||
executionStateRestorer, conversationManager);
|
||||
|
||||
// a factory for flow executions
|
||||
FlowExecutionFactory executionFactory = createFlowExecutionFactory(executionAttributes,
|
||||
flowExecutionListenerLoader, (FlowExecutionKeyFactory) executionRepository);
|
||||
|
||||
// combine all pieces of the puzzle to get an operational flow executor
|
||||
flowExecutor = createFlowExecutor(flowDefinitionLocator, executionFactory, executionRepository);
|
||||
MutableAttributeMap executionAttributes = createFlowExecutionAttributes();
|
||||
DefaultFlowExecutionRepository executionRepository = createFlowExecutionRepository(executionAttributes);
|
||||
FlowExecutionFactory executionFactory = createFlowExecutionFactory(executionAttributes, executionRepository);
|
||||
flowExecutor = new FlowExecutorImpl(flowDefinitionLocator, executionFactory, executionRepository);
|
||||
}
|
||||
|
||||
// implementing FactoryBean
|
||||
@@ -229,110 +147,7 @@ class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
return flowExecutor;
|
||||
}
|
||||
|
||||
// subclassing hook methods
|
||||
|
||||
/**
|
||||
* Create the flow execution state restorer to be used by the executor produced by this factory bean. Configure the
|
||||
* state restorer appropriately. Subclasses may override if they which to use a custom state restorer
|
||||
* implementation.
|
||||
* @param definitionLocator the definition locator to use
|
||||
* @param executionAttributes execution attributes to apply to restored executions
|
||||
* @param executionListenerLoader decides which listeners should apply to restored flow executions
|
||||
* @return a new state restorer instance
|
||||
*/
|
||||
protected FlowExecutionStateRestorer createFlowExecutionStateRestorer(FlowDefinitionLocator definitionLocator,
|
||||
AttributeMap executionAttributes, FlowExecutionListenerLoader executionListenerLoader) {
|
||||
FlowExecutionImplStateRestorer executionStateRestorer = new FlowExecutionImplStateRestorer(definitionLocator);
|
||||
executionStateRestorer.setExecutionAttributes(executionAttributes);
|
||||
if (executionListenerLoader != null) {
|
||||
executionStateRestorer.setExecutionListenerLoader(executionListenerLoader);
|
||||
}
|
||||
return executionStateRestorer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating the flow execution repository for saving and loading executing flows. Subclasses may
|
||||
* override to customize the repository implementation used.
|
||||
* @param repositoryType a hint indicating what type of repository to create
|
||||
* @param executionStateRestorer the execution state restorer strategy to be used by the repository
|
||||
* @param conversationManager the conversation manager specified by the user, could be null in which case the
|
||||
* default conversation manager should be used
|
||||
* @return a new flow execution repository instance
|
||||
*/
|
||||
protected FlowExecutionRepository createFlowExecutionRepository(FlowExecutionRepositoryType repositoryType,
|
||||
FlowExecutionStateRestorer executionStateRestorer, ConversationManager conversationManager) {
|
||||
if (conversationManager == null) {
|
||||
conversationManager = createDefaultConversationManager();
|
||||
}
|
||||
if (repositoryType == null || repositoryType == FlowExecutionRepositoryType.CONTINUATION) {
|
||||
DefaultFlowExecutionRepository repository = new DefaultFlowExecutionRepository(conversationManager,
|
||||
executionStateRestorer);
|
||||
if (maxContinuations != null) {
|
||||
repository.setMaxContinuations(maxContinuations.intValue());
|
||||
}
|
||||
return repository;
|
||||
} else if (repositoryType == FlowExecutionRepositoryType.SIMPLE) {
|
||||
DefaultFlowExecutionRepository repository = new DefaultFlowExecutionRepository(conversationManager,
|
||||
executionStateRestorer);
|
||||
repository.setMaxContinuations(1);
|
||||
return repository;
|
||||
} else if (repositoryType == FlowExecutionRepositoryType.SINGLEKEY) {
|
||||
DefaultFlowExecutionRepository repository = new DefaultFlowExecutionRepository(conversationManager,
|
||||
executionStateRestorer);
|
||||
repository.setAlwaysGenerateNewNextKey(false);
|
||||
return repository;
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot create execution repository - unsupported repository type "
|
||||
+ repositoryType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the conversation manager to be used in the default case, e.g. when no explicit conversation manager has
|
||||
* been configured. This implementation return a {@link SessionBindingConversationManager}.
|
||||
* @return the default conversation manager
|
||||
*/
|
||||
protected ConversationManager createDefaultConversationManager() {
|
||||
SessionBindingConversationManager conversationManager = new SessionBindingConversationManager();
|
||||
if (maxConversations != null) {
|
||||
conversationManager.setMaxConversations(maxConversations.intValue());
|
||||
}
|
||||
return conversationManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the flow execution factory to be used by the executor produced by this factory bean. Configure the
|
||||
* execution factory appropriately. Subclasses may override if they which to use a custom execution factory, e.g. to
|
||||
* use a custom FlowExecution implementation.
|
||||
* @param executionAttributes execution attributes to apply to created executions
|
||||
* @param executionListenerLoader decides which listeners to apply to created executions
|
||||
* @return a new flow execution factory instance
|
||||
*/
|
||||
protected FlowExecutionFactory createFlowExecutionFactory(AttributeMap executionAttributes,
|
||||
FlowExecutionListenerLoader executionListenerLoader, FlowExecutionKeyFactory keyFactory) {
|
||||
FlowExecutionImplFactory executionFactory = new FlowExecutionImplFactory();
|
||||
executionFactory.setExecutionAttributes(executionAttributes);
|
||||
if (executionListenerLoader != null) {
|
||||
executionFactory.setExecutionListenerLoader(executionListenerLoader);
|
||||
}
|
||||
executionFactory.setExecutionKeyFactory(keyFactory);
|
||||
return executionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the flow executor instance created by this factory bean and configure it appropriately. Subclasses may
|
||||
* override if they which to use a custom executor implementation.
|
||||
* @param definitionLocator the definition locator to use
|
||||
* @param executionFactory the execution factory to use
|
||||
* @param executionRepository the execution repository to use
|
||||
* @return a new flow executor instance
|
||||
*/
|
||||
protected FlowExecutor createFlowExecutor(FlowDefinitionLocator definitionLocator,
|
||||
FlowExecutionFactory executionFactory, FlowExecutionRepository executionRepository) {
|
||||
return new FlowExecutorImpl(definitionLocator, executionFactory, executionRepository);
|
||||
}
|
||||
|
||||
private MutableAttributeMap createExecutionAttributeMap() {
|
||||
private MutableAttributeMap createFlowExecutionAttributes() {
|
||||
LocalAttributeMap executionAttributes = new LocalAttributeMap();
|
||||
if (flowExecutionAttributes != null) {
|
||||
for (Iterator it = flowExecutionAttributes.iterator(); it.hasNext();) {
|
||||
@@ -340,9 +155,62 @@ class FlowExecutorFactoryBean implements FactoryBean, InitializingBean {
|
||||
executionAttributes.put(attribute.getName(), getConvertedValue(attribute));
|
||||
}
|
||||
}
|
||||
putDefaultFlowExecutionAttributes(executionAttributes);
|
||||
return executionAttributes;
|
||||
}
|
||||
|
||||
private void putDefaultFlowExecutionAttributes(LocalAttributeMap executionAttributes) {
|
||||
if (!executionAttributes.contains(ALWAYS_REDIRECT_ON_PAUSE)) {
|
||||
if (environment == MvcEnvironment.PORTLET) {
|
||||
executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, Boolean.FALSE);
|
||||
} else {
|
||||
executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DefaultFlowExecutionRepository createFlowExecutionRepository(AttributeMap executionAttributes) {
|
||||
ConversationManager conversationManager = createConversationManager();
|
||||
FlowExecutionStateRestorer executionStateRestorer = createFlowExecutionStateRestorer(executionAttributes);
|
||||
DefaultFlowExecutionRepository repository = new DefaultFlowExecutionRepository(conversationManager,
|
||||
executionStateRestorer);
|
||||
if (maxFlowExecutionSnapshots != null) {
|
||||
repository.setMaxContinuations(maxFlowExecutionSnapshots.intValue());
|
||||
}
|
||||
return repository;
|
||||
}
|
||||
|
||||
private ConversationManager createConversationManager() {
|
||||
SessionBindingConversationManager conversationManager = new SessionBindingConversationManager();
|
||||
if (maxFlowExecutions != null) {
|
||||
conversationManager.setMaxConversations(maxFlowExecutions.intValue());
|
||||
}
|
||||
return conversationManager;
|
||||
}
|
||||
|
||||
private FlowExecutionStateRestorer createFlowExecutionStateRestorer(AttributeMap executionAttributes) {
|
||||
FlowExecutionImplStateRestorer executionStateRestorer = new FlowExecutionImplStateRestorer(
|
||||
flowDefinitionLocator);
|
||||
executionStateRestorer.setExecutionAttributes(executionAttributes);
|
||||
if (flowExecutionListenerLoader != null) {
|
||||
executionStateRestorer.setExecutionListenerLoader(flowExecutionListenerLoader);
|
||||
}
|
||||
return executionStateRestorer;
|
||||
}
|
||||
|
||||
private FlowExecutionFactory createFlowExecutionFactory(AttributeMap executionAttributes,
|
||||
FlowExecutionKeyFactory keyFactory) {
|
||||
FlowExecutionImplFactory executionFactory = new FlowExecutionImplFactory();
|
||||
executionFactory.setExecutionAttributes(executionAttributes);
|
||||
if (flowExecutionListenerLoader != null) {
|
||||
executionFactory.setExecutionListenerLoader(flowExecutionListenerLoader);
|
||||
}
|
||||
executionFactory.setExecutionKeyFactory(keyFactory);
|
||||
return executionFactory;
|
||||
}
|
||||
|
||||
// utility methods
|
||||
|
||||
private Object getConvertedValue(FlowElementAttribute attribute) {
|
||||
if (attribute.needsTypeConversion()) {
|
||||
Class targetType = fromStringToClass(attribute.getType());
|
||||
|
||||
@@ -1,91 +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.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.webflow.core.collection.LocalAttributeMap;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
|
||||
/**
|
||||
* Encapsulates overall flow system configuration defaults. Allows for centralized application of, and if necessary,
|
||||
* overridding of system-wide default values.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
class FlowExecutorSystemDefaults implements Serializable {
|
||||
|
||||
/**
|
||||
* The default 'alwaysRedirectOnPause' execution attribute value.
|
||||
*/
|
||||
private boolean alwaysRedirectOnPause = true;
|
||||
|
||||
/**
|
||||
* The default flow execution repository type.
|
||||
*/
|
||||
private FlowExecutionRepositoryType repositoryType = FlowExecutionRepositoryType.CONTINUATION;
|
||||
|
||||
/**
|
||||
* Overrides the alwaysRedirectOnPause execution attribute default. Defaults to "true".
|
||||
* @param alwaysRedirectOnPause the new default value
|
||||
*/
|
||||
public void setAlwaysRedirectOnPause(boolean alwaysRedirectOnPause) {
|
||||
this.alwaysRedirectOnPause = alwaysRedirectOnPause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default repository type.
|
||||
* @param repositoryType the new default value
|
||||
*/
|
||||
public void setRepositoryType(FlowExecutionRepositoryType repositoryType) {
|
||||
this.repositoryType = repositoryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies default execution attributes if necessary. Defaults will only apply in the case where the user did not
|
||||
* configure a value, or explicitly requested the 'default' value.
|
||||
* @param executionAttributes the user-configured execution attribute map
|
||||
* @return the map with defaults applied as appropriate
|
||||
*/
|
||||
public MutableAttributeMap applyExecutionAttributes(MutableAttributeMap executionAttributes) {
|
||||
if (executionAttributes == null) {
|
||||
executionAttributes = new LocalAttributeMap(1, 1);
|
||||
}
|
||||
if (!executionAttributes.contains("alwaysRedirectOnPause")) {
|
||||
executionAttributes.put("alwaysRedirectOnPause", new Boolean(alwaysRedirectOnPause));
|
||||
}
|
||||
return executionAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the default repository type if requested by the user.
|
||||
* @param selectedType the selected repository type (may be null if no selection was made)
|
||||
* @return the repository type, with the default applied if necessary
|
||||
*/
|
||||
public FlowExecutionRepositoryType applyIfNecessary(FlowExecutionRepositoryType selectedType) {
|
||||
if (selectedType == null) {
|
||||
return repositoryType;
|
||||
} else {
|
||||
return selectedType;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("alwaysRedirectOnPause", alwaysRedirectOnPause).append(
|
||||
"repositoryType", repositoryType).toString();
|
||||
}
|
||||
}
|
||||
@@ -22,12 +22,18 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.binding.convert.service.DefaultConversionService;
|
||||
import org.springframework.binding.format.registry.DefaultFormatterRegistry;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
|
||||
import org.springframework.webflow.expression.DefaultExpressionParserFactory;
|
||||
import org.springframework.webflow.mvc.builder.MvcViewFactoryCreator;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
@@ -37,103 +43,65 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
class FlowRegistryBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
private static final String FLOW_BUILDER_SERVICES_ATTRIBUTE = "flow-builder-services";
|
||||
|
||||
private static final String PARENT_ATTRIBUTE = "parent";
|
||||
|
||||
private static final String FLOW_LOCATION_ELEMENT = "flow-location";
|
||||
|
||||
private static final String FLOW_LOCATION_PATTERN_ELEMENT = "flow-location-pattern";
|
||||
|
||||
private static final String FLOW_BUILDER_ELEMENT = "flow-builder";
|
||||
|
||||
private static final String ID_ATTRIBUTE = "id";
|
||||
|
||||
private static final String PATH_ATTRIBUTE = "path";
|
||||
|
||||
private static final String CLASS_ATTRIBUTE = "class";
|
||||
|
||||
private static final String DEFINITION_ATTRIBUTES_ELEMENT = "flow-definition-attributes";
|
||||
|
||||
private static final String ATTRIBUTE_ELEMENT = "attribute";
|
||||
|
||||
private static final String NAME_ATTRIBUTE = "name";
|
||||
|
||||
private static final String VALUE_ATTRIBUTE = "value";
|
||||
|
||||
private static final String TYPE_ATTRIBUTE = "type";
|
||||
|
||||
private static final String FLOW_LOCATIONS_PROPERTY = "flowLocations";
|
||||
|
||||
private static final String FLOW_LOCATION_PATTERNS_PROPERTY = "flowLocationPatterns";
|
||||
|
||||
private static final String FLOW_BUILDERS_PROPERTY = "flowBuilders";
|
||||
|
||||
private static final String FLOW_BUILDER_SERVICES_PROPERTY = "flowBuilderServices";
|
||||
|
||||
private static final String PARENT_PROPERTY = "parent";
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return FlowRegistryFactoryBean.class;
|
||||
}
|
||||
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder definitionBuilder) {
|
||||
String flowBuilderServices = getFlowBuilderServicesAttribute(element);
|
||||
String flowBuilderServices = element.getAttribute("flow-builder-services");
|
||||
if (StringUtils.hasText(flowBuilderServices)) {
|
||||
definitionBuilder.addPropertyReference(FLOW_BUILDER_SERVICES_PROPERTY, flowBuilderServices);
|
||||
definitionBuilder.addPropertyReference("flowBuilderServices", flowBuilderServices);
|
||||
} else {
|
||||
definitionBuilder.addPropertyReference(FLOW_BUILDER_SERVICES_PROPERTY,
|
||||
FlowBuilderServicesBeanDefinitionParser.registerDefaultFlowBuilderServicesBeanDefinition(
|
||||
parserContext).getBeanName());
|
||||
definitionBuilder.addPropertyValue("flowBuilderServices", createDefaultFlowBuilderServices(parserContext));
|
||||
}
|
||||
String parent = getParentAttribute(element);
|
||||
String parent = element.getAttribute("parent");
|
||||
if (StringUtils.hasText(parent)) {
|
||||
definitionBuilder.addPropertyReference(PARENT_PROPERTY, parent);
|
||||
definitionBuilder.addPropertyReference("parent", parent);
|
||||
}
|
||||
definitionBuilder.addPropertyValue(FLOW_LOCATIONS_PROPERTY, parseLocations(element));
|
||||
definitionBuilder.addPropertyValue(FLOW_LOCATION_PATTERNS_PROPERTY, parseLocationPatterns(element));
|
||||
definitionBuilder.addPropertyValue(FLOW_BUILDERS_PROPERTY, parseFlowBuilders(element));
|
||||
definitionBuilder.addPropertyValue("flowLocations", parseLocations(element));
|
||||
definitionBuilder.addPropertyValue("flowLocationPatterns", parseLocationPatterns(element));
|
||||
definitionBuilder.addPropertyValue("flowBuilders", parseFlowBuilders(element));
|
||||
}
|
||||
|
||||
private List parseLocations(Element element) {
|
||||
List locationElements = DomUtils.getChildElementsByTagName(element, FLOW_LOCATION_ELEMENT);
|
||||
List locationElements = DomUtils.getChildElementsByTagName(element, "flow-location");
|
||||
if (locationElements.isEmpty()) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
List locations = new ArrayList(locationElements.size());
|
||||
for (Iterator it = locationElements.iterator(); it.hasNext();) {
|
||||
Element locationElement = (Element) it.next();
|
||||
String id = locationElement.getAttribute(ID_ATTRIBUTE);
|
||||
String path = locationElement.getAttribute(PATH_ATTRIBUTE);
|
||||
String id = locationElement.getAttribute("id");
|
||||
String path = locationElement.getAttribute("path");
|
||||
locations.add(new FlowLocation(id, path, parseAttributes(locationElement)));
|
||||
}
|
||||
return locations;
|
||||
}
|
||||
|
||||
private List parseLocationPatterns(Element element) {
|
||||
List locationPatternElements = DomUtils.getChildElementsByTagName(element, FLOW_LOCATION_PATTERN_ELEMENT);
|
||||
List locationPatternElements = DomUtils.getChildElementsByTagName(element, "flow-location-pattern");
|
||||
if (locationPatternElements.isEmpty()) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
List locationPatterns = new ArrayList(locationPatternElements.size());
|
||||
for (Iterator it = locationPatternElements.iterator(); it.hasNext();) {
|
||||
Element locationPatternElement = (Element) it.next();
|
||||
String value = locationPatternElement.getAttribute(VALUE_ATTRIBUTE);
|
||||
String value = locationPatternElement.getAttribute("value");
|
||||
locationPatterns.add(value);
|
||||
}
|
||||
return locationPatterns;
|
||||
}
|
||||
|
||||
private Set parseAttributes(Element element) {
|
||||
Element definitionAttributesElement = DomUtils.getChildElementByTagName(element, DEFINITION_ATTRIBUTES_ELEMENT);
|
||||
Element definitionAttributesElement = DomUtils.getChildElementByTagName(element, "flow-definition-attributes");
|
||||
if (definitionAttributesElement != null) {
|
||||
List attributeElements = DomUtils.getChildElementsByTagName(definitionAttributesElement, ATTRIBUTE_ELEMENT);
|
||||
List attributeElements = DomUtils.getChildElementsByTagName(definitionAttributesElement, "attribute");
|
||||
HashSet attributes = new HashSet(attributeElements.size());
|
||||
for (Iterator it = attributeElements.iterator(); it.hasNext();) {
|
||||
Element attributeElement = (Element) it.next();
|
||||
String name = attributeElement.getAttribute(NAME_ATTRIBUTE);
|
||||
String value = attributeElement.getAttribute(VALUE_ATTRIBUTE);
|
||||
String type = attributeElement.getAttribute(TYPE_ATTRIBUTE);
|
||||
String name = attributeElement.getAttribute("name");
|
||||
String value = attributeElement.getAttribute("value");
|
||||
String type = attributeElement.getAttribute("type");
|
||||
attributes.add(new FlowElementAttribute(name, value, type));
|
||||
}
|
||||
return attributes;
|
||||
@@ -143,26 +111,28 @@ class FlowRegistryBeanDefinitionParser extends AbstractSingleBeanDefinitionParse
|
||||
}
|
||||
|
||||
private List parseFlowBuilders(Element element) {
|
||||
List builderElements = DomUtils.getChildElementsByTagName(element, FLOW_BUILDER_ELEMENT);
|
||||
List builderElements = DomUtils.getChildElementsByTagName(element, "flow-builder");
|
||||
if (builderElements.isEmpty()) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
List builders = new ArrayList(builderElements.size());
|
||||
for (Iterator it = builderElements.iterator(); it.hasNext();) {
|
||||
Element builderElement = (Element) it.next();
|
||||
String id = builderElement.getAttribute(ID_ATTRIBUTE);
|
||||
String className = builderElement.getAttribute(CLASS_ATTRIBUTE);
|
||||
String id = builderElement.getAttribute("id");
|
||||
String className = builderElement.getAttribute("class");
|
||||
builders.add(new FlowBuilderInfo(id, className, parseAttributes(builderElement)));
|
||||
}
|
||||
return builders;
|
||||
}
|
||||
|
||||
private String getFlowBuilderServicesAttribute(Element element) {
|
||||
return element.getAttribute(FLOW_BUILDER_SERVICES_ATTRIBUTE);
|
||||
}
|
||||
|
||||
private String getParentAttribute(Element element) {
|
||||
return element.getAttribute(PARENT_ATTRIBUTE);
|
||||
private BeanDefinition createDefaultFlowBuilderServices(ParserContext context) {
|
||||
BeanDefinitionBuilder defaultBuilder = BeanDefinitionBuilder.genericBeanDefinition(FlowBuilderServices.class);
|
||||
defaultBuilder.addPropertyValue("formatterRegistry", DefaultFormatterRegistry.getSharedInstance());
|
||||
defaultBuilder.addPropertyValue("conversionService", DefaultConversionService.getSharedInstance());
|
||||
defaultBuilder.addPropertyValue("expressionParser", DefaultExpressionParserFactory.getExpressionParser());
|
||||
defaultBuilder.addPropertyValue("viewFactoryCreator", BeanDefinitionBuilder.genericBeanDefinition(
|
||||
MvcViewFactoryCreator.class).getBeanDefinition());
|
||||
return defaultBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -169,66 +169,7 @@ The fully qualified class name of the FlowBuilder implementation.
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="flow-executor">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Deploys a flow executor. A FlowExecutor executes flow definitions and acts as the entry-point into the Web Flow system.
|
||||
A flow executor launches new flow executions and resumes paused flow executions.
|
||||
Paused flow executions are stored between requests in a FlowExecutionRepository.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="flow-execution-repository" type="flowExecutionRepositoryType" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Configures the type of FlowExecutionRepository that should be used by this executor. Optional.
|
||||
Specify when you want to override the default repository implementation.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="flow-execution-attributes" type="flowExecutionAttributesType" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Meta attributes to assign new flow executions launched by this executor. These attributes will be associated with all flow executions,
|
||||
regardless of their underlying flow definition. Such attributes may influence flow execution behavior at runtime.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="flow-execution-listeners" type="flowExecutionListenersType" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Registers listeners that observe the lifecycle of flow executions launched by this executor.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="flow-registry" type="xsd:string" default="flowRegistry">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
A reference to the FlowRegistry bean containing the flows eligible for execution by this executor.
|
||||
The default value 'flowRegistry'.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
<xsd:element name="flow-builder-services">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -274,6 +215,65 @@ The custom ExpressionParser implementation to use to compile expression strings
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The custom ViewFactoryCreator implementation to use produce ViewFactories capable of rendering Views.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="flow-executor">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Deploys a flow executor. A FlowExecutor executes flow definitions and acts as the entry-point into the Web Flow system.
|
||||
A flow executor launches new flow executions and resumes paused flow executions.
|
||||
Paused flow executions are stored between requests in a FlowExecutionRepository.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="flow-execution-repository" type="flowExecutionRepositoryType" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Configures the default FlowExecutionRepository by this executor. Optional.
|
||||
Specify when you want to customize attributes of the default repository implementation.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="flow-execution-attributes" type="flowExecutionAttributesType" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Meta attributes to assign new flow executions launched by this executor. These attributes will be associated with all flow executions,
|
||||
regardless of their underlying flow definition. Such attributes may influence flow execution behavior at runtime.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="flow-execution-listeners" type="flowExecutionListenersType" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Registers listeners that observe the lifecycle of flow executions launched by this executor.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="flow-registry" type="xsd:string" default="flowRegistry">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
A reference to the FlowRegistry bean containing the flows eligible for execution by this executor.
|
||||
The default value 'flowRegistry'.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
@@ -284,82 +284,26 @@ The custom ViewFactoryCreator implementation to use produce ViewFactories capabl
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="flowExecutionRepositoryType">
|
||||
<xsd:attribute name="type" type="flowExecutionRepositoryTypeAttribute">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The type of flow execution repository to use.
|
||||
A FlowExecutionRepository manages flow execution persistence between requests.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="max-conversations" type="xsd:integer">
|
||||
<xsd:attribute name="max-executions" type="xsd:integer">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The maximum number of concurrent conversations allowed by this repository. The default is 5.
|
||||
Do not set this attribute if you are also setting the 'conversation-manager' attribute.
|
||||
The maximum number of persistent flow executions allowed per user session. The default is 5.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="max-continuations" type="xsd:integer">
|
||||
<xsd:attribute name="max-execution-snapshots" type="xsd:integer">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The maximum number of flow execution continuations (snapshots) allowed by this repository per conversation. The default is 30.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="conversation-manager" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The custom ConversationManager implementation to use with the FlowExecutionRepository.
|
||||
Setting this attribute allows full control over the conversation manager implementation and configuration.
|
||||
When used, any value for the 'max-conversations' attribute is ignored.
|
||||
The maximum number of history snapshots allowed per flow execution. The default is 30.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:simpleType name="flowExecutionRepositoryTypeAttribute">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="continuation">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The continuation repository type. Use this to snapshot flow execution state server-side to support use
|
||||
of the browser back button. This is the default if not specified.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
<xsd:enumeration value="simple">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The simple repository type. Use of this strategy incurs minimal storage overhead but explicitly prevents resubmits using the browser back button.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
<xsd:enumeration value="singlekey">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The "single key" repository type.
|
||||
Use of this strategy assigns a single key per flow execution that remains constant throughout the life of the execution.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:enumeration>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<xsd:complexType name="flowExecutionListenersType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="listener" type="flowExecutionListenerType" maxOccurs="unbounded">
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
*/
|
||||
package org.springframework.webflow.mvc.builder;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.enums.StaticLabeledEnum;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.portlet.context.ConfigurablePortletApplicationContext;
|
||||
|
||||
/**
|
||||
* Supported Spring Web MVC environments.
|
||||
@@ -38,4 +42,20 @@ public class MvcEnvironment extends StaticLabeledEnum {
|
||||
super(code, label);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (ClassUtils.isPresent("javax.portlet.PortletContext")
|
||||
&& applicationContext instanceof ConfigurablePortletApplicationContext) {
|
||||
return MvcEnvironment.PORTLET;
|
||||
} else if (applicationContext instanceof WebApplicationContext) {
|
||||
return MvcEnvironment.SERVLET;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,8 +22,6 @@ import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.format.FormatterRegistry;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.portlet.context.ConfigurablePortletApplicationContext;
|
||||
import org.springframework.web.servlet.View;
|
||||
import org.springframework.web.servlet.ViewResolver;
|
||||
import org.springframework.webflow.engine.builder.ViewFactoryCreator;
|
||||
@@ -113,12 +111,7 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
if (ClassUtils.isPresent("javax.portlet.PortletContext")
|
||||
&& applicationContext instanceof ConfigurablePortletApplicationContext) {
|
||||
environment = MvcEnvironment.PORTLET;
|
||||
} else {
|
||||
environment = MvcEnvironment.SERVLET;
|
||||
}
|
||||
environment = MvcEnvironment.environmentFor(applicationContext);
|
||||
}
|
||||
|
||||
public ViewFactory createViewFactory(Expression viewId, ExpressionParser expressionParser,
|
||||
@@ -128,7 +121,7 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon
|
||||
} else if (environment == MvcEnvironment.PORTLET) {
|
||||
return new PortletMvcViewFactory(viewId, flowViewResolver, expressionParser, formatterRegistry);
|
||||
} else {
|
||||
throw new IllegalStateException("Environment not supported " + environment);
|
||||
throw new IllegalStateException("Web Environment " + environment + " not supported ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.springframework.webflow.config;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
public class EnableScopesService {
|
||||
private EnableScopesUser user;
|
||||
|
||||
public void setUser(EnableScopesUser user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
Assert.isTrue("foo".equals(user.getName()));
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package org.springframework.webflow.config;
|
||||
|
||||
public class EnableScopesUser {
|
||||
private String name = "foo";
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -66,13 +66,12 @@ public class FlowExecutorFactoryBeanTests extends TestCase {
|
||||
Set attributes = new HashSet();
|
||||
attributes.add(new FlowElementAttribute("foo", "bar", null));
|
||||
factoryBean.setFlowExecutionAttributes(attributes);
|
||||
factoryBean.setFlowExecutionRepositoryType(FlowExecutionRepositoryType.CONTINUATION);
|
||||
FlowExecutionListener listener = new FlowExecutionListenerAdapter() {
|
||||
|
||||
};
|
||||
factoryBean.setFlowExecutionListenerLoader(new StaticFlowExecutionListenerLoader(listener));
|
||||
factoryBean.setMaxContinuations(2);
|
||||
factoryBean.setMaxConversations(1);
|
||||
factoryBean.setMaxFlowExecutionSnapshots(2);
|
||||
factoryBean.setMaxFlowExecutions(1);
|
||||
factoryBean.afterPropertiesSet();
|
||||
FlowExecutor executor = (FlowExecutor) factoryBean.getObject();
|
||||
MockExternalContext context = new MockExternalContext();
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<flow xmlns="http://www.springframework.org/schema/webflow"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
|
||||
|
||||
<end-state id="end">
|
||||
<entry-actions>
|
||||
<bean-action bean="service" method="execute"/>
|
||||
</entry-actions>
|
||||
</end-state>
|
||||
|
||||
</flow>
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
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-2.0.xsd
|
||||
http://www.springframework.org/schema/aop
|
||||
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/webflow-config
|
||||
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
|
||||
|
||||
<webflow:enable-flow-scopes/>
|
||||
|
||||
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
|
||||
<webflow:flow-execution-repository type="continuation" max-conversations="1" max-continuations="2"/>
|
||||
<webflow:flow-execution-attributes>
|
||||
<webflow:alwaysRedirectOnPause value="false"/>
|
||||
<webflow:attribute name="foo" value="bar"/>
|
||||
<webflow:attribute name="bar" value="2" type="integer"/>
|
||||
</webflow:flow-execution-attributes>
|
||||
<webflow:flow-execution-listeners>
|
||||
<webflow:listener ref="listener" criteria="*"/>
|
||||
</webflow:flow-execution-listeners>
|
||||
</webflow:flow-executor>
|
||||
|
||||
<bean id="listener" class="org.springframework.webflow.config.EnableScopesBeanDefinitionParserTests$ConfigurationListener" />
|
||||
|
||||
<webflow:flow-registry id="flowRegistry">
|
||||
<webflow:flow-location path="org/springframework/webflow/config/enable-flow-scopes-flowdef.xml" />
|
||||
</webflow:flow-registry>
|
||||
|
||||
<bean id="user" class="org.springframework.webflow.config.EnableScopesUser" scope="flow">
|
||||
<aop:scoped-proxy/>
|
||||
</bean>
|
||||
|
||||
<bean id="service" class="org.springframework.webflow.config.EnableScopesService">
|
||||
<property name="user" ref="user"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -9,7 +9,7 @@
|
||||
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
|
||||
|
||||
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
|
||||
<webflow:flow-execution-repository max-conversations="1" max-continuations="2"/>
|
||||
<webflow:flow-execution-repository max-executions="1" max-execution-snapshots="2"/>
|
||||
<webflow:flow-execution-attributes>
|
||||
<webflow:always-redirect-on-pause value="false"/>
|
||||
<webflow:attribute name="foo" value="bar"/>
|
||||
|
||||
Reference in New Issue
Block a user