HMVC: The layered pattern for developing strong client tiers

This hierarchical model eases the development of a Java-based client tier

Page 2 of 2

The model encapsulates key server-interaction functionality to retrieve data. To accomplish this task, key issues -- SQL requests, data element-mapping between GUI and databases, transport data formats, etc. -- need to be redressed. Design issues, like data-persistence mechanisms in the model need to be ironed out. However, in most thin-client architectures, the role of the model tends to be that of a data conduit that hides the complexity of data fetching and decouples the rest of the client tier from server-side data formats.

Let's go for a spin

A simple example will help you grasp key concepts.

Figure 4. HMVC client tier instance diagram

Figure 4 illustrates an instance diagram of a client tier, with some of its key components and layers. As explained earlier, the hierarchy of MVC triads for GUIContainers, GUIFrames, and GUIPanes are apparent in this diagram. The model classes in each MVC layer encapsulate the details of the data formats and are responsible for interacting with the ServerFacade to satisfy data requests. The server-side and transport-specific format is mapped to this data format, thereby decoupling the application data formats from its GUI representation.

The Hello World application

In our sample application, we will try to see how the HMVC makes sense in crafting a robust client tier. Our application consists of a GUIContainer, the highest MVC triad, consisting of GUIContainerController, GUIContainerModel, and GUIContainer. The GUIContainer is a nonvisual view; it simply provides services to the contained GUIPanes. In terms of importance within the triad, the controller is assumed to be at a higher level of responsibility than the model and view. It is their gatekeeper; the controller has references to the model and view. GUIFrameController, GUIFrame, and GUIFrameModel compose the second rung. A collection of GUIPanes (see Figure 2), namely MenuGUIPane, StatusGUIPane, NavGUIPane, and ContentGUIPane, make up the GUIFrame. Since the GUIPanes are fairly trivial (ContentGUIPane excepted), they don't have their own controller. Instead, the GUIFrameController controls them. Your needs may be different, however, and each GUIPane could have its own triad if necessary.

We must distinguish between an HMVC controller and a Swing listener. In order to isolate Swing code, each GUIPane by itself deals with Swing events. For example, look at the class definition of the MenuGUIPane:

public class MenuGUIPane extends javax.swing.JMenuBar implements ActionListener
Figure 5. Sample application screenshot

Thus, the MenuGUIPane listens for the ActionEvent generated when a user clicks the File, Hello World menu item (Figure 5). The MenuGUIPane then determines what service it wants from its controller, the GUIFrameController. In our particular example, the ActionEvent replaces the ContentGUIPane, so a navigation service is expected. The code snippet below illustrates the creation of the navigation AppEvent object and its transmission to the GUIFrameController (ctlr_).

public class MenuGUIPane ...
{
   ...
   public void actionPerformed(ActionEvent actionEvent)
   {
      if(actionEvent.getActionCommand().equals("HELLO"))
      {
         ...
         AppEvent ae = new AppEvent(AppEvent.NAV_EVENT);
         ae.setMessage("SHOW_HELLO_WORLD");
         ctlr_.handleAppEvent(ae);
      }
      else
      if(actionEvent.getActionCommand().equals("CLOSE"))
         System.exit(0);    
  }
  ...
}

Upon receiving the AppEvent, GUIFrameController knows what to do in the case of a navigation event. (Our example is fairly trivial, meant to show key behavior and components. In an actual application, more would need to be done!) It creates a new child MVC triad composed of the ContentGUIController, ContentGUIPane, and the ContentGUIPaneModel, and establishes the parent-child hierarchy structure.

public class GUIFrameController ...
{
   ...
   public void handleAppEvent(AppEvent ae)
   {
      if(ae.getMessage().equals("SHOW_HELLO_WORLD"))
      {
         createChildTriad();
         childCtlr_.init();
      }
   }
 
