Flux - The Smart Struts Config Generator
The type of Struts configuration Flux generates supports the idea of logical pages and module nesting. Both concepts do not only impose a certain action mapping structure on the configuration but also require employment of a few generic Struts action classes. Default implementations of these classes are provided with the Flux distribution in the file strux-1.0.1.jar (strux is short for 'struts supplement for flux'). If you want to use your own implementations instead you can override the respective class names in the Flux preferences.
Struts action mappings allow action class implementations to abstract from physical resource paths (usually JSPs) already. Unfortunately, this still means that the 'naked' JSP name may occur multiple times in the struts-config-<module>.xml everywhere where a forward to this page is required. Though maintainance of this alone is not really a problem the situation becomes harder if delivery of a page needs to perform some non-standard and configurable processings as a preparation before actually rendering the JSP. Where to put the configuration for each page? The solution Flux comes up with is another level of indirection called 'logical pages'.
A so-called logical page is an abstraction from its physical realization. It is a symbolic name that is used throughout the UML model and in the Struts action mappings to only indirectly reference the resource that actually generates the response. Usually the resource is a Java Server Page or a static HTML file but it may of course be any appropriate mechanism or technology.
Separating logical from physical pages yields the following advantages:
Logical pages are reflected in the page event mappings, in forward paths of action mappings and in the page mappings which actually map the logical pages to their physical counterparts. Page event mappings refer to the generic Struts action class 'Framework dispatcher action class'. This class simply forwards the incoming request to the action mapping path derived from the original URL. The default implementation delivered with Flux is de.matthias_burbach.workflow.util.DispatcherAction.
Struts 1.1 supports the decomposition of a web application into modules. Each module is configured in a separate struts-config-<module>.xml file. A module can branch into another module by referencing one of that module's entry points with an application relative path (as opposed to a module relative path). Unfortunately, Struts does not directly support dynamic nesting of modules, i. e. calling an entry point of another module and having this module return to its calling module when it finished its processing. This kind of module nesting where flows of one module can be integrated at some point in the flow of another module (like a function call) can, however, be modelled in a Flux UML activity diagram. Flux translates this into a couple of specific action mappings and respective framework dispatcher class references that effectively perform the desired kind of nesting in concert. See the examples that make heavy use of this feature.
For each entered module Flux generates one action mapping to enter the module and one mapping to continue in the calling module after return from the exiting module.
The syntax of these two kinds of mappings in the calling module's config is as follows:
<action path="/Module.<Name>.enter" ...>
<action path="/Module.<Name>.exit" ...>
A complementary action mapping in the called module is the final state mapping. If this mapping references the UnNestModuleAction class (which it does by default) execution of this class will find the module to be returned to being stored in the session and forward to it using the special URL that leads to the <action path="/Module.<Name>.exit" ...> mapping in the calling module.
The one final state mapping occurs when the model contains a UML final state. It maps the path '/FinalState' to a type that is executed if any of the other action mappings of the module forwards to it to mark the end of this module's processing chain in the current workflow.
The default action class being referenced by this final state mapping (de.matthias_burbach.workflow.util.UnNestModuleAction) returns to the module that called this module as a nested flow and passes on the result that this finalized module has reached as a string (a return code, if you like).