Jump the hurdles of Struts development

Tips for solving common difficulties in Struts

Unless you have been living under a rock or in a cave for the past few years, you have most likely heard of the Struts framework. Struts is the open source initiative sponsored by the Apache Software Foundation and was created to encourage the Model-View-Controller (MVC) design paradigm within a Web application's presentation layer. Struts implements the MVC pattern using the Service to Worker pattern. A well-designed architecture strives to be loosely coupled and highly cohesive. Struts provides the mechanism to achieve this design goal in the presentation layer of multitiered, enterprise Web applications.

One of the most daunting tasks facing enterprise application architects is the presentation layer's creation and maintenance. Users expect highly functional, robust, and elegant graphical user interfaces. Thus, the presentation layer's codebase winds up greatly outnumbering that of the application layer. In addition, the advent of different display platforms such as wireless phones and PDAs has made an already complex situation much more complex.

Various books and articles already cover Struts's inner workings and teach how to use the framework. This article elaborates on the issues facing Web application developers who use Struts and how to resolve them. Many of the following approaches can be abstracted and applied to different MVC frameworks such as the upcoming JavaServer Faces specification. Craig R. McClanahan, one of the original creators of Struts, leads that specification.

This discussion's topics cover those areas that present the most hurdles while building a J2EE (Java 2 Platform, Enterprise Edition) application using Struts with BEA WebLogic Server. We cover the following specific issues:

  • Creating/maintaining struts-config.xml
  • Form/session management
  • Relationships of Struts mappings and the user interface
  • Managing the Back button
  • User authentication
  • User interface control flow
  • Exception handling
  • Testing

Take two and call us in the morning

The Struts framework unarguably eases the development and maintenance of user interfaces for enterprise applications. However, after working with Struts on even a simple application, one quickly realizes the nightmare that is struts-config.xml. That file can quickly become unwieldy at best. When building an enterprise application, struts-config.xml can grow in excess of 500 action mappings, making it virtually unmanageable.

We recommend two tools to help manage this headache. First, document your user interface flow using Microsoft Visio and StrutsGUI from Alien-Factory. StrutsGUI is a Visio stencil that helps depict user interface flow diagrams using Struts nomenclature. There is a hidden gem within the Struts stencil item: by right-clicking this option, selecting Edit Title Properties, and then selecting the Tools option, you can generate a struts-config.xml file based on this diagram. For example, the simple application shown in Figure 1 generates the following struts-config.xml shown in the code below:

Figure 1. StrutsGUI model. Click on thumbnail to view full-size image.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!-- Struts Config XML - Sample Struts App -->
<!-- ===================================== -->
<!-- AutoGenerated from : c:\dev\javaworld\app\sample.vsd -->
<!-- AutoGenerated on   : 02-18-2003 23:05:47 -->
<!-- AutoGenerated by   : Struts GUI v2.11   (c)2002 Alien-Factory -->
<!--                    : See 'http://www.alien-factory.co.uk' for details -->
<!-- GET YOUR STICKY FINGERS OFF! i.e. Do not edit. -->
<!DOCTYPE struts-config PUBLIC
      "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
      "http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd">
<struts-config>
  <!-- ====================== Form Bean Definitions =================== -->
  <form-beans>
  </form-beans>
  <!-- ================= Global Forward Definitions =================== -->
  <global-forwards>
  </global-forwards>
  <!-- ======================= Action Definitions ===================== -->
  <action-mappings>
    <action  path="/Login"
             type="com.agilquest.onboard.presentation.actions.LoginAction">
      <description>Authenticates and authorizes a user.</description>
    </action>
  </action-mappings>
  
</struts-config>

To make your user interface flow diagrams more complete, we recommend an additional step when using StrutsGUI. Within your StrutsGUI Visio document, you can easily link each JSP (JavaServer Pages) page to its actual screen shot in the application. Not only does creating this artifact aid in documenting the application, but more importantly, it becomes an excellent tool for training new developers about the user interface design.

Another tool that helps manage Struts applications is the Struts Console created by James Holmes. In essence, it provides facilities that enable you to get to the same endpoint as StrutsGUI, but differs in approach and strengths. Both tools perform well, and either will enhance a Struts-based enterprise application's maintenance.

Now, where did I put that form?

ActionForm session management can be tricky. What should the ActionForm's life be? Should it be in request scope or session scope? One solution to this problem puts the ActionForm in session for the life of the functionality it is supposed to represent.

In such a case, how do you maintain these ActionForm objects generically? Who assumes the responsibility of cleaning up these ActionForm objects once they are no longer needed? A typical scenario is when a user traverses from one functionality to another through a menu. In that case, the old ActionForm objects should be removed from the session and new ActionForm objects created. A centralized Action class, called MenuAction, which deals only with the menu traversal, should be present. This Action class deletes the redundant ActionForm objects from the session. It then forwards the user to the new page where new ActionForm objects are created.

Given this, how do we show the different menu items to the user based on her role or permissions? This menu should also be internationalized, and it can change based on the user permissions; that is, if the permissions change, the menu must change accordingly. One such approach persists the user's permissions. When she logs in, a MenuFactory creates menus from these permissions. For additional safety, the MenuAction class can then authorize the user before permitting her to proceed to the selected functionality.

