It’s finally time to go over the Action class—the center of all the action! The Action class for the Hello World! application follows in Listing 3.4.
This is the biggest file so far in the application, so let’s take it a step at a time and not go too deep for now.
To begin with, the Action class gets its name from the fact that it is a class that extends the base class:
org.apache.struts.action.Action
Thus, the name Action class.
The primary method that must be written in an Action class is the execute() method. The framework calls this method after the form bean is populated and validated correctly. This is great because the Action class can assume that the form bean has passed it data that’s approved by at least a basic level of validation.
Here’s the signature of the execute() method in any Action class:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
This is the same every Action class. As you can see, the four parameters passed into an Action class are
ActionMapping mapping— The ActionMapping provides access to the information stored in the configuration file (struts-config.xml) entry that configures this Action class.
ActionForm form— This is the form bean. By this time, the form bean has been prepopulated and the validate() method has been called and returned with no errors (assuming that validation is turned on). All the data entered by the user is available through the form bean.
HttpServletRequest request— This is the standard JSP or Servlet request object.
HttpServletResponse response— This is the standard JSP or Servlet response object.
It’s also important to point out that the execute() method in an Action class must return an ActionForward object. ActionForward objects will be discussed in more detail in Chapter 8, “The Controller: Directing the Action,” but for now understand that they represent the View chosen to display the results of the Action.
The Action class uses an execute() method to accomplish its work. It is passed a form bean containing data from the View and an ActionMapping containing configuration information, along with the standard JSP request and response objects.
Now let’s review the first section of code in the execute() method:
// These "messages" come from the ApplicationResources.properties file MessageResources messages = getResources(request);
This section of code loads a copy of the MessageResources that were defined in the Application.properties file that you saw earlier. Now the Action class has full access to all the locale-specific text needed for the application.
The next section of code performs the business logic validation that was discussed earlier:
/* * Validate the request parameters specified by the user * Note: Basic field validation done in HelloForm.java * Business logic validation done in HelloAction.java */ ActionErrors errors = new ActionErrors(); String person = (String) PropertyUtils.getSimpleProperty(form, "person"); String badPerson = "Atilla the Hun"; if (person.equals(badPerson)) { errors.add("person", new ActionError("ch03.hello.dont.talk.to.atilla", badPerson )); saveErrors(request, errors); return (new ActionForward(mapping.getInput())); }
At times there is a need to perform data validation based on more complex logic than is appropriate to put in a form bean. This is a relatively simple example.
In other situations, validation might be based on information retrieved from a Model component. For example, having to type your mother’s maiden name on a “Forgot My Password” form requires that the maiden name be retrieved from a user account Model component.
More on accessing Model components is covered in the following section.
In the next section of code, the Controller component directs interaction with the Model component:
/* * Having received and validated the data submitted * from the View, we now update the model */ HelloModel hm = new HelloModel(); hm.setPerson(person); hm.saveToPersistentStore();
Here the Controller creates a new Model component, sets a value in it, and calls a method to save the data to a persistent store. This is common way that Controller components will interact with a Model.
This is a very simple example. In other situations, a controller component might
Read data back from the model for display by the View
Interact with more than one Model component
Choose the View component (ActionForward) to display based on information retrieved from a Model
The HelloModel.java component itself will be presented later in this chapter. Model components are discussed in more detail in Chapter 9, “Model Components: Modeling the Business.”
The Action class passes information to the View component using standard JSP/Servlet setAttribute() and getAttribute() method calls.
The following is the code fragment from HelloAction.java that passes data to the View:
/* * If there was a choice of View components that depended on the model * (or some other) status, we'd make the decision here as to which * to display. In this case, there is only one View component. * * We pass data to the View components by setting them as attributes * in the page, request, session or servlet context. In this case, the * most appropriate scoping is the "request" context since the data * will not be needed after the View is generated. * * Constants.HELLO_KEY provides a key accessible by both the * Controller component (i.e. this class) and the View component * (i.e. the jsp file we forward to). */ request.setAttribute( Constants.HELLO_KEY, hm); // Remove the Form Bean - don't need to carry values forward request.removeAttribute(mapping.getAttribute());
This code actually accomplishes two things:
Sets the HelloModel instance as an attribute on the request to be passed to the View component.
Removes the form bean from the request object. In this case the form bean is not needed, so it is discarded.
In some situations, the form bean attribute should not be removed. For example, if completing a process in your application requires several data entry pages, you might want to have only a single form bean that, by the end, will hold all the data entered in each of the steps.
The final step in this Controller component is to forward control to the view chosen to display the results of the action:
// Forward control to the specified success URI return (mapping.findForward("SayHello"));
The ActionForward SayHello is defined in the struts-config.xml file.