diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/expression/el/SpringBeanWebFlowELResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/core/expression/el/SpringBeanWebFlowELResolver.java index deac0c1d..63c10d30 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/expression/el/SpringBeanWebFlowELResolver.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/expression/el/SpringBeanWebFlowELResolver.java @@ -52,8 +52,8 @@ public class SpringBeanWebFlowELResolver extends SpringBeanFacesELResolver { protected BeanFactory getBeanFactory(ELContext elContext) { RequestContext rc = RequestContextHolder.getRequestContext(); - if (rc.getActiveFlow() instanceof BeanFactory) { - return (BeanFactory) rc.getActiveFlow(); + if (rc.getActiveFlow().getBeanFactory() != null) { + return rc.getActiveFlow().getBeanFactory(); } else { return EMPTY_BEAN_FACTORY; } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/definition/FlowDefinition.java b/spring-webflow/src/main/java/org/springframework/webflow/definition/FlowDefinition.java index 6fddd2c1..558f2e25 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/definition/FlowDefinition.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/definition/FlowDefinition.java @@ -15,6 +15,9 @@ */ package org.springframework.webflow.definition; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.core.io.ResourceLoader; + /** * The definition of a flow, a program that when executed carries out the orchestration of a task on behalf of a single * client. @@ -60,4 +63,15 @@ public interface FlowDefinition extends Annotated { * @throws IllegalArgumentException if a state with this id does not exist */ public StateDefinition getState(String id) throws IllegalArgumentException; + + /** + * Returns a reference to a bean factory hosting application objects needed by this flow definition. + */ + public BeanFactory getBeanFactory(); + + /** + * Returns a reference to a resource loader capable of loading resources relative to this flow. + */ + public ResourceLoader getResourceLoader(); + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java index 6fd1af75..b642f8df 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java @@ -21,14 +21,10 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; -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; @@ -108,7 +104,7 @@ import org.springframework.webflow.execution.RequestContext; * @author Colin Sampaleanu * @author Jeremy Grelle */ -public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory, ResourceLoader { +public class Flow extends AnnotatedObject implements FlowDefinition { /** * Logger, can be used in subclasses. @@ -138,7 +134,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory /** * The mapper to map flow input attributes. */ - private AttributeMapper inputMapper = new NoInputMapper(); + private AttributeMapper inputMapper; /** * The list of actions to execute when this flow starts. @@ -161,7 +157,7 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory /** * The mapper to map flow output attributes. */ - private AttributeMapper outputMapper = new NoOutputMapper(); + private AttributeMapper outputMapper; /** * The set of exception handlers for this flow. @@ -219,6 +215,14 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory return getStateInstance(stateId); } + public BeanFactory getBeanFactory() { + return beanFactory; + } + + public ResourceLoader getResourceLoader() { + return resourceLoader; + } + /** * Add given state definition to this flow definition. Marked protected, as this method is to be called by the * (privileged) state definition classes themselves during state construction as part of a FlowBuilder invocation. @@ -382,7 +386,6 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory * @param inputMapper the input mapper */ public void setInputMapper(AttributeMapper inputMapper) { - Assert.notNull(inputMapper, "The input mapper cannot be null"); this.inputMapper = inputMapper; } @@ -417,7 +420,6 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory * @param outputMapper the output mapper */ public void setOutputMapper(AttributeMapper outputMapper) { - Assert.notNull(outputMapper, "The output mapper cannot be null"); this.outputMapper = outputMapper; } @@ -498,7 +500,9 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory public void start(RequestControlContext context, MutableAttributeMap input) throws FlowExecutionException { assertStartStateSet(); createVariables(context); - inputMapper.map(input, context, null); + if (inputMapper != null) { + inputMapper.map(input, context, null); + } startActionList.execute(context); startState.enter(context); } @@ -547,7 +551,9 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory */ public void end(RequestControlContext context, MutableAttributeMap output) throws FlowExecutionException { endActionList.execute(context); - outputMapper.map(context, output, null); + if (outputMapper != null) { + outputMapper.map(context, output, null); + } } /** @@ -560,52 +566,6 @@ 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() { @@ -653,31 +613,6 @@ public class Flow extends AnnotatedObject implements FlowDefinition, BeanFactory return (TransitionableState) currentState; } - /** - * Maps no input attributes. The default implementation. - */ - private class NoInputMapper implements AttributeMapper { - public void map(Object source, Object target, MappingContext context) { - } - - public String toString() { - return "none"; - } - - } - - /** - * Maps no input attributes. The default implementation. - */ - private class NoOutputMapper implements AttributeMapper { - public void map(Object source, Object target, MappingContext context) { - } - - public String toString() { - return "none"; - } - } - public String toString() { return new ToStringCreator(this).append("id", id).append("states", states).append("startState", startState) .append("variables", variables).append("inputMapper", inputMapper).append("startActionList", diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java index caa73e24..c73268d8 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java @@ -15,12 +15,10 @@ */ package org.springframework.webflow.engine; -import java.io.Serializable; - import org.springframework.core.style.ToStringCreator; import org.springframework.util.Assert; +import org.springframework.webflow.execution.FlowSession; import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.ScopeType; /** * A value object that defines a specification for a flow variable. Encapsulates information about the variable and the @@ -28,7 +26,7 @@ import org.springframework.webflow.execution.ScopeType; * * @author Keith Donald */ -public abstract class FlowVariable extends AnnotatedObject implements Serializable { +public class FlowVariable extends AnnotatedObject { /** * The variable name. @@ -36,20 +34,27 @@ public abstract class FlowVariable extends AnnotatedObject implements Serializab private String name; /** - * The variable scope. + * Is this flow variable local or global? Local variables go into flow scope. Global variables go into conversation + * scope. */ - private ScopeType scope; + private Boolean local; + + /** + * The value factory that provides this variable's value. + */ + private VariableValueFactory valueFactory; /** * Creates a new flow variable. * @param name the variable name - * @param scope the variable scope type + * @param local the local variable */ - public FlowVariable(String name, ScopeType scope) { + public FlowVariable(String name, VariableValueFactory valueFactory, boolean local) { Assert.hasText(name, "The variable name is required"); - Assert.notNull(scope, "The variable scope type is required"); + Assert.notNull(valueFactory, "The variable value factory is required"); this.name = name; - this.scope = scope; + this.valueFactory = valueFactory; + this.local = Boolean.valueOf(local); } /** @@ -60,10 +65,10 @@ public abstract class FlowVariable extends AnnotatedObject implements Serializab } /** - * Returns the scope of this variable. + * Is this a local flow variable or a conversation-scoped flow variable? */ - public ScopeType getScope() { - return scope; + public boolean isLocal() { + return local.booleanValue(); } // name and scope based equality @@ -73,11 +78,11 @@ public abstract class FlowVariable extends AnnotatedObject implements Serializab return false; } FlowVariable other = (FlowVariable) o; - return name.equals(other.name) && scope.equals(other.scope); + return name.equals(other.name) && valueFactory.equals(other.valueFactory) && local.equals(other.local); } public int hashCode() { - return name.hashCode() + scope.hashCode(); + return name.hashCode() + valueFactory.hashCode() + local.hashCode(); } /** @@ -85,18 +90,26 @@ public abstract class FlowVariable extends AnnotatedObject implements Serializab * @param context the flow execution request context */ public final void create(RequestContext context) { - scope.getScope(context).put(name, createVariableValue(context)); + Object value = valueFactory.createVariableValue(context); + if (local == Boolean.TRUE) { + context.getFlowScope().put(name, value); + } else { + context.getConversationScope().put(name, value); + } } - /** - * Hook method that needs to be implemented by subclasses to calculate the value of this flow variable based on the - * information available in the request context. - * @param context the flow execution request context - * @return the flow variable value - */ - protected abstract Object createVariableValue(RequestContext context); + public final Object restore(FlowSession session, RequestContext context) { + Object value; + if (local == Boolean.TRUE) { + value = session.getScope().get(name); + } else { + value = context.getConversationScope().get(name); + } + return valueFactory.restoreReferences(value, context); + } public String toString() { - return new ToStringCreator(this).append("name", name).append("scope", scope).toString(); + return new ToStringCreator(this).append("name", name).append("valueFactory", valueFactory).append("local", + local).toString(); } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/LocalFlowBuilderContext.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/LocalFlowBuilderContext.java index 22926c22..e8beab28 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/LocalFlowBuilderContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/LocalFlowBuilderContext.java @@ -18,6 +18,7 @@ package org.springframework.webflow.engine.builder.xml; import org.springframework.beans.factory.BeanFactory; import org.springframework.binding.convert.ConversionService; import org.springframework.binding.expression.ExpressionParser; +import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.io.ResourceLoader; import org.springframework.webflow.action.BeanInvokingActionFactory; import org.springframework.webflow.core.collection.AttributeMap; @@ -35,9 +36,9 @@ class LocalFlowBuilderContext implements FlowBuilderContext { private FlowBuilderContext parent; - private BeanFactory localFlowBeanFactory; + private GenericApplicationContext localFlowBeanFactory; - public LocalFlowBuilderContext(FlowBuilderContext parent, BeanFactory localFlowBeanFactory) { + public LocalFlowBuilderContext(FlowBuilderContext parent, GenericApplicationContext localFlowBeanFactory) { this.parent = parent; this.localFlowBeanFactory = localFlowBeanFactory; } @@ -100,10 +101,10 @@ class LocalFlowBuilderContext implements FlowBuilderContext { } public ResourceLoader getResourceLoader() { - return (ResourceLoader) getBeanFactory(); + return localFlowBeanFactory; } public BeanFactory getBeanFactory() { - return localFlowBeanFactory; + return localFlowBeanFactory.getBeanFactory(); } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java index df8b30c6..fdfaa440 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilder.java @@ -25,6 +25,7 @@ import java.util.List; import javax.xml.parsers.ParserConfigurationException; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.binding.convert.ConversionException; @@ -68,13 +69,13 @@ import org.springframework.webflow.engine.FlowVariable; import org.springframework.webflow.engine.TargetStateResolver; import org.springframework.webflow.engine.Transition; import org.springframework.webflow.engine.TransitionCriteria; +import org.springframework.webflow.engine.VariableValueFactory; 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.ActionExecutingViewFactory; -import org.springframework.webflow.engine.support.BeanFactoryFlowVariable; +import org.springframework.webflow.engine.support.BeanFactoryVariableValueFactory; import org.springframework.webflow.engine.support.BooleanExpressionTransitionCriteria; -import org.springframework.webflow.engine.support.SimpleFlowVariable; import org.springframework.webflow.engine.support.TransitionCriteriaChain; import org.springframework.webflow.engine.support.TransitionExecutingFlowExecutionExceptionHandler; import org.springframework.webflow.execution.Action; @@ -437,7 +438,7 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde this.localFlowBuilderContext = new LocalFlowBuilderContext(getContext(), createFlowBeanFactory(resources)); } - private BeanFactory createFlowBeanFactory(Resource[] resources) { + private GenericApplicationContext createFlowBeanFactory(Resource[] resources) { // see if this factory has a parent BeanFactory parent = getContext().getBeanFactory(); // determine the context implementation based on the current environment @@ -478,24 +479,20 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde private void parseAndAddFlowVariables(Element flowElement, Flow flow) { List varElements = DomUtils.getChildElementsByTagName(flowElement, VAR_ELEMENT); for (Iterator it = varElements.iterator(); it.hasNext();) { - flow.addVariable(parseVariable((Element) it.next())); + flow.addVariable(parseFlowVariable((Element) it.next())); } } - private FlowVariable parseVariable(Element element) { + private FlowVariable parseFlowVariable(Element element) { + Class clazz = (Class) fromStringTo(Class.class).execute(element.getAttribute(CLASS_ATTRIBUTE)); + VariableValueFactory valueFactory = new BeanFactoryVariableValueFactory(clazz, + (AutowireCapableBeanFactory) getFlow().getBeanFactory()); ScopeType scope = parseScope(element, ScopeType.FLOW); - if (StringUtils.hasText(element.getAttribute(BEAN_ATTRIBUTE))) { - return new BeanFactoryFlowVariable(element.getAttribute(NAME_ATTRIBUTE), element - .getAttribute(BEAN_ATTRIBUTE), getLocalContext().getBeanFactory(), scope); - } else { - if (StringUtils.hasText(element.getAttribute(CLASS_ATTRIBUTE))) { - Class variableClass = (Class) fromStringTo(Class.class).execute(element.getAttribute(CLASS_ATTRIBUTE)); - return new SimpleFlowVariable(element.getAttribute(NAME_ATTRIBUTE), variableClass, scope); - } else { - return new BeanFactoryFlowVariable(element.getAttribute(NAME_ATTRIBUTE), null, getLocalContext() - .getBeanFactory(), scope); - } + if (!(scope == ScopeType.FLOW || scope == ScopeType.CONVERSATION)) { + throw new IllegalArgumentException("Only " + ScopeType.FLOW + " or " + ScopeType.CONVERSATION + + " scope is allowed for flow variables"); } + return new FlowVariable(element.getAttribute("name"), valueFactory, scope == ScopeType.FLOW ? true : false); } private void parseAndAddStartActions(Element element, Flow flow) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/spring-webflow-2.0.xsd b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/spring-webflow-2.0.xsd index 4f0df56d..7e40f5f2 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/spring-webflow-2.0.xsd +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/spring-webflow-2.0.xsd @@ -259,7 +259,8 @@ The persistence context can be referenced from within this flow by the "entityMa @@ -623,47 +624,33 @@ of a non-singleton bean in the configured Bean Factory to use as the initial var - - - - -
  • request - The variable goes out of scope when a call to start this flow completes. -
  • flash - The variable goes out of scope when the next user event is signaled. -
  • flow - The variable goes out of scope when this flow session ends. -
  • conversation - The variable goes out of scope when the overall conversation governing this flow ends. - -
    -If not specified the default scope type is used ('flow' by default). -]]> - - - - + - - - - - - - + + + + +
  • request - The variable goes out of scope when a call to start this flow completes. +
  • flash - The variable goes out of scope when the next user event is signaled. +
  • flow - The variable goes out of scope when this flow session ends. +
  • conversation - The variable goes out of scope when the overall conversation governing this flow ends. + +
    +If not specified the default scope type is used ('flow' by default). +]]> + + + diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionTransitionCriteria.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionTransitionCriteria.java index e4100edb..e4672f12 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionTransitionCriteria.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionTransitionCriteria.java @@ -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. diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/BeanFactoryFlowVariable.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/BeanFactoryFlowVariable.java deleted file mode 100644 index c995958c..00000000 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/BeanFactoryFlowVariable.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2004-2007 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.support; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; -import org.springframework.webflow.engine.FlowVariable; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.ScopeType; - -/** - * A concrete flow variable subclass that obtains variable values from a Spring {@link BeanFactory}. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class BeanFactoryFlowVariable extends FlowVariable { - - /** - * The name of the bean whose value will be used as the flow variable. The bean should be a prototype. - */ - private String beanName; - - /** - * The bean factory where initial variable values will be obtained. - */ - private BeanFactory beanFactory; - - /** - * Convenience constructor to create a new bean factory flow variable. Defaults the bean name to the variable name. - * @param name the variable name which will also be used as the bean name - * @param beanFactory the bean factory where initial variable values will be obtained - * @param scope the variable scope - * @since 1.0.2 - */ - public BeanFactoryFlowVariable(String name, BeanFactory beanFactory, ScopeType scope) { - this(name, name, beanFactory, scope); - } - - /** - * Creates a new bean factory flow variable. - * @param variableName the variable name - * @param beanName the bean name, will default to the variable name if not specified - * @param beanFactory the bean factory where initial variable values will be obtained - * @param scope the variable scope - */ - public BeanFactoryFlowVariable(String variableName, String beanName, BeanFactory beanFactory, ScopeType scope) { - super(variableName, scope); - if (StringUtils.hasText(beanName)) { - this.beanName = beanName; - } else { - this.beanName = variableName; - } - Assert.notNull(beanFactory, "The bean factory is required"); - Assert.isTrue(!beanFactory.isSingleton(this.beanName), "The bean with name '" + this.beanName - + "' must be a prototype (singleton=false)"); - this.beanFactory = beanFactory; - } - - protected Object createVariableValue(RequestContext context) { - return beanFactory.getBean(beanName); - } -} \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/SimpleFlowVariable.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/SimpleFlowVariable.java deleted file mode 100644 index 34eee48b..00000000 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/SimpleFlowVariable.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2004-2007 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.support; - -import java.lang.reflect.Modifier; - -import org.springframework.beans.BeanUtils; -import org.springframework.util.Assert; -import org.springframework.webflow.engine.FlowVariable; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.ScopeType; - -/** - * A trivial concrete flow variable subclass that creates new variable values using Java reflection. - * - * @author Keith Donald - */ -public class SimpleFlowVariable extends FlowVariable { - - /** - * The concrete variable value class. - */ - private Class variableClass; - - /** - * Creates a new simple flow variable. - * @param name the variable name - * @param variableClass the concrete variable class - * @param scope the variable scope - */ - public SimpleFlowVariable(String name, Class variableClass, ScopeType scope) { - super(name, scope); - Assert.notNull(variableClass, "The variable class is required"); - Assert.isTrue(!variableClass.isInterface(), "The variable class cannot be an interface"); - Assert.isTrue(!Modifier.isAbstract(variableClass.getModifiers()), "The variable class cannot be abstract"); - this.variableClass = variableClass; - } - - /** - * Returns the variable value class. - */ - public Class getVariableClass() { - return variableClass; - } - - protected Object createVariableValue(RequestContext context) { - return BeanUtils.instantiateClass(variableClass); - } -} \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/definition/registry/FlowDefinitionRegistryImplTests.java b/spring-webflow/src/test/java/org/springframework/webflow/definition/registry/FlowDefinitionRegistryImplTests.java index 33166ddf..199bd6e5 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/definition/registry/FlowDefinitionRegistryImplTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/definition/registry/FlowDefinitionRegistryImplTests.java @@ -17,6 +17,8 @@ package org.springframework.webflow.definition.registry; import junit.framework.TestCase; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.core.io.ResourceLoader; import org.springframework.webflow.core.collection.AttributeMap; import org.springframework.webflow.definition.FlowDefinition; import org.springframework.webflow.definition.StateDefinition; @@ -101,6 +103,16 @@ public class FlowDefinitionRegistryImplTests extends TestCase { public StateDefinition getState(String id) throws IllegalArgumentException { return null; } + + public BeanFactory getBeanFactory() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Auto-generated method stub"); + } + + public ResourceLoader getResourceLoader() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Auto-generated method stub"); + } } private static class BarFlow implements FlowDefinition { @@ -129,5 +141,15 @@ public class FlowDefinitionRegistryImplTests extends TestCase { public StateDefinition getState(String id) throws IllegalArgumentException { return null; } + + public BeanFactory getBeanFactory() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Auto-generated method stub"); + } + + public ResourceLoader getResourceLoader() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Auto-generated method stub"); + } } } \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java index aa548c48..8d737b20 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowTests.java @@ -21,19 +21,16 @@ import junit.framework.TestCase; import org.springframework.binding.mapping.DefaultAttributeMapper; import org.springframework.binding.mapping.MappingBuilder; -import org.springframework.context.support.StaticApplicationContext; import org.springframework.webflow.TestException; import org.springframework.webflow.action.TestMultiAction; import org.springframework.webflow.core.collection.LocalAttributeMap; import org.springframework.webflow.core.expression.DefaultExpressionParserFactory; -import org.springframework.webflow.engine.support.BeanFactoryFlowVariable; import org.springframework.webflow.engine.support.DefaultTargetStateResolver; import org.springframework.webflow.engine.support.EventIdTransitionCriteria; -import org.springframework.webflow.engine.support.SimpleFlowVariable; import org.springframework.webflow.engine.support.TransitionExecutingFlowExecutionExceptionHandler; import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.execution.ScopeType; +import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.TestAction; import org.springframework.webflow.test.MockRequestControlContext; @@ -184,13 +181,17 @@ public class FlowTests extends TestCase { public void testStartWithVariables() { MockRequestControlContext context = new MockRequestControlContext(flow); - flow.addVariable(new SimpleFlowVariable("var1", ArrayList.class, ScopeType.FLOW)); - StaticApplicationContext beanFactory = new StaticApplicationContext(); - beanFactory.registerPrototype("bean", ArrayList.class); - flow.addVariable(new BeanFactoryFlowVariable("var2", "bean", beanFactory, ScopeType.FLOW)); + flow.addVariable(new FlowVariable("var1", new VariableValueFactory() { + public Object createVariableValue(RequestContext context) { + return new ArrayList(); + } + + public Object restoreReferences(Object value, RequestContext context) { + return value; + } + }, true)); flow.start(context, new LocalAttributeMap()); context.getFlowScope().getRequired("var1", ArrayList.class); - context.getFlowScope().getRequired("var2", ArrayList.class); } public void testStartWithMapper() { diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilderTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilderTests.java index a81ec5c6..fffa6458 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilderTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/xml/XmlFlowBuilderTests.java @@ -73,4 +73,15 @@ public class XmlFlowBuilderTests extends TestCase { assertNotNull(flow.getAttributes().get("persistenceContext")); assertTrue(((Boolean) flow.getAttributes().get("persistenceContext")).booleanValue()); } + + public void testFlowVariable() { + ClassPathResource resource = new ClassPathResource("flow-var.xml", getClass()); + builder = new XmlFlowBuilder(resource); + FlowAssembler assembler = new FlowAssembler(builder, new MockFlowBuilderContext("flow")); + Flow flow = assembler.assembleFlow(); + assertEquals("flow-foo", flow.getVariables()[0].getName()); + assertEquals(true, flow.getVariables()[0].isLocal()); + assertEquals("conversation-foo", flow.getVariables()[1].getName()); + assertEquals(false, flow.getVariables()[1].isLocal()); + } } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/support/BeanFactoryFlowVariableTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/support/BeanFactoryFlowVariableTests.java deleted file mode 100644 index 8ec4fa81..00000000 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/support/BeanFactoryFlowVariableTests.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2004-2007 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.support; - -import junit.framework.TestCase; - -import org.springframework.context.support.StaticApplicationContext; -import org.springframework.webflow.execution.ScopeType; -import org.springframework.webflow.test.MockRequestContext; - -public class BeanFactoryFlowVariableTests extends TestCase { - private MockRequestContext context = new MockRequestContext(); - - public void testCreateValidFlowVariable() { - StaticApplicationContext beanFactory = new StaticApplicationContext(); - beanFactory.registerPrototype("bean", Object.class); - BeanFactoryFlowVariable variable = new BeanFactoryFlowVariable("var", "bean", beanFactory, ScopeType.FLOW); - variable.create(context); - context.getFlowScope().getRequired("var"); - } -} \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/support/SimpleFlowVariableTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/support/SimpleFlowVariableTests.java deleted file mode 100644 index de279ae3..00000000 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/support/SimpleFlowVariableTests.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2004-2007 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.support; - -import java.util.ArrayList; - -import junit.framework.TestCase; - -import org.springframework.webflow.execution.ScopeType; -import org.springframework.webflow.test.MockRequestContext; - -public class SimpleFlowVariableTests extends TestCase { - private MockRequestContext context = new MockRequestContext(); - - public void testCreateValidFlowVariableCustomScope() { - SimpleFlowVariable variable = new SimpleFlowVariable("var", ArrayList.class, ScopeType.REQUEST); - variable.create(context); - assertTrue(context.getRequestScope().contains("var")); - context.getRequestScope().getRequired("var", ArrayList.class); - } - - public void testCreateVariableNoDefaultConstructor() { - SimpleFlowVariable variable = new SimpleFlowVariable("var", Integer.class, ScopeType.FLOW); - try { - variable.create(context); - fail("should have failed"); - } catch (Exception e) { - - } - } -}