
Originally Posted by
klr8
Given the fact that the parent and sub flow have access to the same request scope there is no use for mapping in this case: if the sub flow puts an object in request scope before it ends, it will still be there when the parent flow resumes
Hi Erwin,
Thanks for the explanation. You mention that there is no use for mapping sub-flow request scope to super-flow request scope. I agree on this point. I am only concerned with mapping the flow-scope of the sub-flow to the request-scope of the super-flow.
As it stands now, the sub-flow's action must place a flow-scoped form backing object into the request scope when the sub-flow completes. I'd argue that using a mapping to accomplish that task is a more desirable approach.
Consider the following example.
Code:
/**
* Does all the dirty work of building an instance of MyDomainObject.
*/
public class BuildMyDomainObjectAction extends FormAction {
public ComponentAction() {
setFormObjectName("myDomainObject");
setFormObjectScope(ScopeType.FLOW);
setFormObjectClass(MyDomainObject.class);
}
// ...
public Event submit(RequestContext context) throws Exception {
// Notice that we aren't explicitly adding the myDomainObject
// instance to the request scope here. It is implied that
// consumers of this action's flow will retrieve the instance
// in a fashion that is consistent with how it will be used.
// Some super-flows may require the instance in the request
// scope, and some may require the instance in the flow scope.
// Super-flows may also want this instance to be stored
// in their request scope with a name that is relevant to that flow.
return success();
}
}
Code:
<subflow-state id="buildCollectionElement" flow="myDomainObjectFlow">
<attribute-mapper>
<output value="myDomainObject" as="${requestScope.collectionElement}/>
</attribute-mapper>
<transition on="success" to="addCollectionElement" />
</subflow-state>
Code:
/**
* Builds an instance of MyParentObjectAction. This process involves
* launching a sub-flow to add new elements to the parent's collection.
*/
public class ParentObjectAction extends FormAction {
public ParentObjectActionAction() {
setFormObjectName("parentObject");
setFormObjectScope(ScopeType.FLOW);
setFormObjectClass(MyParentDomainObject.class);
}
/**
* Retrieves a MyDomainObject instance named
* "collectionElement" from the request scope and adds it
* to this flow's MyParentObjectAction's collection.
*/
public Event addCollectionElement(RequestContext ctx) throws Exception {
MyDomainObject collectionElement = (MyDomainObject) ctx.getRequestScope().get("collectionElement");
((MyParentDomainObject) getFormObject(ctx)).getCollection().add(
collectionElement
);
return success();
}
}
In this case, we've alleviated the need for the sub-flow to assume that the super-flow will be using the myDomainObject in the request scope. That responsibility has been delegated instead to the attribute mapper. This eliminates the sub-flow's orthagonal responsibility of correctly naming and placing its form backing object in the request scope as required by the super flow.
As a side effect, our super-flow's action knows only that an incoming collection element will be named "collectionElement" and that it'll be appropriately accessible from the request scope. If we have any problems with retrieving this value, we know right where to look: the attribute mappings!
Thanks for taking the time to consider my rebuttal! =)
-Alex