Comments
Richard Davies wrote: The UK has a good crop of technology pioneers in cloud computing - for example ElasticHosts, FlexiScale, Flexiant, OnApp - and also some strong government initiatives such as G-Cloud. We will have to see whether this kind of technical leadership converts into swift mass-market adoption or not.
Cloud Expo on Google News


2008 West
DIAMOND SPONSOR:
Data Direct
SOA, WOA and Cloud Computing: The New Frontier for Data Services
PLATINUM SPONSORS:
Red Hat
The Opening of Virtualization
GOLD SPONSORS:
Appsense
User Environment Management – The Third Layer of the Desktop
Cordys
Cloud Computing for Business Agility
EMC
CMIS: A Multi-Vendor Proposal for a Service-Based Content Management Interoperability Standard
Freedom OSS
Practical SOA” Max Yankelevich
Intel
Architecting an Enterprise Service Router (ESR) – A Cost-Effective Way to Scale SOA Across the Enterprise
Sensedia
Return on Assests: Bringing Visibility to your SOA Strategy
Symantec
Managing Hybrid Endpoint Environments
VMWare
Game-Changing Technology for Enterprise Clouds and Applications
Click For 2008 West
Event Webcasts

2008 West
PLATINUM SPONSORS:
Appcelerator
Get ‘Rich’ Quick: Rapid Prototyping for RIA with ZERO Server Code
Keynote Systems
Designing for and Managing Performance in the New Frontier of Rich Internet Applications
GOLD SPONSORS:
ICEsoft
How Can AJAX Improve Homeland Security?
Isomorphic
Beyond Widgets: What a RIA Platform Should Offer
Oracle
REAs: Rich Enterprise Applications
Click For 2008 Event Webcasts
SYS-CON.TV
Top Links You Must Click On


Java Wizard Class
Java Wizard Class

As it turns out, designing and implementing this wizard framework exposes many of the real-world design and programming issues we face when creating Java applications.

Overview
The first step in designing our wizard class is to come up with an interface. An interface is a prototype for a class in which we describe the class' functionality without getting into implementation details. When designing an interface, think about how someone would use the class and jot down some pseudo-code. Translate these ideas into member functions to create the interface. One thing to remember is that the initial pass at an interface will rarely be the last. You will probably end up modifying and improving the interface several times during the course of development.

Since there are several different ways we could go about designing our wizard interface and corresponding implementation class, we need to decide what features are important to us. For instance, what types of containers do we want our wizard to be capable of displaying? What events do we want our wizard to support? Do we want to support multicasting of events, and, if so, how? Do we want to have random access to our wizard pages or is sequential access sufficient? What do we want our wizard buttons to look like?

