Section 19.4. The Struts Controller


19.4. The Struts Controller

In a moment we will discuss the Struts approach to the MVC controller and then provide detail on the building-block classes, org.apache.struts.action.Action and org.apache.struts.action.ActionForm. But first we should take a step back and look at the nail for which Struts is attempting to be the hammer. In many web applications, the basic HTTP interaction is not especially complicated. An HTTP request includes at least the name of a resource and zero or more parameters. Based on the name of the resource and the parameters, control must be handed off to specialized code that performs an action. The action determines what response is appropriate; this HTTP response is then encoded and returned to the requester, typically with HTML as the message body. So far, so good.

But in ad hoc web programming, it is all too easy to handle each of these tasks in an idiosyncratic way. For example, a developer might write a servlet to handle a request and might create his own methods and conventions for validating parameters (ensuring that certain parameters are syntactically valid phone numbers, perhaps). Meanwhile, another coder, working primarily on GET requests, writes her own method for validating parameters. Clearly, there are organizational and maintenance issues here with the existence of two modules doing similar tasks, maintained by two different people. But the larger issue is that there are well-known patterns for handling such minutiaeand if handled once, and well, those patterns become amenable to all of the good features we associate with object-oriented programming: encapsulation, separation of responsibilities, inheritance where appropriate, and the rest. In fact, validation is small potatoes compared to the main course of organizing the management of actions in a systematic way. When it comes to the more elaborate requirement of making it easy to rearrange the relationships between requests, actions, and responses, we need a framework such as Struts to provide an object representing each piece in request/response processing.

Struts provides an object encapsulating each of the features in our earlier summary of request processing. It's worth noting at this point a significant difference between Struts and JSF. In Struts, the developer is exposed more directly to the underlying request processing, whereas in JSF, much more of the detail of request processing is handled by the framework. This distinction also affects our discussion of these two frameworks. For Struts, you will find that we frequently talk about classes and methods, whereas in JSF, we talk about XML declarations that define the "wiring" of the relationships between beans. Let's look at request processing again, but from the point of view of Struts.

The starting point is the connection between the servlet container and Struts. Struts typically monopolizes all requests in your web application with its own implementation of javax.servlet.Servlet (org.apache.struts.action.ActionServlet). Control is passed to this Servlet by the container. It is this ActionServlet that chooses which class should handle any particular request. The choice is based on settings in an XML file so that you can change the control flow without recompiling.

An Action class handles the request and extends org.apache.struts.action.Action. This Action class has an execute method that you will almost always want to override. It is passed the request and response instances that the ActionServlet receives as well as references to the form that contains the parameter data and a "mapping" that defines the control flow.

An ActionForm represents the parameter data. Once again, you extend a Struts class: org.apache.struts.action.ActionForm.

Now for some more detail on each of these fundamental classes.

19.4.1. The ActionServlet

The fundamental feature of Struts is a servlet, org.apache.struts.action.ActionServlet, which delegates incoming HTTP GET and POST requests to a request processor (org.apache.struts.action.RequestProcessor) and from there to special-purpose handlersinstances of the action classes.

Specify the Struts ActionServlet and a mapping for it in the web.xml file for the application:

   <servlet>     <servlet-name>Struts Action Servlet</servlet-name>     <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>     <init-param>       <param-name>config</param-name>       <param-value>/WEB-INF/struts-config.xml</param-value>     </init-param>     <load-on-startup>1</load-on-startup>   </servlet>     <servlet-mapping>     <servlet-name>Struts Action Servlet</servlet-name>     <url-pattern>*.do</url-pattern>   </servlet-mapping> 

