Take command of your software

The Command pattern benefits both the client and the server

1 2 Page 2
Page 2 of 2

Example 3. test.jsp

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
   <head>
     <title>Struts Actions</title>
   </head>
   <body>
     <a href='simple.do'>
       Click Here to Perform a Simple Action
     </a>
   </body>
</html>

The preceding JSP creates an HTML anchor element that references the /simple.do URL. If you click on that link, the Struts action servlet is invoked because the mapping in the deployment descriptor maps all URLs that end in .do to the action servlet (see Example 2). So what does the action servlet do when it receives the /simple.do URL? The answer resides in the Struts configuration file, which is specified in the deployment descriptor (see Example 2) and listed in Example 4:

Example 4. WEB-INF/action.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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>
   <action-mappings>
      <action path="/simple"
              type="actions.SimpleAction">
         <forward name="fwd-page" path="/forwardPage.jsp"/>
      </action>
   </action-mappings>
</struts-config>

The preceding configuration file maps the /simple URL to the actions.SimpleAction class. When the action servlet receives the /simple.do URL, it strips off the .do suffix and maps the URL to the actions.SimpleAction class. If an instance of that class does not exist, the action servlet creates one and invokes its execute() method. Example 5 lists the actions.SimpleAction class:

Example 5. WEB-INF/classes/actions/SimpleAction.java

package actions;
import javax.servlet.ServletContext;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import beans.CounterBean;
public class SimpleAction extends Action {
     public ActionForward execute(ActionMapping mapping, 
                                ActionForm form,
                                HttpServletRequest request, 
                                HttpServletResponse response)
                  throws java.io.IOException, 
                         javax.servlet.ServletException {
      ActionServlet      servlet = getServlet();
      ServletContext application = servlet.getServletContext();
      CounterBean    counterBean = (CounterBean)application.
                                     getAttribute("counterBean");
      if(counterBean == null) {
         counterBean = new CounterBean();
         application.setAttribute("counterBean", counterBean);
      }
      counterBean.updateCount(request, ".simpleActionCount");
      return mapping.findForward("fwd-page");
   } 
}

The preceding action checks to see if a counter bean exists in the application scope; if not, it creates one and stores it there. Subsequently, the action invokes the counter bean's updateCount() method, which updates a counter stored in a file named .simpleActionCount. Then the action returns an ActionForward instance that points to a JSP mapped to the string fwd-page. That mapping, also defined in the Struts configuration file (see Example 4), resolves the string fwd-page to the forwardPage.jsp JSP. The action servlet subsequently forwards control to that JSP, listed in Example 6:

Example 6. forwardPage.jsp

<%@ taglib uri='/WEB-INF/tlds/struts-bean.tld' prefix='struts'%>
<%@ taglib uri='http://java.sun.com/jstl/core' prefix='c'%>
<%@ page import='beans.CounterBean' %>
This simple action has been accessed 
<c:out value='${counterBean.count}'/> 
<c:choose>
   <c:when test='${counterBean.count == 1}'>
      time.
   </c:when>
   <c:otherwise>
      times.
   </c:otherwise>
</c:choose>
<p><c:import url='test.jsp'/>

The preceding JSP uses the JSTL <c:out>, <c:choose>, <c:when>, and <c:otherwise> actions to display information about how many times the counter bean, and therefore the simple action, has been accessed. JSTL defines an expression language that will be incorporated into the upcoming JSP 2.0. The preceding JSP, for example, uses that expression language to access the counter bean in application scope. (You can download JSTL from Resources.)

Finally, Example 7 lists the counter bean class—beans.CounterBean:

Example 7. WEB-INF/classes/beans/CounterBean.java

package beans;
import java.io.*;
import javax.servlet.http.*;
public class CounterBean {
   private int count = 0;
   private File file = null;
   public synchronized void updateCount(HttpServletRequest request,
                                        String filename) 
                                       throws java.io.IOException {
      checkFile(filename);
      readCount();
      count++;
      saveCount();
   }
   public int getCount() {
      return count;
   }
   private void checkFile(String filename) throws IOException {
      if(file == null) {
         file  = new File(filename);
         count = 0;
      }
      if(!file.exists()) {
         file.createNewFile();
         saveCount();
      }
   }
   private void saveCount() throws java.io.IOException {
      FileWriter writer = new FileWriter(file);
      writer.write(count);
      writer.close();
   }
   private void readCount() throws java.io.IOException {
      FileReader reader = new FileReader(file);
      count = reader.read();
      reader.close();
   }
}

The CounterBean class updates the count associated with a particular action. That class serves as a receiver, as I discussed at this article's beginning, by implementing application-specific behavior.

Your wish is my command

Unless you develop application frameworks, you may never need to implement the Command pattern; nevertheless, you should understand how it works so you can effectively use application frameworks such as Swing and Struts. Now that you've seen how to use the Command pattern in Swing and Struts, you'll be able to better use those and other OO frameworks you encounter in the future.

Homework

For your homework assignment, download Struts, then add your own custom action to the example discussed above. That custom action can implement whatever application-specific behavior you desire.

Homework from last time

In your homework assignment from "Strategy for Success" (JavaWorld, April 2002), I asked you to discuss how Swing uses the Strategy pattern in its list class to render list cells.

As "Strategy for Success" outlined, the Swing JComponent class uses the Strategy pattern to paint borders around components. The JComponent class also uses the Strategy pattern to paint Swing components themselves by delegating that behavior to individual Swing components; for example, the JComponent.paint() method invokes the paintComponent() method, which JComponent subclasses override to paint the component.

Some Swing components, those with more complicated rendering needs, do not paint themselves; instead, they use the Strategy pattern to delegate that behavior to another object. For example, Swing lists delegate the painting of their list cells to an object that implements the ListCellRenderer interface. That interface defines a single method—getListCellRendererComponent()—that returns a component that paints the list's cells. That Strategy pattern usage lets developers modify how lists paint their cells by implementing a list cell renderer and attaching it to a specific list.

David Geary is the author of Core JSTL Mastering the JSP Standard Tag Library, which will be published this fall by Prentice-Hall and Sun Microsystems Press; Advanced JavaServer Pages (Prentice Hall, 2001; ISBN: 0130307041); and the Graphic Java series (Sun Microsystems Press). David has been developing object-oriented software with numerous object-oriented languages for 18 years. Since the GOF Design Patterns book was published in 1994, David has been an active proponent of design patterns, and has used and implemented design patterns in Smalltalk, C++, and Java. In 1997, David began working full-time as an author and occasional speaker and consultant. David is a member of the expert groups defining the JSP standard custom tag library and JavaServer Faces, and is a contributor to the Apache Struts JSP framework.

Learn more about this topic

1 2 Page 2
Page 2 of 2