There are three main elements to a wizard.

  • First, there are the navigation buttons (next, previous, cancel, etc.).
  • Second, there are the information and controls presented by the wizard, which I refer to as "pages."
  • Finally, there is the dialog, typically modal, that contains the active page and the navigation buttons.

    The Layout
    We now need to think about how the wizard dialog should be laid out. Because the wizard navigation buttons are independent of the content pages, we want to create two distinct areas within the dialog. The first area, which will occupy the upper region of the dialog, will consist of the information that changes between each wizard page. The second area, which will occupy the lower region of the dialog, will contain the wizard navigation buttons. This is where Java's layout manager classes will come in handy.

    Messaging
    The next issue we need to deal with is messaging. We need to provide a mechanism in our wizard class to notify the outside world of events. To do this we will need to create our own event and listener classes so that the appropriate event occurs when one of our navigation buttons is clicked.

    If you are experienced in using the AWT, you are probably familiar with event listeners and event adapters. For instance, Java provides a class called WindowAdapter to accept events that occur on a window. The class is provided mainly for convenience reasons, providing empty methods for all the various window events. To actually do something, you must extend the WindowAdapter class and tell the window about it by calling the AddWindowListener function.

    We are going to use a similar structure in our wizard framework. Our wizard class will allow a user to set a particular WizardAdapter to have the wizard messages sent to. We are going to design our wizard so that there can be only one WizardAdapter active at any given time. Note, however, that this does not prevent us from multicasting the events, if desired, since you can add that functionality to the WizardAdapter class. Why not allow multiple listeners to be registered with the wizard class as they can in Java's Window class? Consider the events that our wizard class is producing. In response to these events (next, previous, finish, etc.) we might validate some of the fields in the current page, then tell the wizard class to display the next page or the previous page, or to close the dialog. Can you see some of the potential problems if these events were to be processed by independent listeners? What if the first listener told the wizard to advance to the next page, while the next listener, not knowing about the first, did the same thing? In this case you would get the unintended result of advancing two pages whenever the next button was clicked.

    By limiting the wizard class to one WizardAdapter, we require a central point of control by the user of the wizard class. This is important because it is the user of the class, not the wizard class itself, that knows how the wizard should be used. If users want events to be multicast, they can implement that multicasting inside their WizardAdapter, simply forwarding on the wizard events to all interested parties. The lesson here is to provide functionality appropriate for the object being modeled. Don't add capabilities just because you think they're cool.

    Example Classes
    To show how you use the wizard class, I created a sample vacation wizard. This wizard is relatively simple, yet illustrates most of the features of the wizard class, as well as some interesting "gotchas."To effectively use the wizard class, several application-specific support classes are created, as shown in Figure 1. An application-specific version of the WizardAdapter class (VacationWizardAdapter) is created to handle messaging, while a class called VacationWizard is used to create the wizard content pages and control the interactions between wizard pages. The VacationWizard class knows about both the wizard class and the VacationWizardAdapter class. The VacationWizardAdapter takes a VacationWizard instance in its constructor so that it knows whom to send messages to. The three classes used together provide a flexible and extensible mechanism for handling wizards.

    The Details
    Let us begin by taking a closer look at the interface definition for the wizard class (see Listing 1). From this interface definition we can see that in addition to the basic wizard navigation support, we also want our wizard to be able to support advanced features such as hidden panels, keyboard navigation, help button and messaging.

    In implementing our wizard class, one of the first issues we must confront is what existing Java class we want to extend. As I mentioned in the overview, a modal dialog is typically used as the container for the various wizard elements. To get some exposure to some of the new JFC classes, we will extend the JFC class Jdialog.

    public class Wizard extends com.sun.java.swing.JDialog implements WizardControllerInterface

    Notice that this declaration says we are going to implement the WizardInterface that we listed earlier. Therefore, our class definition must define all the member functions we defined in our WizardInterface.

    The Layout
    As I alluded earlier, Java's layout classes come in handy when implementing our Wizard class. Using a GridBagLayout, we can lay out the wizard dialog's contents as shown in Figure 2. The uppermost area is itself a Jpanel that uses its own layout manager, CardLayout, to manage the wizard pages. I won't go into the details of laying out controls using the GridBagLayout here, but look at the source code if you are interested.

    Messaging
    How do we go about handling the messaging? First, we need to create a new event type called a WizardEvent by extending Java's EventObject class (see Listing 2). We will then need to create a WizardListener class by extending the Java's EventListener class. Our WizardListener class will handle the events shown in Listing 3.

    Inside our wizard class we need to create ActionListeners for each of our wizard navigation buttons, such as:

    previous_.addActionListener(new PreviousButtonListener());

    Our listener classes simply fire off an appropriate event when one of our navigation buttons is clicked. Listing 4 shows how one of these functions, PreviousButtonListener, is implemented.

    In addition, we need to add KeyListeners for each of our wizard navigation buttons since we want to support keyboard control of our navigation buttons using the Enter Key.

    next_.addKeyListener(new NextEnterKeyListener());

    All we are doing here is checking to see if the Enter Key is pressed while the focus is on one of our navigation buttons. If it is, we fire off the appropriate event. Listing 5 shows how the NextEnterKeyListener is implemented.

    Page Navigation
    How do we accomplish the task of moving between pages in the wizard class? As mentioned earlier, the Java Layout Manager called CardLayout is used to switch between wizard pages. The CardLayout is ideal for use with wizards because it allows easy access to all the pages in the layout either sequentially or randomly via a name. (See the complete listing for details.)

    The wizard class offers the ability to hide certain pages of the wizard if desired. As we will see in our example, many times we might want to create a wizard that shows certain pages conditionally. This is accomplished by using the wizard functions hidePanel and unHidePanel. PanelAttribute class is used inside the wizard class to maintain state about each page of the wizard. If a page is marked as hidden, that page is bypassed by the forward and next logic of the wizard. (See the complete listing for details.)

    Miscellaneous
    Our wizard class also has the ability to display messages. The user of the wizard class might want to display a message stating that all the required fields of the wizard have not been filled in. A user might also want to display a specific field validation message, such as "value must be between 10 and 50." The wizard class handles these situations using a specific function called displayRequiredFieldMessage, as well as provides a generic error message function called displayErrorMessage that takes a title and a message string.

    An Example
    To create an actual wizard of your own, you need to decide on the content and order of the wizard pages. Once you have figured that out, you need to decide what container you will use for the wizard pages. Our wizard class allows you to use any class derived from the AWT's Component class. For the sample wizard I used a variety of components such as the AWT's Panel and ScrollPanel class, as well as the new JFC's Jpanel class.

    Once you have your wizard pages designed, you need to deal with any required interactions between the various controls on the same page as well as the interactions between pages. For instance, in the VacationWizard example, the second page of the wizard is displayed only if Hawaii has been selected as the destination. Therefore, we need to be able to conditionally hide/unhide this wizard page based on the value of the radio buttons on the first wizard page.

    To check the values of various controls at the appropriate time, messages need to be sent when a wizard page is activated and deactivated. This is the job of our VacationWizardAdapter. Since the VacationWizardAdapter is the class that is getting the messages (previous, next, finish, etc.) from the Wizard Class, it is responsible for calling the initializePage and finalizePage functions of the VacationWizard class, passing the current wizard page as a parameter. The finalizePage function can veto moving to the next page by returning false. This is a handy mechanism for validating fields and preventing the wizard from moving forward until all the appropriate fields and values are filled in.The code in the VacationWizard class deals mostly with creating the content pages for the wizard. However, there is one interesting thing to look at. While creating and testing the wizard pages, I discovered some undesired behavior with the AWT's TextArea class. I wanted to use a non-editable TextArea to display some explanatory text at the top of each wizard page (see Figure 3). At first glance everything looked okay. However, when I used the tab key to tab around the dialog, I noticed that once the TextArea received the focus, it did not want to give it back. Although I'm sure the TextArea was happy, the rest of my controls were feeling left out.

    I imagine this behavior stems from the fact that in a standard editable text area, the tab key really means to put in a tab character. Fortunately, you can get around this problem by deriving a new class from TextArea. I called my new class UnfocusedTextArea (see Listing 6). After searching the documentation, I found a handy function in the AWT's Component class, from which TextArea descends, called isFocusTraversable. The key to solving the problem lies in overriding this function in our UnfocusedTextArea class so that it simply returns false. This means that the text area will never actually get the focus -- which is exactly what we want to happen in this case.

    Conclusion
    There are many different ways to design a wizard class and its supporting classes. I have presented one way that provides a flexible and extensible framework for creating real-world wizards. One thing to keep in mind when building applications of your own is that most real-world problems require more than one class to model. In most cases it is best to solve problems with mini-frameworks that use a general-purpose class or classes (like the Wizard class) combined with one or more specializing classes (like the VacationWizard and VacationWizardAdapter classes).

    About Donald Fowler
    Donald Fowler works as a software design
    developer at Rogue Wave Software where he is currently the technical lead for the Software Parts Manager product line. He has 15 years of software design and development experience specializing
    in GUI programming and 7 years' experience in object-oriented design and programming.

  • In order to post a comment you need to be registered and logged in.

    Register | Sign-in

    Reader Feedback: Page 1 of 1

    These Wizard classes are just what I am looking for. I wish that the VacationWizard example classes were included in the source listings.

    Thanks


    Your Feedback
    Milt Demaray wrote: These Wizard classes are just what I am looking for. I wish that the VacationWizard example classes were included in the source listings. Thanks
    Enterprise Open Source Magazine Latest Stories . . .
    With Cloud Expo 2012 New York (10th Cloud Expo) just four months away, what better time to start introducing you in greater detail to the distinguished individuals in our incredible Speaker Faculty for the technical and strategy sessions at the conference... We have technical and st...
    AMD said late Tuesday that its chief sales officer Emilio Ghilardi had left the company and that CEO and president Rory Read is going to do his job while a replacement is sought. AMD didn’t say why Ghilardi left but it’s assumed Read wants his own people. Read is relatively new to th...
    During the lifespan of M3 (Monitis Monitor Manager) there has always been something lacking – timers. M3 execution procedure was outlined in this previous article. The execution mentioned in the latter was a one-time-execution, whereas server monitoring requires periodic invocati...
    Red Hat is putting its bought-in Gluster scale-out NAS storage technology, acquired in October, on the Amazon cloud. It’s styled Red Hat Virtual Storage Appliance for Amazon Web Services and other clouds are supposed to follow in short order.
    A new episode of the screencast series is now available at the OpenNebula YouTube Channel. This screencast demonstrates the new easily-customizable self-service portal for cloud consumers. Its aim is to offer a simplified access to shared infrastructure for non-IT end users. The scree...
    C12G Labs has just announced an update release of OpenNebulaPro, the enterprise edition of the OpenNebula Toolkit. OpenNebula 3.2, released two weeks ago, brings important benefits to cloud providers with a new easily-customizable self-service portal for cloud consumers, and builders w...
    Subscribe to the World's Most Powerful Newsletters
    Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
    Click to Add our RSS Feeds to the Service of Your Choice:
    Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
    myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
    Publish Your Article! Please send it to editorial(at)sys-con.com!

    Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


    SYS-CON Featured Whitepapers
    ADS BY GOOGLE