The servlet-name value can be anything you like, although it should be descriptive. You should also specify a parameter named config whose value defines the location of a Struts-specific XML configuration file. The default value for the location of this configuration file is /WEB-INF/struts-config.xml (for more details, see "The Struts Configuration File" later in this chapter). It is conventional to specify this file even when you are using the default location so that it is obvious in your web.xml where the Struts-specific configuration lives. Struts must perform its configuration work before any requests are served, so the <load-on-startup> element is essential to ensure that Struts initializes first (note: if you have a singleton class that should be initialized when Struts starts, see "Struts Plug-ins" later in this chapter). All requests to URL patterns matching *.do will be handled by the Struts ActionServlet. Mapping Struts actions to the .do extension is conventional. Some Struts developers map a path to the Struts ActionServlet, which can be handy if you want to provide J2EE security for the path that is mapped to Struts actions (see Chapter 10) or put a servlet filter in front of your Struts actions (see Chapter 3). Note that if you're using Struts modules, you must use extension mapping.

When ActionServlet is initialized by the servlet container, it performs a number of tasks. It initializes Struts "modules," it sets up Struts-managed DataSources, it initializes Struts plug-ins, and it reads in and processes the Struts configuration file.

Once initialized, the ActionServlet will satisfy requests that are passed to it by the container. When doGet( ) or doPost( ) is called, ActionServlet immediately calls a protected method that then delegates to an instance of a RequestProcessor .

19.4.2. The RequestProcessor

If you've downloaded the source to Struts, open the source for org.apache.struts.action.RequestProcessor and follow along. Understanding how this class uses resources is the key to becoming an adept Struts developer. By the way, here as elsewhere with Struts, the source reveals a number of tidbits that can be quite helpful; as a tiny but useful example, you will see where Struts provides debug messages to the console.

When an HTTP GET or POST request is passed to the process method of RequestProcessor, the following tasks are performed in this order:

  1. If the request is a multipart request, it is handled by a special processor (org.apache.struts.upload.MultipartRequestWrapper). Multipart requests are typically file uploads.[4]

    [4] To learn more about uploading and Struts, see recipe 7.10 in Bill Siggelow's Jakarta Struts Cookbook (O'Reilly).

  2. The path is extracted from the request. This path will be used as the basis for selecting a "mapping" (an instance of ActionMapping) in step 7, which in turn will determine the selection of the ActionForm (step 9) and Action (step 12) for handling the request (step 13). (The relationship between the mapping, the Action, and the ActionForm is defined in the struts-config.xml filesee "The Struts Configuration File" later in this chapter.)

  3. If the controller has been configured to select the locale automatically, the user's locale is set. This locale will be the basis for the choice of a resource bundle with defining properties for that locale. (For more information, see the internationalization section of the current Struts User Guide at http://struts.apache.org or Chapter 12 of O'Reilly's Programming Jakarta Struts.)

  4. The controller sets content and caching headers, if so configured.

  5. The method processPreprocess( ) is called. If you extend the class RequestProcessor and override this method, you may conduct some preprocessingfor instance, you might add special attributes to the request or you might manipulate the session data. (We provide an example of a custom RequestProcessor later.)

  6. Messages that were "cached" for display in the prior request are removedin particular, error messages managed by the org.apache.struts.action.ActionErrors class and the <html:errors> tag are removed.

  7. Based on the path extracted in step 2, the ActionMapping for the current request is looked up.

  8. Roles are checked for the request and mapping; if the user is not allowed to proceed, the processor doesn't continue.

  9. The ActionForm, if any, is determined based on the ActionMapping. If an ActionForm is found, it is prepopulated. If the ActionForm has been configured to require validation, it is validated.

  10. If a forward has been specified for this mapping, the request is forwarded. (For discussion of redirects and forwards, see the sections on "Servlet Responses" and "Request Dispatching" in Chapter 3.)

  11. If an include has been specified for this mapping, the inclusion takes place.

  12. The Action specified for the mapping is looked up or created.

  13. The action is processed, returning an ActionForward that specifies what is to be done next.

  14. The returned ActionForward's path is processed, meaning that either a servlet-style forward is performed via a RequestDispatcher or a redirect response is returned.

The key steps in this process are the ones that select the ActionMapping based on the path, populate and validate the ActionForm, acquire the Action, process the Action, and then return the ActionForward.



Java Enterprise in a Nutshell
Java Enterprise in a Nutshell (In a Nutshell (OReilly))
ISBN: 0596101422
EAN: 2147483647
Year: 2004
Pages: 269

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net