The Client

The wizard client classes present a user with a graphical user interface used to manipulate the settings on the server. As stated in Wizard Architecture and The Server, the server is responsible for performing the task that defines the purpose of the wizard. Without the client classes, the server would be able to perform its operation, but the user would have no way of modifying the settings within the WizardState.

The main responsibility of the client classes is to provide an interface through which the user can guide the execution of the wizard. Other important features the client should have include:

The client responsibilities are fulfilled by a set of classes connected by a WizardTreeManager object, which implements the Mediator design pattern. This design pattern was also used on the server (*html tag here). Each object in the client maintains a reference (or is able to request a reference) to the WizardTreeManager.

The ability to run in a browser influences the implementation of the entire client. The WizardConsole is the class responsible for the layout of the wizard. The WizardConsole is subclassed from Panel, and can be used either within a frame (for application mode) or within an Applet (for browser mode). The WizardConsole provides the interface between the system environment and the other client classes. Other responsibilities of the WizardConsole include:

The WizardTreeManager is responsible for creating all of the panels that are displayed by the WizardConsole. The panels consist of the image panel, the navigation panel, and the wizard panel. The image panel displays an image that can be used for quick identification of the purpose of the wizard. The navigation panel presents a common interface for wizard user interface traversal. The wizard panel provides a space for panels to be displayed that will guide the user through the wizard setup and execution.

The WizardTreeManager is also responsible for deserializing the wizard-specific panels (referred to as the client panel tree) from the wizard archive. To do this, the WizardTreeManager uses the WizardState object to read the client section from the archive. The WizardTreeManager instantiates each of the client tree panels, and gives each panel the opportunity to deserialize its required initialization data from the archive.

The WizardTreeManager facilitates the retrieval of all data stored in the wizard archive. Common examples of data that the client will access are image data, initialization data, and audio data. Client objects will use the getNamedResource method to retrieve data from the archive.

The WizardTreeManager manages the client panel tree traversal. This is accomplished by listening for events originating from the navigation buttons and sending messages to the IteratorLayout object that is responsible for traversing the tree. By making the navigation mechanism a part of the client-side architecture, all wizards will have the same navigation semantics and behavior. This user experience reuse reduces confusion and helps instill user confidence during the wizard execution.

The wizard client tree panels are arranged in a tree structure. The tree is comprised of leafs (the panels to be displayed), and nodes (objects that have panels and/or nodes as children). The structure of the tree, combined with the logic in the panels and nodes, determines the order in which the panels are displayed. Nodes can be used to enable or disable the traversal of its child panels, which provides alternate paths that the user can explore to make additional decisions about how the wizard will execute. This facilitates creating a single wizard with good default values that require no user intervention. This can also be used to allow the user to enter advanced settings. This feature can be used to broaden the audience of a particular wizard to include novice as well as advanced users.

The wizard panels that comprise the client panel tree are subclassed from WizardLeaf. The nodes in the client panel tree are subclassed from WizardComposite. Both WizardLeaf and WizardComposite are subclassed from WizardComponent. Together these objects implement the Composite design pattern. The Composite design pattern facilitates creating complex structures like the client panel tree. Though the tree is composed of nodes and leafs, the Composite design pattern allows all objects comprising the tree to be treated identically. This allows the IteratorLayout object to use the same interface on both leafs and nodes.

The wizard panel tree is created within the builder by specifying the children of the root node. Each panel is instantiated and added to the node through a call to addChild. Nodes can be added in the same way. When the builder writes the wizard archive, the client panel tree is serialized. Each panel has the responsibility of recording all the information necessary for proper initialization into the archive. This is done by overriding the serialize method of WizardComponent. As each panel in the tree is recorded into the archive, the serialize method of that panel is called.

When the wizard is executed, the WizardTreeManager deserializes the client panel tree. As each object in the tree is instantiated, that object has a responsibility to read its initialization data from the archive. This is done through a call to the deserialize method of WizardComponent. The deserialize method must read its information in exactly the same order as it was written in the serialize method. Any discrepancy in the correspondence of serialize and deserialize results in creating a wizard that will not initialize correctly. This problem is reported on the console, and is easy to find and correct.

Each panel and node within the client panel tree can choose not to be shown. This provides different paths through the panels. The skip method of WizardComponent is used to indicate whether the panel or node should be displayed. The skip method in WizardComponent always returns true, indicating that the panel or node should be displayed. Subclasses of WizardComponent often will look at data within the WizardState to determine if the panel should be displayed or not. If a node returns false from the skip method, none of the children of that node are displayed.


Last modified: Fri Nov 25 16:48 PDT