Added Spring scoping support (SWF-163). Also updated the sellitem-jsf sample to use the new scoping scheme.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
<faces-config>
|
||||
<application>
|
||||
<navigation-handler>org.springframework.webflow.executor.jsf.FlowNavigationHandler</navigation-handler>
|
||||
<variable-resolver>org.springframework.webflow.executor.jsf.DelegatingFlowVariableResolver</variable-resolver>
|
||||
<variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
|
||||
</application>
|
||||
|
||||
<lifecycle>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?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:flow="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/webflow-config
|
||||
http://www.springframework.org/schema/webflow-config/spring-webflow-config-1.1.xsd">
|
||||
|
||||
<flow:enable-scopes/>
|
||||
|
||||
<bean id="sale" class="org.springframework.webflow.samples.sellitem.Sale" scope="conversation"/>
|
||||
|
||||
</beans>
|
||||
@@ -3,8 +3,6 @@
|
||||
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">
|
||||
|
||||
<var name="sale" class="org.springframework.webflow.samples.sellitem.Sale" scope="conversation"/>
|
||||
|
||||
<start-state idref="enterPriceAndItemCount" />
|
||||
|
||||
@@ -33,6 +31,6 @@
|
||||
<transition on="success" to="showCostOverview" />
|
||||
</action-state>
|
||||
|
||||
<end-state id="showCostOverview" view="/costOverview.jsp" />
|
||||
<end-state id="showCostOverview" view="/costOverview.jsp" />
|
||||
|
||||
</flow>
|
||||
@@ -9,6 +9,7 @@
|
||||
<param-value>
|
||||
classpath:org/springframework/webflow/samples/sellitem/services-config.xml
|
||||
/WEB-INF/webflow-config.xml
|
||||
/WEB-INF/flows/sellitem-beans.xml
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
http\://www.springframework.org/schema/webflow-config/spring-webflow-config-1.0.xsd=org/springframework/webflow/config/spring-webflow-config-1.0.xsd
|
||||
http\://www.springframework.org/schema/webflow-config/spring-webflow-config-1.0.xsd=org/springframework/webflow/config/spring-webflow-config-1.0.xsd
|
||||
http\://www.springframework.org/schema/webflow-config/spring-webflow-config-1.1.xsd=org/springframework/webflow/config/spring-webflow-config-1.1.xsd
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.webflow.context.scope.ScopeRegistrar;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link BeanDefinitionParser} for the <code><enable-scopes></code> tag.
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @since 1.1
|
||||
*/
|
||||
class EnableScopesBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return ScopeRegistrar.class;
|
||||
}
|
||||
|
||||
protected boolean shouldGenerateId() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -65,5 +65,6 @@ public class WebFlowConfigNamespaceHandler extends NamespaceHandlerSupport {
|
||||
registerBeanDefinitionParser("execution-listeners", new ExecutionListenersBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("executor", new ExecutorBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("registry", new RegistryBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("enable-scopes", new EnableScopesBeanDefinitionParser());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<xsd:schema
|
||||
xmlns="http://www.springframework.org/schema/webflow-config"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
targetNamespace="http://www.springframework.org/schema/webflow-config"
|
||||
elementFormDefault="qualified" attributeFormDefault="unqualified"
|
||||
version="1.1">
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Spring Web Flow Configuration Schema
|
||||
Authors: Keith Donald, Ben Hale
|
||||
<br>
|
||||
Provides an easy way to configure a flow executor and an XML flow definition registry.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"
|
||||
schemaLocation="http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" />
|
||||
|
||||
<xsd:element name="enable-scopes">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Allows access to the Spring Web Flow scopes (conversation, flow, flash) from a Spring ApplicationContext.
|
||||
Only one of these elements is required per ApplicationContext.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="registry">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Deploys a flow definition registry. A flow definition registry contains a set of flow definitions.
|
||||
A flow definition is typically built from externalized resource location such as a .xml file.
|
||||
<br>
|
||||
Each flow definition registered in this registry is assigned a unique identifier. By default,
|
||||
this identifier is the name of the externalized resource minus its file extension. For example,
|
||||
a registry containing flow definitions built from the files "orderitem-flow.xml" and "shipping-flow.xml"
|
||||
would index those definitions by "orderitem-flow" and "shipping-flow" by default.
|
||||
<br>
|
||||
A flow registry is used by a flow executor at runtime to launch new executions of flow definitions.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="location" type="locationType" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Specifies a path to a externalized flow definition resource. The flow definition built from this
|
||||
resource will be registered in this registry.
|
||||
<br>
|
||||
Individual paths such as:
|
||||
<pre>
|
||||
/WEB-INF/flows/orderitem-flow.xml
|
||||
</pre>
|
||||
... are supported as well as wildcard paths such as:
|
||||
<pre>
|
||||
/WEB-INF/flows/**/*-flow.xml
|
||||
</pre>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="locationType">
|
||||
<xsd:attribute name="path" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The path to the externalized flow definition resource. May be a path to a single resource or
|
||||
a ANT-style path expression that matches multiple resources.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="executor">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Deploys a flow executor. A flow executor executes flow definitions. More specifically, an executor
|
||||
is responsible for launching new flow executions as well as resuming paused flow executions.
|
||||
A flow execution that spans more than one request is said to have 'paused' and is stored in
|
||||
an execution repository.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="repository" type="repositoryType" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Explicit repository configuration for this executor. This element is used if configuration needs
|
||||
to be more fine grained than the repositoryType attribute on executor.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="execution-attributes" type="execution-attributesType" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Execution attributes to associate with new flow executions launched by this executor.
|
||||
These attributes may influence execution behavior.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="execution-listeners" type="execution-listenersType" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The listeners eligible for observing the lifecycle of executions launched by this executor.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="repository-type" type="repositoryTypeAttribute">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The type of execution repository to use. The repository is responsible for managing flow execution
|
||||
persistence between requests.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="registry-ref" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The idref to the registry this executor will use to locate flow definitions for execution.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:simpleType name="repositoryTypeAttribute">
|
||||
<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.
|
||||
]]>
|
||||
</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="client">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The client continuation repository type. Use this to snapshot flow execution state client-side to support use of the browser
|
||||
back button in a stateless server environment.
|
||||
]]>
|
||||
</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="repositoryType">
|
||||
<xsd:attribute name="type" type="repositoryTypeAttribute" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The type of flow execution repository to use. The repository is responsible for managing flow execution
|
||||
persistence between requests.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="max-conversations" type="xsd:integer">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The maximum number of concurrent conversations allowed by this repository. It is illegal to set this
|
||||
attribute if you are also setting the 'conversation-manager-ref' attribute.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="max-continuations" type="xsd:integer">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The maximum number of flow execution continuations (snapshots) allowed by this repository per conversation.
|
||||
This attribute is only relevant when the repository type is 'continuation'.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="conversation-manager-ref" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The idref of the conversation manager this repository should use. Setting this attribute
|
||||
allows full control over the conversation manager implementation and configuration.
|
||||
When used, any value for the 'max-conversations' attribute is ignored.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="execution-listenersType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="listener" type="listenerType" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Deploys a single flow execution listener that will observe the execution lifecycle of one or more
|
||||
flow definitions. The flow definitions this listener applies to may be restricted by specifying criteria.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="listenerType">
|
||||
<xsd:attribute name="ref" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The idref to your flow execution listener.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="criteria" type="xsd:string" default="*">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The flow definitions your listener should apply to, delimited by commas or '*' for "all".
|
||||
Example: 'flow1,flow2,flow3'.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="execution-attributesType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="alwaysRedirectOnPause" type="alwaysRedirectOnPauseType" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Sets the 'alwaysRedirectOnPause' execution attribute value. 'alwaysRedirectOnPause' allows
|
||||
control over whether each time a flow execution pauses a browser redirect is performed. If
|
||||
not specified the default value is 'true' unless explicitly set otherwise.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="attribute" type="attributeType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
A single attribute describing an element. Attributes have string keys and object values.
|
||||
An attribute's type may be specified using the 'type' attribute.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="alwaysRedirectOnPauseType">
|
||||
<xsd:attribute name="value" type="xsd:boolean" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
true = always redirect on pause; false = do not, only redirect when explicitly instructed by the flow definition.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="attributeType">
|
||||
<xsd:attribute name="name" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The name of the attribute.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="type" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The attribute's type, used to perform a from-string type conversion if specified.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="value" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The attribute value, subject to type conversion if the 'type' attribute is defined.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
</xsd:schema>
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.context.scope;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.config.Scope;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.execution.FlowExecutionContext;
|
||||
import org.springframework.webflow.execution.FlowExecutionContextHolder;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* Abstract {@link Scope} implementation that reads from a particular scope
|
||||
* in the current thread-bound {@link FlowExecutionContext} object.
|
||||
*
|
||||
* <p>Subclasses simply need to implement {@link #getScope()} to instruct
|
||||
* this class which {@link FlowExecutionContext} scope to read attributes from.
|
||||
*
|
||||
* <p>Relies on a thread-bound @{link FlowExecutionContext} instance wich is located
|
||||
* through a @{link FlowExecutionContextHolder}.
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @since 1.1
|
||||
* @see FlowExecutionContext
|
||||
* @see FlowExecutionContextHolder
|
||||
*/
|
||||
public abstract class AbstractWebFlowScope implements Scope {
|
||||
|
||||
/**
|
||||
* Logger, usable by subclasses.
|
||||
*/
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/**
|
||||
* Template method that determines the actual target scope.
|
||||
* @return the target scope
|
||||
* @see RequestContext#getConversationScope()
|
||||
* @see RequestContext#getFlowScope()
|
||||
* @see RequestContext#getRequestScope()
|
||||
* @see RequestContext#getFlashScope()
|
||||
*/
|
||||
protected abstract MutableAttributeMap getScope();
|
||||
|
||||
public Object get(String name, ObjectFactory objectFactory) {
|
||||
MutableAttributeMap scope;
|
||||
try {
|
||||
scope = getScope();
|
||||
} catch(IllegalStateException e) {
|
||||
throw new ScopedBeanException("Cannot retrieve scoped bean '"
|
||||
+ name + "' before the scope has been populated");
|
||||
}
|
||||
Object scopedObject = scope.get(name);
|
||||
if (scopedObject == null) {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Could not find existing scoped instance of '" +
|
||||
name + "'; creating new instace");
|
||||
}
|
||||
scopedObject = objectFactory.getObject();
|
||||
scope.put(name, scopedObject);
|
||||
} else {
|
||||
if(logger.isDebugEnabled()) {
|
||||
logger.debug("Found existing scoped instance of '" +
|
||||
name + "'");
|
||||
}
|
||||
}
|
||||
return scopedObject;
|
||||
}
|
||||
|
||||
public Object remove(String name) {
|
||||
try {
|
||||
return getScope().remove(name);
|
||||
} catch(IllegalStateException e) {
|
||||
throw new ScopedBeanException("Cannot remove scoped bean '" +
|
||||
name + "' before the scope has been populated");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns <code>null</code> as most Spring Web Flow scopes do not
|
||||
* have obvious conversation ids. Subclasses should override this method
|
||||
* where conversation ids can be intelligently returned.
|
||||
* @return always returns <code>null</code>
|
||||
*/
|
||||
public String getConversationId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will not register a destruction callback as Spring Web Flow does not
|
||||
* support destruction of scoped beans. Subclasses should override this
|
||||
* method where where destruction can adequately be accomplished.
|
||||
* @param name the name of the bean to register the callback for
|
||||
* @param callback the callback to execute
|
||||
*/
|
||||
public void registerDestructionCallback(String name, Runnable callback) {
|
||||
logger.warn("Destruction callback for '" + name +
|
||||
"' was not registered. Spring Web Flow does not " +
|
||||
"support destruction of scoped beans.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current flow execution context. Used by subclasses to easily
|
||||
* get access to the thread-bound flow execution context.
|
||||
* @return the current thread-bound flow execution context
|
||||
*/
|
||||
protected FlowExecutionContext getFlowExecutionContext() {
|
||||
return FlowExecutionContextHolder.getFlowExecutionContext();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.context.scope;
|
||||
|
||||
import org.springframework.beans.factory.config.Scope;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.execution.FlowExecution;
|
||||
|
||||
/**
|
||||
* Conversation-backed {@link Scope} implementation.
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @since 1.1
|
||||
* @see FlowExecution#getConversationScope()
|
||||
*/
|
||||
public class ConversationScope extends AbstractWebFlowScope {
|
||||
|
||||
protected MutableAttributeMap getScope() {
|
||||
return getFlowExecutionContext().getConversationScope();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.context.scope;
|
||||
|
||||
import org.springframework.beans.factory.config.Scope;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.execution.FlowSession;
|
||||
|
||||
/**
|
||||
* Flash-backed {@link Scope} implementation.
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @since 1.1
|
||||
* @see FlowSession#getFlashMap()
|
||||
*/
|
||||
public class FlashScope extends AbstractWebFlowScope {
|
||||
|
||||
protected MutableAttributeMap getScope() {
|
||||
return getFlowExecutionContext().getActiveSession().getFlashMap();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.context.scope;
|
||||
|
||||
import org.springframework.beans.factory.config.Scope;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.execution.FlowSession;
|
||||
|
||||
/**
|
||||
* Flow-backed {@link Scope} implementation.
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @since 1.1
|
||||
* @see FlowSession#getScope()
|
||||
*/
|
||||
public class FlowScope extends AbstractWebFlowScope {
|
||||
|
||||
protected MutableAttributeMap getScope() {
|
||||
return getFlowExecutionContext().getActiveSession().getScope();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.context.scope;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.Scope;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.webflow.execution.ScopeType;
|
||||
|
||||
/**
|
||||
* Registers the Spring Web Flow bean scopes with a @{link ConfigurableListableBeanFactory}.
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @see Scope
|
||||
*/
|
||||
public class ScopeRegistrar implements BeanFactoryPostProcessor, Ordered {
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
beanFactory.registerScope(ScopeType.CONVERSATION.getLabel().toLowerCase(), new ConversationScope());
|
||||
beanFactory.registerScope(ScopeType.FLASH.getLabel().toLowerCase(), new FlashScope());
|
||||
beanFactory.registerScope(ScopeType.FLOW.getLabel().toLowerCase(), new FlowScope());
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.context.scope;
|
||||
|
||||
import org.springframework.webflow.core.FlowException;
|
||||
|
||||
/**
|
||||
* Thrown when a bean cannot be retrieved because the scope it resides in
|
||||
* has not yet been populated. This might occur if the bean is being referenced
|
||||
* before the FlowExecution has been retrieved.
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @since 1.1
|
||||
*/
|
||||
public class ScopedBeanException extends FlowException {
|
||||
|
||||
/**
|
||||
* Create a new scoped bean exception.
|
||||
* @param message the message
|
||||
* @param cause the root cause of the failure
|
||||
*/
|
||||
public ScopedBeanException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new scoped bean exception.
|
||||
* @param message the message
|
||||
*/
|
||||
public ScopedBeanException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.execution;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple holder class that associates a {@link FlowExecutionContext} instance
|
||||
* with the current thread. The FlowExecutionContext will not be inherited by
|
||||
* any child threads spawned by the current thread.
|
||||
* <p>
|
||||
* Used as a central holder for the current FlowExecutionContext in Spring Web
|
||||
* Flow, wherever necessary. Often used by artifacts needing to access the
|
||||
* current active flow execution.
|
||||
*
|
||||
* @see FlowExecutionContext
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @since 1.1
|
||||
*/
|
||||
public class FlowExecutionContextHolder {
|
||||
|
||||
private static final ThreadLocal flowExecutionContextHolder = new ThreadLocal();
|
||||
|
||||
/**
|
||||
* Associate the given FlowExecutionContext with the current thread.
|
||||
* @param flowExecutionContext the current FlowExecutionContext, or
|
||||
* <code>null</code> to reset the thread-bound context
|
||||
*/
|
||||
public static void setFlowExecutionContext(FlowExecutionContext flowExecutionContext) {
|
||||
flowExecutionContextHolder.set(flowExecutionContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the FlowExecutionContext associated with the current thread, if
|
||||
* any.
|
||||
* @return the current FlowExecutionContext
|
||||
* @throws IllegalStateException if no FlowExecutionContext is bound to this
|
||||
* thread
|
||||
*/
|
||||
public static FlowExecutionContext getFlowExecutionContext() {
|
||||
Assert.state(flowExecutionContextHolder.get() != null,
|
||||
"No request context is bound to this thread");
|
||||
return (FlowExecutionContext) flowExecutionContextHolder.get();
|
||||
}
|
||||
|
||||
// not instantiable
|
||||
private FlowExecutionContextHolder() {
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import javax.faces.context.FacesContext;
|
||||
import javax.faces.el.EvaluationException;
|
||||
|
||||
import org.springframework.webflow.execution.FlowExecution;
|
||||
import org.springframework.webflow.execution.FlowExecutionContextHolder;
|
||||
|
||||
/**
|
||||
* A static utility class for accessing the current flow execution holder.
|
||||
@@ -48,6 +49,7 @@ public class FlowExecutionHolderUtils {
|
||||
*/
|
||||
public static void setFlowExecutionHolder(FlowExecutionHolder holder, FacesContext context) {
|
||||
context.getExternalContext().getRequestMap().put(getFlowExecutionHolderKey(), holder);
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(holder.getFlowExecution());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.webflow.definition.FlowDefinition;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
|
||||
import org.springframework.webflow.engine.NoMatchingTransitionException;
|
||||
import org.springframework.webflow.execution.FlowExecution;
|
||||
import org.springframework.webflow.execution.FlowExecutionContextHolder;
|
||||
import org.springframework.webflow.execution.FlowExecutionFactory;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
import org.springframework.webflow.executor.RequestParameterInputMapper;
|
||||
@@ -246,6 +247,7 @@ public class FlowNavigationHandler extends DecoratingNavigationHandler {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cleaning up allocated flow system resources");
|
||||
}
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
FlowExecutionHolderUtils.unlockCurrentFlowExecutionIfNecessary(context);
|
||||
ExternalContextHolder.setExternalContext(null);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.definition.FlowDefinition;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionLocator;
|
||||
import org.springframework.webflow.execution.FlowExecution;
|
||||
import org.springframework.webflow.execution.FlowExecutionContextHolder;
|
||||
import org.springframework.webflow.execution.FlowExecutionFactory;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
import org.springframework.webflow.execution.repository.FlowExecutionAccessException;
|
||||
@@ -481,6 +482,7 @@ public class FlowPhaseListener implements PhaseListener {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cleaning up allocated flow system resources");
|
||||
}
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
FlowExecutionHolderUtils.unlockCurrentFlowExecutionIfNecessary(context);
|
||||
ExternalContextHolder.setExternalContext(null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.context.scope;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.webflow.execution.FlowExecutionContextHolder;
|
||||
import org.springframework.webflow.test.MockFlowExecutionContext;
|
||||
|
||||
/**
|
||||
* Test cases for the @{link ConversationScope} class.
|
||||
*
|
||||
* @author Ben Hale
|
||||
*/
|
||||
public class ConversationScopeTests extends TestCase {
|
||||
|
||||
private MockFlowExecutionContext context;
|
||||
|
||||
private ConversationScope scope;
|
||||
|
||||
protected void setUp() {
|
||||
context = new MockFlowExecutionContext();
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(context);
|
||||
scope = new ConversationScope();
|
||||
}
|
||||
|
||||
protected void tearDown() {
|
||||
scope = null;
|
||||
context = null;
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
}
|
||||
|
||||
public void testGetVarMissing() {
|
||||
StubObjectFactory factory = new StubObjectFactory();
|
||||
Object gotten = scope.get("name", factory);
|
||||
assertNotNull("Should be real object", gotten);
|
||||
assertTrue("Should have added object to the map", context.getConversationScope().contains("name"));
|
||||
assertSame("Created object should have been returned", factory.getValue(), gotten);
|
||||
assertSame("Created object should have been persisted", factory.getValue(), context.getConversationScope().get(
|
||||
"name"));
|
||||
}
|
||||
|
||||
public void testGetVarExist() {
|
||||
StubObjectFactory factory = new StubObjectFactory();
|
||||
Object value = new Object();
|
||||
context.getConversationScope().put("name", value);
|
||||
Object gotten = scope.get("name", factory);
|
||||
assertNotNull("Should be real object", gotten);
|
||||
assertTrue("Should still be in map", context.getConversationScope().contains("name"));
|
||||
assertSame("Persisted object should have been returned", value, gotten);
|
||||
assertNotSame("Created object should not have been returned", factory.getValue(), gotten);
|
||||
}
|
||||
|
||||
public void testGetRequestContextMissing() {
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
StubObjectFactory factory = new StubObjectFactory();
|
||||
try {
|
||||
scope.get("name", factory);
|
||||
fail("Should have thrown a ScopedBeanException without a request context");
|
||||
} catch (ScopedBeanException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetConversationId() {
|
||||
String conversationId = scope.getConversationId();
|
||||
assertNull("Method not implemented yet, should return null", conversationId);
|
||||
}
|
||||
|
||||
public void testRemoveVarMissing() {
|
||||
Object removed = scope.remove("name");
|
||||
assertFalse("Should have removed from object from map", context.getConversationScope().contains("name"));
|
||||
assertNull("Should have returned a null object", removed);
|
||||
}
|
||||
|
||||
public void testRemoveVarExist() {
|
||||
Object value = new Object();
|
||||
context.getConversationScope().put("name", value);
|
||||
Object removed = scope.remove("name");
|
||||
assertFalse("Should have removed from object from map", context.getConversationScope().contains("name"));
|
||||
assertSame("Should have returned the previous object", removed, value);
|
||||
}
|
||||
|
||||
public void testRemoveRequestContextMissing() {
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
try {
|
||||
scope.remove("name");
|
||||
fail("Should have thrown a ScopedBeanException without a request context");
|
||||
} catch (ScopedBeanException e) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.context.scope;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.webflow.execution.FlowExecutionContextHolder;
|
||||
import org.springframework.webflow.test.MockFlowExecutionContext;
|
||||
|
||||
/**
|
||||
* Test cases for the
|
||||
* @{link FlashScope} class.
|
||||
*
|
||||
* @author Ben Hale
|
||||
*/
|
||||
public class FlashScopeTests extends TestCase {
|
||||
|
||||
private MockFlowExecutionContext context;
|
||||
|
||||
private FlashScope scope;
|
||||
|
||||
protected void setUp() {
|
||||
context = new MockFlowExecutionContext();
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(context);
|
||||
scope = new FlashScope();
|
||||
}
|
||||
|
||||
protected void tearDown() {
|
||||
scope = null;
|
||||
context = null;
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
}
|
||||
|
||||
public void testGetVarMissing() {
|
||||
StubObjectFactory factory = new StubObjectFactory();
|
||||
Object gotten = scope.get("name", factory);
|
||||
assertNotNull("Should be real object", gotten);
|
||||
assertTrue("Should have added object to the map", context.getActiveSession().getFlashMap().contains("name"));
|
||||
assertSame("Created object should have been returned", factory.getValue(), gotten);
|
||||
assertSame("Created object should have been persisted", factory.getValue(), context.getActiveSession()
|
||||
.getFlashMap().get("name"));
|
||||
}
|
||||
|
||||
public void testGetVarExist() {
|
||||
StubObjectFactory factory = new StubObjectFactory();
|
||||
Object value = new Object();
|
||||
context.getActiveSession().getFlashMap().put("name", value);
|
||||
Object gotten = scope.get("name", factory);
|
||||
assertNotNull("Should be real object", gotten);
|
||||
assertTrue("Should still be in map", context.getActiveSession().getFlashMap().contains("name"));
|
||||
assertSame("Persisted object should have been returned", value, gotten);
|
||||
assertNotSame("Created object should not have been returned", factory.getValue(), gotten);
|
||||
}
|
||||
|
||||
public void testGetRequestContextMissing() {
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
StubObjectFactory factory = new StubObjectFactory();
|
||||
try {
|
||||
scope.get("name", factory);
|
||||
fail("Should have thrown a ScopedBeanException without a request context");
|
||||
} catch (ScopedBeanException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetConversationId() {
|
||||
String flashId = scope.getConversationId();
|
||||
assertNull("Method not implemented yet, should return null", flashId);
|
||||
}
|
||||
|
||||
public void testRemoveVarMissing() {
|
||||
Object removed = scope.remove("name");
|
||||
assertFalse("Should have removed from object from map", context.getActiveSession().getFlashMap().contains(
|
||||
"name"));
|
||||
assertNull("Should have returned a null object", removed);
|
||||
}
|
||||
|
||||
public void testRemoveVarExist() {
|
||||
Object value = new Object();
|
||||
context.getActiveSession().getFlashMap().put("name", value);
|
||||
Object removed = scope.remove("name");
|
||||
assertFalse("Should have removed from object from map", context.getActiveSession().getFlashMap().contains(
|
||||
"name"));
|
||||
assertSame("Should have returned the previous object", removed, value);
|
||||
}
|
||||
|
||||
public void testRemoveRequestContextMissing() {
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
try {
|
||||
scope.remove("name");
|
||||
fail("Should have thrown a ScopedBeanException without a request context");
|
||||
} catch (ScopedBeanException e) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.context.scope;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.webflow.execution.FlowExecutionContextHolder;
|
||||
import org.springframework.webflow.test.MockFlowExecutionContext;
|
||||
|
||||
/**
|
||||
* Test cases for the
|
||||
* @{link FlowScope} class.
|
||||
*
|
||||
* @author Ben Hale
|
||||
*/
|
||||
public class FlowScopeTests extends TestCase {
|
||||
|
||||
private MockFlowExecutionContext context;
|
||||
|
||||
private FlowScope scope;
|
||||
|
||||
protected void setUp() {
|
||||
context = new MockFlowExecutionContext();
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(context);
|
||||
scope = new FlowScope();
|
||||
}
|
||||
|
||||
protected void tearDown() {
|
||||
scope = null;
|
||||
context = null;
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
}
|
||||
|
||||
public void testGetVarMissing() {
|
||||
StubObjectFactory factory = new StubObjectFactory();
|
||||
Object gotten = scope.get("name", factory);
|
||||
assertNotNull("Should be real object", gotten);
|
||||
assertTrue("Should have added object to the map", context.getActiveSession().getScope().contains("name"));
|
||||
assertSame("Created object should have been returned", factory.getValue(), gotten);
|
||||
assertSame("Created object should have been persisted", factory.getValue(), context.getActiveSession()
|
||||
.getScope().get("name"));
|
||||
}
|
||||
|
||||
public void testGetVarExist() {
|
||||
StubObjectFactory factory = new StubObjectFactory();
|
||||
Object value = new Object();
|
||||
context.getActiveSession().getScope().put("name", value);
|
||||
Object gotten = scope.get("name", factory);
|
||||
assertNotNull("Should be real object", gotten);
|
||||
assertTrue("Should still be in map", context.getActiveSession().getScope().contains("name"));
|
||||
assertSame("Persisted object should have been returned", value, gotten);
|
||||
assertNotSame("Created object should not have been returned", factory.getValue(), gotten);
|
||||
}
|
||||
|
||||
public void testGetRequestContextMissing() {
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
StubObjectFactory factory = new StubObjectFactory();
|
||||
try {
|
||||
scope.get("name", factory);
|
||||
fail("Should have thrown a ScopedBeanException without a request context");
|
||||
} catch (ScopedBeanException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetConversationId() {
|
||||
String flowId = scope.getConversationId();
|
||||
assertNull("Method not implemented yet, should return null", flowId);
|
||||
}
|
||||
|
||||
public void testRemoveVarMissing() {
|
||||
Object removed = scope.remove("name");
|
||||
assertFalse("Should have removed from object from map", context.getActiveSession().getScope().contains("name"));
|
||||
assertNull("Should have returned a null object", removed);
|
||||
}
|
||||
|
||||
public void testRemoveVarExist() {
|
||||
Object value = new Object();
|
||||
context.getActiveSession().getScope().put("name", value);
|
||||
Object removed = scope.remove("name");
|
||||
assertFalse("Should have removed from object from map", context.getActiveSession().getScope().contains("name"));
|
||||
assertSame("Should have returned the previous object", removed, value);
|
||||
}
|
||||
|
||||
public void testRemoveRequestContextMissing() {
|
||||
FlowExecutionContextHolder.setFlowExecutionContext(null);
|
||||
try {
|
||||
scope.remove("name");
|
||||
fail("Should have thrown a ScopedBeanException without a request context");
|
||||
} catch (ScopedBeanException e) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.context.scope;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
|
||||
/**
|
||||
* Stub implementation for testing the Spring Web Flow scopes.
|
||||
*
|
||||
* @author Ben Hale
|
||||
*/
|
||||
public class StubObjectFactory implements ObjectFactory {
|
||||
|
||||
private Object value = new Object();
|
||||
|
||||
public Object getObject() throws BeansException {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user