This article explores the Struts framework in depth and highlights the benefits Struts can bring to your development efforts. We believe that once you can “talk the talk” of web architecture and design, you will be better equipped to use Struts with your own applications.
With a sound overview of the Struts architecture in place, we outline the Struts control flow and the way it handles the request-response event cycle. A good understanding of this process makes it much easier to create applications that make the best use of the framework.
Choosing a web application framework should not be a casual decision. Many people will use this book, and especially this chapter, as part of evaluating Struts for their project. Accordingly, we conclude this chapter with a candid look at the strengths and weaknesses of the Struts framework and address concerns regarding overall performance. Struts is designed for professional developers. To make informed decisions, professionals need to be aware of both a tool’s capabilities and its limitations.
A Greatt Desiign Pattttern – MVC
Part of MVC triad
A Model in MVC terms is a presentation-neutral arbiter of data. This data then can be tailored to support a given presentation, or tailored to represent application-specific data structures.
A View is a presentation-specific way of displaying data from a Model. There is a relationship between a Model and View such that changes in a Model are automatically reflected in any Views attached to it, and changes in the View-presented data are automatically pushed back to associated Models.
The controller coordinates activity Model and View, and for the application as a whole. Whereas Model and View can frequently be instances of off-the-shelf types, Controllers are typically custom written to an application.
Types of MVC
MVC1 (Page-centric Architecture): There is no clear distinction between view and a controller. In Java terms, there is JSP page (view and partial controller) which itself controls Business logic (Model) that is why it is also called as page-centric architecture. Fig 2 below shows MVC1 implementation.
MVC2 (Servlet-centric architecture): MVC2 incorporates a clear separation of view and controller. A controller receives all the requests, retrieves data from a Model and forwards it to next view for presentation.
In Java terms, there is a central Servlet (Controller) which calls business logic (Model) and the forwards it particular JSP page (View) that is why it is also called servlet-centric architecture. Diagram below depicts MVC2 implementation.
Struts – An implementatiion of MVC2
As discussed in the previous section about MVC2, there is central controller associated with all views and models. Similarly, Struts has central controller called as ActionServlet, which receives requests from all the JSP Pages (View) and forwards them to appropriate Model called as Action and vice versa. To put it in Struts framework terms, org.apache.struts.action.ActionServlet is the backbone of all Struts applications. It is the main Controller that handles client request and determines which org.apache.struts.action.Action to call to process each received
request. This logic of associating a client request to particular Action, an ActionServlet takes from a configuration file called strus-config.xml.
Fig 3 below shows how Struts framework is the prefect implementation of MVC2.
Today’s web applications are critical components of the corporate mission. As always, development teams need to build applications in record time, but they have to build them right and build them to last.
Java web developers already have utilities for building presentation pages, such as JavaServer Pages and Velocity templates. We also have mechanisms for handling databases—JDBC and Enterprise JavaBeans (EJBs), for example. But what do we use to put these components together? We have the plumbing and the drywall … what else do we need?
One step back, three steps forward
In the late 1970s, when graphical user interfaces (GUIs) were being invented, software architects saw applications as having three major parts: the part that manages data, the part that creates screens and reports, and the part that handles interactions between the user and the other subsystems [Ooram]. In the early 1980s, the ObjectWorks/Smalltalk programming environment introduced this triumvirate as a development framework. In Smalltalk 80 parlance, the data system is dubbed the Model, the presentation system is called the View, and the interaction system is the Controller. Many modern development environments, including Java’s Swing, use this Model/View/Controller (MVC) architecture as the foundation of their own frameworks.
Java web developers already have capable tools, such as JDBC and JSP, for consulting the Model and creating the View, but where’s the Controller for our web applications?
The centerpiece of Struts is an MVC-style Controller. The Struts Controller bridges the gap between Model and View. The framework also includes other missing pieces developers need to write scalable, leading-edge web applications. Struts is a collection of “invisible underpinnings” that help developers turn raw materials like databases and web pages into a coherent application.
A Big Picture
Figure lays out the Struts request-response process in a visual sequence. Let us walk through a description of the request-response. The numbers in parentheses refer to figure 5 where appropriate:
- A client requests a path that matches the Action URI pattern (1).
- The container passes the request to the ActionServlet.
- If this is a modular application, the ActionServlet selects the appropriate module.
- The ActionServlet looks up the mapping for the path.
- If the mapping specifies a form bean, the ActionServlet sees if there is one already or creates one.
- If a form bean is in play, the ActionServlet resets and populates it from the HTTP request.
- If the mapping has the validate property set to true, it calls validate on the form
- If it fails, the servlet forwards to the path specified by the input property and this control flow ends.
- If the mapping specifies an Action type, it is reused if it already exists or instantiated
- The Action’s perform or execute method is called and passed the instantiated form bean (or null).
- The Action may populate the form bean, call business objects, and do whatever else is needed.
- The Action returns an ActionForward to the ActionServlet.
- If the ActionForward is to another Action URI, we begin again; otherwise, it’s off to a display page or some other resource. Most often, it is a JSP, in which case Jasper, or the equivalent (not Struts), renders the page.
Struts….. fine–tuned further
The devil, as they say, is in the details. The synopsis and diagram in the prior sections do a good job of outlining the big picture but omit important details. Let’s drill down now and visit the finer points. Since this is HTTP, everything starts with an incoming request.
Request is received by our container
The backbone component of the Struts framework is the ActionServlet. Like all servlets, it lives in a container, such as Tomcat, Resin, or WebLogic. When the container boots, it reads a deployment descriptor (web.xml) that tells it which servlets to load. One of the standard servlet settings is the servlet mapping. The container uses this setting to decide which requests are sent to which servlet:
<servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>/do/*</url-pattern> </servlet-mapping>
Here, we have asked the container to give our ActionServlet any request that matches the pattern /do/*. That would include /do/This or /do/That and /do/ something/Whatever.Many applications like to use suffix mapping instead:
<servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.*.do/url-pattern> </servlet-mapping>
This URL pattern would likewise match this.do or that.do or /something/whatever.do. Any valid extension or prefix can be used; .do is simply a popular choice. When a request comes in with a path component that matches our servlet context, the container forwards it to our ActionServlet. Requests that do not match our pattern are not sent to the ActionServlet. A request matching *.jsp, for example, would be forwarded to the container’s JSP service, such as Jasper if you are using Tomcat or WebSphere. There may be other servlets in your applications that handle other patterns. Any pattern that does not match a servlet mapping is sent to the container’s default web server.
Request is received by our ActionServlet
When our ActionServlet receives a request, it runs the request through a gauntlet that processes the locale, mapping, form bean, and finally the Action. Some of these steps apply only to Struts 1.1 applications:
Process MultipartRequest. If this is a multipart request (a form with a Multipurpose Internet Mail Extension [MIME] attachment), the servlet wraps the request with a special handler, to avoid errors later in the process.
Process Path. The ActionServlet checks to see if this path is for an application module. If so the configuration for the appropriate module is selected. [Struts 1.1] Process Locale. By default, the ActionServlet will check to see if there is a standard locale object in the user’s session. If there is no locale object, the ActionServlet will put one there. This object can be used to provide a localized presentation for each user. Process Content and NoCache. The default MIME type and optional request headers are added to the response.
Process Mapping. The ActionServlet checks the ActionMappings for a mapping keyed to a path that matches the one we are processing. If one is not found, the ActionServlet forwards to the default (or “unknown”) Action, if one has been set, or generates a “bad request” error. If the mapping is found, it is placed into the request for future reference.
Process Roles. The ActionServlet checks to see if the user is authorized to access this action. [Struts 1.1]
Process ActionForm. The ActionServlet checks whether the mapping specifies an ActionForm. If it does, the servlet checks to see if one already exists in the specified scope. (The default is session.) If one does not exist, the ActionServlet creates one.
Process Populate. The ActionForm’s reset method is called, and then it is auto populated via reflection. Parameters that match the ActionForm’s properties are applied. Other parameters and properties are ignored.
Process Validate. The ActionForm’s validate method is called. If the method returns false, control is passed to the input property specified on the mapping, and the Action is not processed.
Process Forward or Include. If the ActionMapping specifies the forward or include attribute, control is transferred to another resource. Otherwise, the ActionServlet delegates the request to an Action object.
Process Action. If the mapping specifies an Action type, the servlet checks to see if one has already been instantiated. If it does not find one, the Action object is instantiated. There is only one Action object per class (the Singleton pattern), which handles all the requests for that Action through multithreading. The servlet calls the Action’s perform or execute method, passing the request, response, mapping, and any form bean. The Action executes whatever behavior is required, which may include:
Accessing a data system, such as a JDBC database
- Creating objects in the request to be used by the view
- Creating objects in the user session, if required
- Updating session objects, such as the user’s locale, as needed
- Performing any other business function required by the application
- Handling exceptions and other error conditions
- Sending a direct response or (most often) returning an ActionForward to
A business object that is invoked by the Action (the Business Delegate pattern) often handles some of this behavior, like accessing a database. The Action is there to handle any web-specific tasks, but any code that can be placed in a business object should be placed in a business object. The Action is a Controller class and should not be used to
handle your application’s core business logic.
The Action returns an ActionForward
When the Action completes, it returns an ActionForward. If the ActionForward is null, the ActionServlet assumes the response has been generated and does nothing. Otherwise, the ActionServlet reads the ActionForward and either redirects or forwards the request as appropriate.
If the request is another Action URI, the container will return the request to the ActionServlet. Otherwise, the container sends the request to another servlet or service. If the ActionForward is set for redirect, the request is sent back to the client with instructions to submit a new request to the specified location.
Jasper (or equivalent) renders a JavaServer Page
When the ActionServlet sends a request to a JSP, the request is handled by another service, such as Jasper. Typically, the Struts and other tag extensions are used to write the dynamic portions of the page. Sometimes a JSP template may be used so that the page is built up from other components. Most often, the dynamic data is passed to the page in the request context in a JavaBean. This is known as the View Helper pattern [Go3]. The tag extensions simply call methods on the JavaBeans that return the formatted data. How data is positioned on a page is considered part of the presentation logic. The format of the data itself is usually part of the business logic, so it is delegated to the bean. The Struts tags may also access view helpers provided by the framework. These include localized labels and prompts, error messages, and hyperlink paths. In addition, Struts tags can evaluate expressions, iterate through lists, and populate the controls in an HTML form.
Another servlet renders the response
After processing an Action, the request can be sent to any other servlet or service in the application. Other presentation systems, such as Velocity templates, can access framework resources through the servlet contexts.
Today’s developers need to build full-featured applications that can be maintained over time. Web application frameworks such as Struts solve common problems, so developers can focus on their application’s unique functionality. Frameworks are especially important when building web applications since the way HTTP and HTML work makes creating dynamic applications difficult.
Struts makes the most of the standard Java servlet API and has even become an informal compliance test for servlet containers. Struts also builds on the common design patterns, especially the MVC architectural paradigm. The framework encourages a “layered” design for applications. This design helps make applications both robust and scalable. A key part of the Struts architecture is the way it extends the flow of the base HTTP request-response cycle. The Struts controller manages the paths used by your application, helps to safely collect input from users, and can localize application messages— especially error messages. Struts is a performant solution. It will not hold your application back and usually frees resources that can be better used elsewhere. Of course, Struts has its flaws. Many of the classnames were hastily chosen during development and can be confusing; other areas could also be improved. Despite any drawback, Struts is easily the most popular web application framework available today.