2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

Shale Dialog Manager (Basic Implementation)

Introduction

The Shale Dialog Manager defines a generic API by which an application may utilize a Dialog Manager implementation to manage conversations with the user of that application. A user may have (at most) one active conversation in each window or frame that he or she is using.

This module contains the Basic Implementation of the Shale Dialog Manager facilities. It is designed to be as simple as possible to configure and use, while encapsulating advanced state management capabilities. It is fundamentally similar in configuration and use with the legacy Dialog Manager support in Shale versions up through 1.0.3, but many bugs and limitations of the original code have been corrected.

Services Provided

Conceptually, a dialog can be thought of as a set of labelled states, connected by labelled transitions between those states. Indeed, a UML State Diagram is a popular way to represent the architecture of such a dialog. Each dialog has a specified starting state (with an automatic transition to this state when the dialog is first started), and one or more ending states.

Shale supports four state types, with specific implementations realized as described below.

  • ActionState - Represents a call to a public method, taking no parameters, and returning a String that will be treated as the logical outcome. The method to be called is configured with a JavaServer Faces method binding expression, which means you can leverage the managed beans facility to instantiate your processing classes on demand. The logical outcome is used to drive the transition to the next state, as described below.
  • ViewState - Represents the rendering of a JavaServer Faces view, followed by a wait for the subsequent form submit. The logical outcome returned by the action method (typically on the ViewController bean that you've associated with the current page) is used to drive the transition to the next state, as described below.
  • SubdialogState - Represents pushing the state of the current dialog onto a stack, and starting a specified new dialog at its starting state. When the subordinate dialog returns, the calling dialog is resumed, with the logical outcome returned by the subordinate dialog is used to drive the transition to the next state, as described below.
  • EndState - Terminates the current dialog (popping the stack if we are inside a subdialog), and returns a logical outcome (to drive transition) in one of two ways:
    • If a view identifier was configured, cause that view to be rendered and return the logical outcome from the application action that is invoked (just like a ViewState, but also terminates the dialog).
    • If no view identifier was configured (meaning that the parent dialog will be responsible for rendering the response to the current request), simply return the logical outcome that caused this EndState to be selected.
Transitions between states are performed by consulting the set of Transitions that have been defined (either locally for this State, or globally for the entire Dialog), matching on logical outcome. The matching Transition is then used to select the identifier of the next state to be performed (which can be of any type).

It is not required that all JavaServer Faces interactions be organized into dialogs -- you can have a mix of dialog and standard navigation processing. Indeed, to enter a dialog in the first place, simply have one of your standard action methods return a logical outcome of dialog:xxxxx, which will cause the dialog named xxxxx to be entered at its starting state. Once that dialog completes, standard JavaServer Faces navigation will resume.

The configuration of a Dialog is represented as a tree of JavaBeans defined in the org.apache.shale.dialog.model package, rooted at an instance Dialog. The set of all known Dialog instances is stored in a Map, keyed by dialog identifier, which is stored in an application scope attribute named by symbolic constant Globals.DIALOGS. The Dialog instances may be configured by any desired mechanism; however, the most commonly used will likely be an XML document that conforms to a DTD provided by Shale.

Using Dialog Manager (Basic Implementation)

To use the Dialog Manager facilities in Shale, take the following steps:

  • Model your dialog as a series of States with transitions between them labelled with the logical outcome that selects that particular transition. A UML State Diagram is a very useful mechanism for visualizing such a model.
  • Build the views (and corresponding ViewController beans, if you are also using the Shale View Controller Support functionality) that comprise your dialog, using standard JavaServer Faces and (optional) Shale ViewController facilities.
  • Define your dialogs in an XML document, conventionally named /WEB-INF/dialog-config.xml, that conforms to the required DTD, which defines all the state transitions:
    <!DOCTYPE dialogs PUBLIC
      "-//Apache Software Foundation//DTD Shale Dialog Configuration 1.1//EN"
      "http://shale.apache.org/dtds/dialog-config_1_1.dtd">
    
    <dialogs>
    
      <dialog name="First Dialog Name" start="Start State Id">
        ... <action/>, <view/>, <subdialog/>, and <exit/> elements for states ...
      </dialog>
    
      <dialog name="Second Dialog Name" start="Start State Id">
        ... <action/>, <view/>, <subdialog/>, and <exit/> elements for states ...
      </dialog>
    
      ...
    
    </dialogs>
    
  • Note that the DTD referenced above has thorough documentation on all of the supported XML elements and attributes.
  • If you have more than one dialog configuration file, or you have defined your only dialog configuration file as a web application resource with a name different than the one described above, use a context initiaization parameter to define a comma-delimited list of context-relative paths to configuration resources to be loaded:
    <context-param>
      <param-name>org.apache.shale.dialog.basic.CONFIGURATION</param-name>
      <param-value>/WEB-INF/foo.xml,/WEB-INF/bar.xml</param-value>
    </context-param>
    
  • In addition to the dialog configuration resources defined by this context initialization parameter, a resource named /WEB-INF/dialog-config.xml will be automatically processed, if it exists, and has not already been loaded.
  • Alternatively, or in addition to the above, any JAR file in /WEB-INF/lib will be scanned for configuration documents at META-INF/dialog-config.xml. Such resources will be automatically processed, making it easy to define JAR files with dialog configurations and corresponding Java classes and resources, which are recognized simply by including this JAR file in the application.
  • To initiate a dialog named "xxxxx", use one of the techniques defined by the Shale Dialog Manager.
In order to address potential issues with the application user using browser navigation buttons (back and forward) within a dialog, it is also possible to configure advanced handling of storing dialog state information across requests, with a context initialization parameter, as follows:
<context-param>
  <param-name>org.apache.shale.dialog.basic.STRATEGY</param-name>
  <param-value>xxxxx</param-value>
</context-param>

The possible strategy values, and the use cases under which they are appropriate, are as follows:

  • none - Save no extra information. This works best in circumstances when you have users trained to not use back and forward navigation buttons, so no extra overhead is incurred.
  • top - (Default value) Record the state name of the current state such that, if the user uses the back arrow and then resubmits a previously submitted form, the current state will be reset to the recorded one (so that navigation outcomes work as expected). The data object associated with this dialog instance is not saved and restored. This works best in cases like a multi-page wizard dialog that is collecting data, where resubmitting the same page again only mutates the state within the data object, and does not cause any undesireable changes to the model state of the application (such as submitting a credit card order more than once). This strategy can not effectively deal with cases where the user has navigated across the start or end of a subdialog, so an exception will be thrown in that scenario.
  • stack - Record the entire stack of Position information for the current dialog instance, including any changes to the data object. This strategy is best used when you want, when the user presses the back arrow, to "unwind" any changes that the previous form submit did to the data object. This strategy stores the maximum amount of information in the JSF component tree state, so it might have significant memory or network traffic impacts if the size of your data object is large.
Note that, no matter which strategy you choose, you can optionally use the "token" facility of the Shale Core module to detect duplicate submit attempts on the same form. If you do this, you will also want to provide a "cancel" command of some sort, with the immediate attribute set to true, to allow the user to get out of a dialog where they have mistakenly tried to submit the same form more than once.