made start state optional
This commit is contained in:
@@ -27,6 +27,9 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.support.StaticListableBeanFactory;
|
||||
import org.springframework.binding.mapping.AttributeMapper;
|
||||
import org.springframework.binding.mapping.MappingContext;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.style.StylerUtils;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -105,7 +108,7 @@ import org.springframework.webflow.execution.RequestContext;
|
||||
* @author Colin Sampaleanu
|
||||
* @author Jeremy Grelle
|
||||
*/
|
||||
public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory {
|
||||
public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory, ResourceLoader {
|
||||
|
||||
/**
|
||||
* Logger, can be used in subclasses.
|
||||
@@ -166,9 +169,14 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory
|
||||
private FlowExecutionExceptionHandlerSet exceptionHandlerSet = new FlowExecutionExceptionHandlerSet();
|
||||
|
||||
/**
|
||||
* The local bean factory for this flow
|
||||
* An optional bean factory hosting services needed by this flow.
|
||||
*/
|
||||
private BeanFactory localBeanFactory = new StaticListableBeanFactory();
|
||||
private BeanFactory beanFactory = new StaticListableBeanFactory();
|
||||
|
||||
/**
|
||||
* An optional resource loader capable of loading resources relative to this flow.
|
||||
*/
|
||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
/**
|
||||
* Construct a new flow definition with the given id. The id should be unique among all flows.
|
||||
@@ -433,6 +441,22 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory
|
||||
return globalTransitionSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a reference to a bean factory hosting application objects needed by this flow.
|
||||
* @param beanFactory the bean factory
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a reference to a resource loader capable of loading resources relative to this flow.
|
||||
* @param resourceLoader the resource loader
|
||||
*/
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
// id based equality
|
||||
|
||||
public boolean equals(Object o) {
|
||||
@@ -536,6 +560,52 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory
|
||||
return getExceptionHandlerSet().handleException(exception, context);
|
||||
}
|
||||
|
||||
// implementing bean factory
|
||||
|
||||
public boolean containsBean(String name) {
|
||||
return beanFactory.containsBean(name);
|
||||
}
|
||||
|
||||
public String[] getAliases(String name) {
|
||||
return beanFactory.getAliases(name);
|
||||
}
|
||||
|
||||
public Object getBean(String name, Class requiredType) throws BeansException {
|
||||
return beanFactory.getBean(name, requiredType);
|
||||
}
|
||||
|
||||
public Object getBean(String name, Object[] args) throws BeansException {
|
||||
return beanFactory.getBean(name, args);
|
||||
}
|
||||
|
||||
public Object getBean(String name) throws BeansException {
|
||||
return beanFactory.getBean(name);
|
||||
}
|
||||
|
||||
public Class getType(String name) throws NoSuchBeanDefinitionException {
|
||||
return beanFactory.getType(name);
|
||||
}
|
||||
|
||||
public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
|
||||
return beanFactory.isPrototype(name);
|
||||
}
|
||||
|
||||
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
|
||||
return beanFactory.isSingleton(name);
|
||||
}
|
||||
|
||||
public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException {
|
||||
return beanFactory.isTypeMatch(name, targetType);
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
return resourceLoader.getClassLoader();
|
||||
}
|
||||
|
||||
public Resource getResource(String name) {
|
||||
return resourceLoader.getResource(name);
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private void assertStartStateSet() {
|
||||
@@ -616,44 +686,4 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory
|
||||
"outputMapper", outputMapper).toString();
|
||||
}
|
||||
|
||||
public void setLocalBeanFactory(BeanFactory localBeanFactory) {
|
||||
this.localBeanFactory = localBeanFactory;
|
||||
}
|
||||
|
||||
public boolean containsBean(String name) {
|
||||
return localBeanFactory.containsBean(name);
|
||||
}
|
||||
|
||||
public String[] getAliases(String name) {
|
||||
return localBeanFactory.getAliases(name);
|
||||
}
|
||||
|
||||
public Object getBean(String name, Class requiredType) throws BeansException {
|
||||
return localBeanFactory.getBean(name, requiredType);
|
||||
}
|
||||
|
||||
public Object getBean(String name, Object[] args) throws BeansException {
|
||||
return localBeanFactory.getBean(name, args);
|
||||
}
|
||||
|
||||
public Object getBean(String name) throws BeansException {
|
||||
return localBeanFactory.getBean(name);
|
||||
}
|
||||
|
||||
public Class getType(String name) throws NoSuchBeanDefinitionException {
|
||||
return localBeanFactory.getType(name);
|
||||
}
|
||||
|
||||
public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
|
||||
return localBeanFactory.isPrototype(name);
|
||||
}
|
||||
|
||||
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
|
||||
return localBeanFactory.isSingleton(name);
|
||||
}
|
||||
|
||||
public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException {
|
||||
return localBeanFactory.isTypeMatch(name, targetType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007 the original author or authors.
|
||||
* 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007 the original author or authors.
|
||||
* 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.
|
||||
@@ -27,7 +27,8 @@ import org.springframework.webflow.engine.Flow;
|
||||
*
|
||||
* <pre>
|
||||
* FlowBuilder builder = ...;
|
||||
* Flow flow = new FlowAssembler("myFlow", builder, null).assembleFlow();
|
||||
* FlowBuilder context = ...;
|
||||
* Flow flow = new FlowAssembler(builder, builderContext).assembleFlow();
|
||||
* </pre>
|
||||
*
|
||||
* @see org.springframework.webflow.engine.builder.FlowBuilder
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007 the original author or authors.
|
||||
* 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.
|
||||
@@ -25,8 +25,8 @@ import org.springframework.webflow.engine.Flow;
|
||||
* <li> Call {@link #buildInputMapper()} to create and set the input mapper for the flow.
|
||||
* <li> Call {@link #buildStartActions()} to create and add any start actions to the flow.
|
||||
* <li> Call {@link #buildStates()} to create the states of the flow and add them to the flow definition.
|
||||
* <li> Call {@link #buildGlobalTransitions()} to create the any transitions shared by all states of the flow and add
|
||||
* them to the flow definition.
|
||||
* <li> Call {@link #buildGlobalTransitions()} to create any transitions shared by all states of the flow and add them
|
||||
* to the flow definition.
|
||||
* <li> Call {@link #buildEndActions()} to create and add any end actions to the flow.
|
||||
* <li> Call {@link #buildOutputMapper()} to create and set the output mapper for the flow.
|
||||
* <li> Call {@link #buildExceptionHandlers()} to create the exception handlers of the flow and add them to the flow
|
||||
@@ -44,9 +44,10 @@ import org.springframework.webflow.engine.Flow;
|
||||
* reused, however, exercise caution when doing this as these objects are not thread safe. Also, for each use be sure to
|
||||
* call init, followed by the build* methods, getFlow, and dispose completely in that order.
|
||||
* <p>
|
||||
* This is an example of the classic GoF builder pattern.
|
||||
* This is a good example of the classic GoF builder pattern.
|
||||
*
|
||||
* @see Flow
|
||||
* @see FlowBuilderContext
|
||||
* @see FlowAssembler
|
||||
*
|
||||
* @author Keith Donald
|
||||
@@ -111,15 +112,17 @@ public interface FlowBuilder {
|
||||
public void buildExceptionHandlers() throws FlowBuilderException;
|
||||
|
||||
/**
|
||||
* Get the fully constructed and configured Flow object - called by the builder's assembler (director) after
|
||||
* Get the fully constructed and configured Flow object. Called by the builder's assembler (director) after
|
||||
* assembly. When this method is called by the assembler, it is expected flow construction has completed and the
|
||||
* returned flow is ready for use.
|
||||
* returned flow is fully configured and ready for use.
|
||||
* @throws FlowBuilderException an exception occurred building this flow
|
||||
*/
|
||||
public Flow getFlow();
|
||||
public Flow getFlow() throws FlowBuilderException;
|
||||
|
||||
/**
|
||||
* Shutdown the builder, releasing any resources it holds. A new flow construction process should start with another
|
||||
* call to the {@link #init(FlowBuilderContext)} method.
|
||||
* @throws FlowBuilderException an exception occurred building this flow
|
||||
*/
|
||||
public void dispose();
|
||||
public void dispose() throws FlowBuilderException;
|
||||
}
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* 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.engine.builder;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -8,6 +23,10 @@ import org.springframework.webflow.action.BeanInvokingActionFactory;
|
||||
import org.springframework.webflow.core.collection.AttributeMap;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
|
||||
|
||||
/**
|
||||
* Provides services needed to a direct a flow builder through building a flow definition.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface FlowBuilderContext {
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007 the original author or authors.
|
||||
* 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.
|
||||
@@ -20,7 +20,7 @@ import org.springframework.webflow.core.FlowException;
|
||||
/**
|
||||
* Exception thrown to indicate a problem while building a flow.
|
||||
*
|
||||
* @see org.springframework.webflow.engine.builder.FlowBuilder
|
||||
* @see FlowBuilder
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007 the original author or authors.
|
||||
* 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.
|
||||
|
||||
@@ -1,14 +1,38 @@
|
||||
/*
|
||||
* 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.engine.builder;
|
||||
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.webflow.execution.Action;
|
||||
import org.springframework.webflow.execution.View;
|
||||
import org.springframework.webflow.execution.ViewFactory;
|
||||
|
||||
/**
|
||||
* A factory for ViewFactory objects. This is an SPI interface and conceals specific types of view factories from the
|
||||
* flow builder infrastructure.
|
||||
*/
|
||||
public interface ViewFactoryCreator {
|
||||
|
||||
/**
|
||||
* Create a view factory capable of creating {@link View} objects that can render the view template with the
|
||||
* provided identifier.
|
||||
* @param viewId an expression that resolves the id of the view template
|
||||
* @param viewResourceLoader an optional resource loader to use to load the view template from an input stream
|
||||
* @return the view factory
|
||||
*/
|
||||
public ViewFactory createViewFactory(Expression viewId, ResourceLoader viewResourceLoader);
|
||||
|
||||
public Action createFinalResponseAction(Expression viewId, ResourceLoader viewResourceLoader);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007 the original author or authors.
|
||||
* 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.
|
||||
@@ -36,8 +36,15 @@ public abstract class AbstractFlowBuilder implements FlowBuilder {
|
||||
*/
|
||||
private Flow flow;
|
||||
|
||||
/**
|
||||
* The flow builder context providing access to services needed to build the flow.
|
||||
*/
|
||||
private FlowBuilderContext context;
|
||||
|
||||
/**
|
||||
* Returns this flow builder's context.
|
||||
* @return the flow builder context
|
||||
*/
|
||||
protected FlowBuilderContext getContext() {
|
||||
return context;
|
||||
}
|
||||
@@ -48,10 +55,18 @@ public abstract class AbstractFlowBuilder implements FlowBuilder {
|
||||
this.flow = createFlow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flow builder initialization hook. Does nothing by default. May be overridden by subclasses.
|
||||
*/
|
||||
protected void doInit() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that initially creates the flow implementation during flow builder initialization. Simply
|
||||
* delegates to the configured flow artifact factory by default.
|
||||
* @return the flow instance, initially created but not yet built
|
||||
*/
|
||||
protected Flow createFlow() {
|
||||
String id = getContext().getFlowId();
|
||||
AttributeMap attributes = getContext().getFlowAttributes();
|
||||
@@ -81,15 +96,18 @@ public abstract class AbstractFlowBuilder implements FlowBuilder {
|
||||
public void buildExceptionHandlers() throws FlowBuilderException {
|
||||
}
|
||||
|
||||
public Flow getFlow() {
|
||||
public Flow getFlow() throws FlowBuilderException {
|
||||
return flow;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
public void dispose() throws FlowBuilderException {
|
||||
flow = null;
|
||||
doDispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flow builder destruction hook. Does nothing by default. May be overridden by subclasses.
|
||||
*/
|
||||
protected void doDispose() {
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.engine.builder.support;
|
||||
|
||||
import org.springframework.webflow.engine.ActionExecutor;
|
||||
import org.springframework.webflow.execution.Action;
|
||||
import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.View;
|
||||
import org.springframework.webflow.execution.ViewFactory;
|
||||
|
||||
/**
|
||||
* A view factory implementation that creates views that execute an action when rendered. Used mainly to encapsulate an
|
||||
* action that renders a response. Examples include flow redirect and external redirect actions.
|
||||
*/
|
||||
public class ActionExecutingViewFactory implements ViewFactory {
|
||||
|
||||
/**
|
||||
* The action to execute.
|
||||
*/
|
||||
private Action action;
|
||||
|
||||
/**
|
||||
* Create a new action invoking view factory
|
||||
* @param action the action to execute
|
||||
*/
|
||||
public ActionExecutingViewFactory(Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public View getView(RequestContext context) {
|
||||
return new ActionExecutingView(action, context);
|
||||
}
|
||||
|
||||
private static class ActionExecutingView implements View {
|
||||
|
||||
private Action action;
|
||||
|
||||
private RequestContext context;
|
||||
|
||||
private ActionExecutingView(Action action, RequestContext context) {
|
||||
this.action = action;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public boolean eventSignaled() {
|
||||
return context.getExternalContext().getRequestParameterMap().contains("_eventId");
|
||||
}
|
||||
|
||||
public Event getEvent() {
|
||||
return new Event(this, context.getExternalContext().getRequestParameterMap().get("_eventId"));
|
||||
}
|
||||
|
||||
public void render() {
|
||||
ActionExecutor.execute(action, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package org.springframework.webflow.engine.builder.support;
|
||||
|
||||
import org.springframework.webflow.execution.Action;
|
||||
import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.View;
|
||||
import org.springframework.webflow.execution.ViewFactory;
|
||||
|
||||
public class ActionInvokingViewFactory implements ViewFactory {
|
||||
|
||||
private Action action;
|
||||
|
||||
public ActionInvokingViewFactory(Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public View getView(RequestContext context) {
|
||||
return new ActionExecutingView(action, context);
|
||||
}
|
||||
|
||||
private static class ActionExecutingView implements View {
|
||||
|
||||
private Action action;
|
||||
|
||||
private RequestContext context;
|
||||
|
||||
private ActionExecutingView(Action action, RequestContext context) {
|
||||
this.action = action;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public boolean eventSignaled() {
|
||||
return context.getExternalContext().getRequestParameterMap().contains("_eventId");
|
||||
}
|
||||
|
||||
public Event getEvent() {
|
||||
return new Event(this, context.getExternalContext().getRequestParameterMap().get("_eventId"));
|
||||
}
|
||||
|
||||
public void render() {
|
||||
try {
|
||||
action.execute(context);
|
||||
} catch (Exception e) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,10 @@ import org.springframework.webflow.engine.builder.FlowArtifactFactory;
|
||||
import org.springframework.webflow.engine.builder.FlowBuilderContext;
|
||||
import org.springframework.webflow.engine.builder.ViewFactoryCreator;
|
||||
|
||||
/**
|
||||
* Generic implementation of a flow builder context, suitable for use by most flow assembly systems.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class FlowBuilderContextImpl implements FlowBuilderContext {
|
||||
|
||||
private String flowId;
|
||||
@@ -24,6 +28,13 @@ public class FlowBuilderContextImpl implements FlowBuilderContext {
|
||||
|
||||
private GenericConversionService flowConversionService;
|
||||
|
||||
/**
|
||||
* Creates a new flow builder context.
|
||||
* @param flowId the id to assign the flow being built
|
||||
* @param flowAttributes attributes to assign the flow being built
|
||||
* @param flowDefinitionLocator a locator to find dependent subflows
|
||||
* @param flowBuilderServices a parameter object providing access to additional services needed by the flow builder
|
||||
*/
|
||||
public FlowBuilderContextImpl(String flowId, AttributeMap flowAttributes,
|
||||
FlowDefinitionLocator flowDefinitionLocator, FlowBuilderServices flowBuilderServices) {
|
||||
this.flowId = flowId;
|
||||
@@ -36,6 +47,12 @@ public class FlowBuilderContextImpl implements FlowBuilderContext {
|
||||
flowConversionService.setParent(this.flowBuilderServices.getConversionService());
|
||||
}
|
||||
|
||||
public FlowBuilderServices getFlowBuilderServices() {
|
||||
return flowBuilderServices;
|
||||
}
|
||||
|
||||
// implementing flow builder context
|
||||
|
||||
public String getFlowId() {
|
||||
return flowId;
|
||||
}
|
||||
@@ -76,7 +93,4 @@ public class FlowBuilderContextImpl implements FlowBuilderContext {
|
||||
return flowDefinitionLocator;
|
||||
}
|
||||
|
||||
public FlowBuilderServices getFlowBuilderServices() {
|
||||
return flowBuilderServices;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,16 @@ import org.springframework.webflow.core.expression.DefaultExpressionParserFactor
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.engine.State;
|
||||
import org.springframework.webflow.engine.builder.FlowArtifactFactory;
|
||||
import org.springframework.webflow.engine.builder.FlowBuilderContext;
|
||||
import org.springframework.webflow.engine.builder.ViewFactoryCreator;
|
||||
import org.springframework.webflow.execution.Action;
|
||||
|
||||
/**
|
||||
* A simple holder for services needed by a flow builder. These services are typically exposed via a Flow Builder's
|
||||
* {@link FlowBuilderContext}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAware {
|
||||
|
||||
/**
|
||||
@@ -32,17 +39,19 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar
|
||||
private BeanInvokingActionFactory beanInvokingActionFactory = new BeanInvokingActionFactory();
|
||||
|
||||
/**
|
||||
* The view factory creator.
|
||||
* The view factory creator for creating views to render during flow execution. The default is <code>null</code>
|
||||
* and this service must be configured externally.
|
||||
*/
|
||||
private ViewFactoryCreator viewFactoryCreator;
|
||||
|
||||
/**
|
||||
* The conversion service.
|
||||
* The conversion service for converting from one object type to another.
|
||||
*/
|
||||
private ConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
/**
|
||||
* The parser for parsing expression strings into expression objects.
|
||||
* The parser for parsing expression strings into expression objects. The default is Web Flow's default expression
|
||||
* parser implementation.
|
||||
*/
|
||||
private ExpressionParser expressionParser = DefaultExpressionParserFactory.getExpressionParser();
|
||||
|
||||
@@ -52,7 +61,7 @@ public class FlowBuilderServices implements ResourceLoaderAware, BeanFactoryAwar
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
/**
|
||||
* The Spring bean factory used.
|
||||
* The Spring bean factory that provides access to the services of the user application.
|
||||
*/
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
|
||||
@@ -26,6 +26,11 @@ import org.springframework.webflow.engine.builder.FlowArtifactFactory;
|
||||
import org.springframework.webflow.engine.builder.FlowBuilderContext;
|
||||
import org.springframework.webflow.engine.builder.ViewFactoryCreator;
|
||||
|
||||
/**
|
||||
* A builder context that delegates to a flow-local bean factory for builder services. Such builder services override
|
||||
* the services of the external "parent" context.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
class LocalFlowBuilderContext implements FlowBuilderContext {
|
||||
|
||||
private FlowBuilderContext parent;
|
||||
|
||||
@@ -57,6 +57,7 @@ import org.springframework.webflow.action.EvaluateAction;
|
||||
import org.springframework.webflow.action.ExternalRedirectAction;
|
||||
import org.springframework.webflow.action.FlowDefinitionRedirectAction;
|
||||
import org.springframework.webflow.action.SetAction;
|
||||
import org.springframework.webflow.action.ViewFactoryActionAdapter;
|
||||
import org.springframework.webflow.core.collection.AttributeMap;
|
||||
import org.springframework.webflow.core.collection.LocalAttributeMap;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
@@ -71,7 +72,7 @@ import org.springframework.webflow.engine.TransitionCriteria;
|
||||
import org.springframework.webflow.engine.builder.FlowArtifactFactory;
|
||||
import org.springframework.webflow.engine.builder.FlowBuilderException;
|
||||
import org.springframework.webflow.engine.builder.support.AbstractFlowBuilder;
|
||||
import org.springframework.webflow.engine.builder.support.ActionInvokingViewFactory;
|
||||
import org.springframework.webflow.engine.builder.support.ActionExecutingViewFactory;
|
||||
import org.springframework.webflow.engine.support.BeanFactoryFlowVariable;
|
||||
import org.springframework.webflow.engine.support.BooleanExpressionTransitionCriteria;
|
||||
import org.springframework.webflow.engine.support.SimpleFlowVariable;
|
||||
@@ -96,13 +97,13 @@ import org.xml.sax.SAXException;
|
||||
* <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-1.0.xsd">
|
||||
* http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
|
||||
* <!-- Define your states here -->
|
||||
* </flow>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Consult the <a href="http://www.springframework.org/schema/webflow/spring-webflow-1.0.xsd">web flow XML schema</a>
|
||||
* Consult the <a href="http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">web flow XML schema</a>
|
||||
* for more information on the XML-based flow definition format.
|
||||
* <p>
|
||||
* This builder will setup a flow-local bean factory for the flow being constructed. That flow-local bean factory will
|
||||
@@ -125,8 +126,6 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
|
||||
|
||||
private static final String FLOW_ELEMENT = "flow";
|
||||
|
||||
private static final String START_STATE_ELEMENT = "start-state";
|
||||
|
||||
private static final String ACTION_STATE_ELEMENT = "action-state";
|
||||
|
||||
private static final String ACTION_ELEMENT = "action";
|
||||
@@ -323,7 +322,8 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
|
||||
|
||||
protected Flow createFlow() {
|
||||
Flow flow = parseFlow(getDocumentElement());
|
||||
flow.setLocalBeanFactory(getLocalContext().getBeanFactory());
|
||||
flow.setBeanFactory(getLocalContext().getBeanFactory());
|
||||
flow.setResourceLoader(getLocalContext().getResourceLoader());
|
||||
return flow;
|
||||
}
|
||||
|
||||
@@ -542,12 +542,27 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
|
||||
|
||||
private void parseAndSetStartState(Element element, Flow flow) {
|
||||
String startStateId = getStartStateId(element);
|
||||
flow.setStartState(startStateId);
|
||||
if (StringUtils.hasText(startStateId)) {
|
||||
flow.setStartState(startStateId);
|
||||
}
|
||||
}
|
||||
|
||||
private String getStartStateId(Element element) {
|
||||
Element startStateElement = DomUtils.getChildElementByTagName(element, START_STATE_ELEMENT);
|
||||
return startStateElement.getAttribute(IDREF_ATTRIBUTE);
|
||||
String startState = "start-state";
|
||||
if (element.hasAttribute(startState)) {
|
||||
Element startStateElement = DomUtils.getChildElementByTagName(element, startState);
|
||||
Assert
|
||||
.isNull(startStateElement,
|
||||
"Define either a flow 'start-state' attribute or use the classic 'start-state' element. Do not use both.");
|
||||
return element.getAttribute(startState);
|
||||
} else {
|
||||
Element startStateElement = DomUtils.getChildElementByTagName(element, startState);
|
||||
if (startStateElement != null) {
|
||||
return startStateElement.getAttribute(IDREF_ATTRIBUTE);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseAndAddActionState(Element element, Flow flow) {
|
||||
@@ -614,11 +629,11 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
|
||||
String encodedUrl = encodedView.substring(EXTERNAL_REDIRECT_PREFIX.length());
|
||||
Expression externalUrl = getExpressionParser().parseExpression(encodedUrl,
|
||||
new ParserContextImpl().eval(RequestContext.class).expect(String.class));
|
||||
ViewFactory viewFactory = new ActionInvokingViewFactory(new ExternalRedirectAction(externalUrl));
|
||||
ViewFactory viewFactory = new ActionExecutingViewFactory(new ExternalRedirectAction(externalUrl));
|
||||
return new ViewInfo(viewFactory, Boolean.FALSE);
|
||||
} else if (encodedView.startsWith(FLOW_DEFINITION_REDIRECT_PREFIX)) {
|
||||
String flowRedirect = encodedView.substring(FLOW_DEFINITION_REDIRECT_PREFIX.length());
|
||||
ViewFactory viewFactory = new ActionInvokingViewFactory(FlowDefinitionRedirectAction.create(flowRedirect));
|
||||
ViewFactory viewFactory = new ActionExecutingViewFactory(FlowDefinitionRedirectAction.create(flowRedirect));
|
||||
return new ViewInfo(viewFactory, Boolean.FALSE);
|
||||
} else if (encodedView.startsWith(BEAN_PREFIX)) {
|
||||
ViewFactory viewFactory = (ViewFactory) getLocalContext().getBeanFactory().getBean(
|
||||
@@ -652,8 +667,8 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
|
||||
} else {
|
||||
Expression viewName = getExpressionParser().parseExpression(encodedView,
|
||||
new ParserContextImpl().eval(RequestContext.class).expect(String.class));
|
||||
return getLocalContext().getViewFactoryCreator().createFinalResponseAction(viewName,
|
||||
getLocalContext().getResourceLoader());
|
||||
return new ViewFactoryActionAdapter(getLocalContext().getViewFactoryCreator().createViewFactory(viewName,
|
||||
getLocalContext().getResourceLoader()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -280,11 +280,16 @@ Defines flow startup logic to execute. This logic will always execute when this
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element ref="start-state">
|
||||
<xsd:element ref="start-state" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Identifies the starting point of this flow. The start state is the point where flow execution begins.
|
||||
Identifies the starting point of this flow. The start state is the point where flow execution begins.
|
||||
|
||||
This element is an alternative to the 'start-state' attribute. In general, the 'start-state' attribute
|
||||
is performed when you wish to explictly denote the flow start-state.
|
||||
|
||||
If not specified, the default start state is the first state defined in the document.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
@@ -453,6 +458,16 @@ definition resource location.
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="start-state" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Identifies the starting point of this flow. The start state is the point where flow execution begins.
|
||||
If not specified, the default start state is the first state defined in the document.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
@@ -367,11 +367,11 @@ public class FlowExecutionImpl implements FlowExecution, Externalizable {
|
||||
}
|
||||
|
||||
FlowExecutionKey assignKey() {
|
||||
this.key = keyFactory.getKey(this);
|
||||
key = keyFactory.getKey(this);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Assigned key " + this.key);
|
||||
logger.debug("Assigned key " + key);
|
||||
}
|
||||
return this.key;
|
||||
return key;
|
||||
}
|
||||
|
||||
// package private setters for restoring transient state used by FlowExecutionImplServicesConfigurer
|
||||
|
||||
@@ -46,7 +46,7 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
public Action createFinalResponseAction(Expression viewId, ResourceLoader viewResourceLoader) {
|
||||
public Action createRenderViewAction(Expression viewId, ResourceLoader viewResourceLoader) {
|
||||
return new ViewFactoryActionAdapter(createViewFactory(viewId, viewResourceLoader));
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.webflow.execution.ViewFactory;
|
||||
* @author Keith Donald
|
||||
*/
|
||||
class MockViewFactoryCreator implements ViewFactoryCreator {
|
||||
public Action createFinalResponseAction(Expression viewId, ResourceLoader viewResourceLoader) {
|
||||
public Action createRenderViewAction(Expression viewId, ResourceLoader viewResourceLoader) {
|
||||
return new ViewFactoryActionAdapter(createViewFactory(viewId, viewResourceLoader));
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public class FlowBuilderServicesBeanDefinitionParserTests extends TestCase {
|
||||
|
||||
public static class TestViewFactoryCreator implements ViewFactoryCreator {
|
||||
|
||||
public Action createFinalResponseAction(Expression viewId, ResourceLoader viewResourceLoader) {
|
||||
public Action createRenderViewAction(Expression viewId, ResourceLoader viewResourceLoader) {
|
||||
throw new UnsupportedOperationException("Auto-generated method stub");
|
||||
}
|
||||
|
||||
|
||||
@@ -37,4 +37,32 @@ public class XmlFlowBuilderTests extends TestCase {
|
||||
assertEquals("flow", flow.getId());
|
||||
assertEquals("end", flow.getStartState().getId());
|
||||
}
|
||||
|
||||
public void testBuildFlowWithDefaultStartState() {
|
||||
ClassPathResource resource = new ClassPathResource("flow-startstate-default.xml", getClass());
|
||||
builder = new XmlFlowBuilder(resource);
|
||||
FlowAssembler assembler = new FlowAssembler(builder, new MockFlowBuilderContext("flow"));
|
||||
Flow flow = assembler.assembleFlow();
|
||||
assertEquals("flow", flow.getId());
|
||||
assertEquals("end", flow.getStartState().getId());
|
||||
}
|
||||
|
||||
public void testBuildFlowWithStartStateAttribute() {
|
||||
ClassPathResource resource = new ClassPathResource("flow-startstate-attribute.xml", getClass());
|
||||
builder = new XmlFlowBuilder(resource);
|
||||
FlowAssembler assembler = new FlowAssembler(builder, new MockFlowBuilderContext("flow"));
|
||||
Flow flow = assembler.assembleFlow();
|
||||
assertEquals("flow", flow.getId());
|
||||
assertEquals("end", flow.getStartState().getId());
|
||||
}
|
||||
|
||||
public void testBuildFlowWithStartStateElement() {
|
||||
ClassPathResource resource = new ClassPathResource("flow-startstate-element.xml", getClass());
|
||||
builder = new XmlFlowBuilder(resource);
|
||||
FlowAssembler assembler = new FlowAssembler(builder, new MockFlowBuilderContext("flow"));
|
||||
Flow flow = assembler.assembleFlow();
|
||||
assertEquals("flow", flow.getId());
|
||||
assertEquals("end", flow.getStartState().getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<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">
|
||||
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd" start-state="end">
|
||||
|
||||
<start-state idref="end"/>
|
||||
|
||||
<end-state id="end"/>
|
||||
|
||||
</flow>
|
||||
@@ -0,0 +1,9 @@
|
||||
<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" start-state="end">
|
||||
|
||||
<end-state id="foo"/>
|
||||
<end-state id="end"/>
|
||||
|
||||
</flow>
|
||||
@@ -0,0 +1,8 @@
|
||||
<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"/>
|
||||
|
||||
</flow>
|
||||
@@ -0,0 +1,11 @@
|
||||
<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">
|
||||
|
||||
<start-state idref="end"/>
|
||||
|
||||
<end-state id="foo"/>
|
||||
<end-state id="end"/>
|
||||
|
||||
</flow>
|
||||
Reference in New Issue
Block a user