A rule of thumb in naming the ActionForm objects in struts-config.xml is to end the object name with Form, thereby simplifying the maintenance of these forms in session. For example: ReservationForm, SearchUserForm, BankAccountForm, UserProfileForm, and so on.

The code below further clarifies ActionForm(s) management by illustrating a generic menu traversal action with the Action mappings:

 public class MenuAction {
  public ActionForward perform(ActionMapping       _mapping,
                               ActionForm          _form,
                               HttpServletRequest  _request,
                               HttpServletResponse _response)
                                  throws IOException, ServletException {
    // Check end-user permissions whether allowed into the requested     
    // functionality 
    checkIfUserAllowedToProceed(_mapping, _form, _request, _response); 
    // Clean up the session object (this logic is in its own method)
    String formName = null; 
    HttpSession session = _request.getSession();
    Enumeration e = session.getAttributeNames();  
 
    while(e.hasMoreElements()) {
     
      formName = (String)e.nextElement();
      if (formName.endsWith("Form")){
        session.removeAttribute(formName);
      }    
    }
    // Now find out which functionality the end-user wants to go to
    String forwardStr = _request.getParameter("nextFunctionality");
    if (forwardStr != null && forwardStr.trim().length() > 0){
      return _mapping.findForward(forwardStr);
    }
    else {
      return _mapping.findForward("index");
    }
  }  
}

The following Action mapping is an example of how to implement an action based on a menu selection:

<!-- A generic menu action that forwards the user from one 
     functionality to another functionality (after checking permissions)
-->
<action path="/menuAction"
        type="x.y.z.MenuAction"
        input="/menu.jsp">      
  <forward name="create_reservation" path="/actionResv.do"/> 
  <forward name="index"              path="/menu.jsp"/> 
  <forward name="add_person"         path="/actionPerson.do"/> 
  <forward name="logout"             path="/actionLogout.do"/> 
</action>

The example and the mapping are self-explanatory.

Tell me again, how are we related?

Any JSP can have one to many entry points and one to many exit points, depending on the complexity of the page itself. Recognizing these relationships is paramount to understanding and maintaining the complexity of the user interface. We have defined the relationships between a JSP page and an Action class as:

  • 1:1 relationship
  • 1:N relationship
  • N:N relationship

1:1 relationship

In a 1:1 relationship, a user goes from one JSP page to another through an Action class; this facilitates tight coupling between a JSP page and an Action. The only extra overhead is one Action mapping in struts-config.xml. This single Action with only one Action mapping in struts-config.xml can be used to go from one page to another.

Referencing one JSP page directly through another is poor practice; the user's permissions that go to the target JSP page cannot be checked (if applicable). This also leads to maintenance issues. To avoid these issues, always go from one JSP page to another through an Action class:

<!-- A generic action that forwards request from one JSP page to another JSP page -->
<action path="/forwardAction"
        type="x.y.z.One2OneAction"
        input="/test1.jsp">      
  <forward name="continue"  path="/test2.jsp"/> 
</action>

1:N relationship

A slightly more complex relationship is one where a JSP page has multiple exit points but a single point of entry, referred to as a 1:N relationship. In this case, always use a single Action class to branch to different targets. That will ensure that Action can check for different situations or permissions before forwarding the user to the target.

The only extra overhead is one Action mapping in struts-config.xml. This will also facilitate a 1:1 mapping between a JSP page and an Action mapping.

The Action mapping below notes a mapping that has a single point of entry yet multiple forwards, signifying many exit points:

<!-- A generic action that forwards request from one JSP page to different 
     branches depending on the selected hyperlink, by the end-user
-->
<action path="/branchAction"
         type="x.y.z.One2NAction"
         input="/test1.jsp">      
  <forward name="target1"   path="/test2.jps"/> 
  <forward name="target2"   path="/test3.jsp"/> 
  <forward name="target3"   path="/someAction.do"/> 
</action>

N:N relationship

The most complex piece of relationship, commonly referred to as an N:N relationship, is when a JSP page or an Action class has multiple entry points and multiple exit points. The N:N relationship is an interesting and complex piece that occurs frequently in enterprise applications. The N:N relationship is primarily used when different JSP pages access a common JSP page or a common Action class. Suppose the user has come to a JSP page that is a hub (i.e., the JSP page can be reached from different JSP pages) and somehow wants to go back or cancel the flow; the developer faces the dilemma of how to send the user to the correct page.

Another scenario is an Action class that commits to the database (through different functionalities or JSP pages), and an error occurs. Sending the user back to where he originated or to forward appropriately, based on where the user came from, requires careful thought. The struts-config.xml mapping will not prove helpful since the input field is a fixed JSP page or Action class. A flexible architecture should be created wherein a developer can change the flow logic easily without mucking around in the struts-config.xml. This is where the N:N relationship kicks in. By implementing an interface with the flexibility to send the user either to the target or the destination, the values can change easily.

The Action mapping below notes a mapping that has multiple points of entry and multiple forwards, signifying many exit points:

1 2 3 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more