   ...
   public void createChildTriad()
   {
      ContentGUIPane contentPane = new ContentGUIPane(new Dimension(20,20));  
      ContentGUIPaneModel contentModel = new ContentGUIPaneModel();
      ContentGUIPaneController contentController = new ContentGUIPaneController();
        
      contentController.setView(contentPane);
      contentController.setModel(contentModel);
        
      contentController.setParentController(this);
      setChildController(contentController);
      view_.setPane(contentPane);
   }
}
Figure 6. Sample application screenshot

Figure 6 shows the resulting GUIFrame. In order to further illustrate some key concepts behind the responsibility-based controller hierarchy and MVC interaction, let us take a look at intralayer communication like retrieving data -- data-event handling, in other words.

Figure 7. Sample application screenshot

Upon clicking the Click button, the text "Hello World!" appears in the TextField, as in Figure 7. The mechanism for achieving this is similar to what transpired in the MenuGUIPane actionPerformed() method. However, this time, instead of a navigation service, the ContentGUIPane controller requests a data service.

public class ContentGUIPane ...
{
   ...
   public void actionPerformed(ActionEvent ae)
   {
      if(ae.getActionCommand().equals("CLICK"))
      {
         ...
         AppEvent ape = new AppEvent(AppEvent.DATA_EVENT);
         ape.setMessage("HELLO_WORLD");
         ctlr_.handleAppEvent(ape);
      }
      ...
   }
   ...
}

The ContentGUIPaneController simply delegates a data-service event to its associated model object; status-event or navigation-event service would be passed on to its parent controller, the GUIFrameController. This establishes a clear chain of responsibility for the controllers. They deal only with events that are within their scope and defer other events to their parents.

public class ContentGUIPaneController...
{
   ...
   public void handleAppEvent(AppEvent evt)
   {
      if(evt.isDataEvent())
         contentModel_.handleAppEvent(evt);
      else
      if(evt.isStatusEvent() || evt.isNavEvent())
         parentCtlr_.handleAppEvent(evt);
   }
   ...
}

Upon receiving the data-service event, the ContentGUIPaneModel would engage the ServerFacade to retrieve data and subsequently request the associated view to refresh itself. (The ServerFacade is not implemented in the example as it is out of this article's scope.)

public class ContentGUIPaneModel ...
{
   ...
   public void handleAppEvent(Sample.controller.AppEvent ae)
   {
      String[] stra = new String[1];
      // stra = ServerFacade.getData(xyz...);
      stra[0] = "Hello World!";
      contentPane_.refreshView(stra);
   }
   ...
}

The associated view, the

ContentGUIPane

, then displays the data in the appropriate widget.

public class ContentGUIPane ...
{
   ...
   public void refreshView(String[] data)
   {
      txtMsg_.setText(data[0]);   
      validate();
   }
   ...
}

Conclusion and further work

The example presented here skips issues like data management, data formats, advanced controller, and view management. Our objective here has been to present a scalable and robust design pattern that you can use to create a client tier in Java.

The ability to handle multiple GUIFrames and Content GUIPanes would also need to be included in any eventual solution. A composite pattern that models server-side data can handle the missing data format part. Issues like data persistence and SQL query generation, along with database and UI data maps, will need to be redressed.

Currently, we are working on putting together a client-tier framework in Java that leverages the HMVC pattern and hopefully assists the client-tier architect in using an out-of-the-box solution that significantly reduces development time and risk.

Jason Cai is a consultant with RDA, and has over 10 years of software-development experience. He is a Sun-certified Java 2 architect, developer, and programmer; he also is an MCSD and MCSE, and has an MS in electronic engineering and statistics. Ranjit Kapila is a consultant with RDA. He has BS and MS degrees in computer science, with over seven years of software development experience. He is a Sun-certified Java 2 programmer in addition to having extensive object-oriented experience in C++. Gaurav Pal is a consultant with RDA. He has a BS in computer science with six years of software-development experience, including over three years in Java. He is a Sun-certified Java 1.1 and 2 programmer and has written extensively for publications like IEEE Potentials and Computer Communications UK.

Learn more about this topic

| 1 2 Page 2