The J2EE architecture is a great advance for developers. Its standardized framework defines and supports a multitiered programming model, freeing application developers to concentrate on solutions.
This article is based on version 0.5 of Struts; some of the APIs will change slightly in subsequent versions.
There are a number of ways to architect applications using J2EE technologies, including JSPs, servlets, and EJBs. However, there aren't any application development frameworks available that address how developers should create applications based on the J2EE architecture.
The development community has recognized the need for an open-source framework that's useful in building Web applications using J2EE technology. This has led to the creation of the Struts project, a burgeoning grassroots movement that will soon become a J2EE "household name."
Struts is an open-source initiative from the Jakarta Project, which is sponsored by the Apache Software Foundation. The framework was created by Craig McClanahan in May of 2000, after which the code was donated to the Apache Software Foundation and then to the development community.
The Struts charter is to provide an open-source framework that facilitates building applications based on the J2EE servlet and JSP technologies. The primary functionality provided by Struts includes request dispatching, tag libraries to accelerate GUI development, internationalization, and automatic form population.
Struts encourages application architectures based on the Model-View-Controller (MVC) design paradigm, also known as Model 2.
Model 1 (page-centric) vs Model 2
In a Model 1 design the application logic and program flow are combined into JSP pages. Model 1 designs are considered page-centric because the application flow is controlled by the JSP pages. Therefore, there's a tight coupling between the pages and the logic in the application.
However, while Model 1 is well suited to relatively simple applications, it's limited for complex ones. For example, the fact that the JSP pages in a Model 1 design contain both the presentation and control logic means the application is more difficult to maintain. A large amount of Java code within the HTML eliminates the role separation between Web page designer and Java coder, creating dependencies across multiple developers and increasing the likelihood of errors.
In addition, Web applications inherently have flow control issues, which can lead to many problems unless proper precautions are taken to avoid them. In many cases, "proper precautions" mean the creation of a great deal of duplicate code. For instance, to facilitate proper security, a developer must not make assumptions about the users' authentication before they arrive at the current page. This requires some sort of user authentication to happen in every page.
In a Model 2 design the application flow is controlled by a central servlet that utilizes an implementation of the Mediator design pattern to delegate requests to the appropriate handler. The request handler will most often be a presentation JSP; however, it could also delegate a processing page JSP or servlet to handle the application logic. Then the JSP or servlet forwards the request to the appropriate presentation page back through the servlet. To acquire the appropriate page to forward the request to, resolve the logical name that's passed from a configuration file or database to the servlet as part of the pathinfo or as a request parameter. This provides a loose coupling of the pages and components within the application.
Another term used to describe the Model 2 design approach is Model-View-Controller. In describing this design, the JavaBeans or EJBs used within the application are considered the Model, JSP pages are used as the View, and the mediating servlet is considered the Controller.
The Struts framework provides developers with a well-thought-out design that allows you to focus your program flow, validation, and request dispatching. Struts accomplishes this by providing specific components for each piece of the MVC architecture - Model, View, and Controller.
The Model represents the data that the View presents. In Struts, the Model is comprised of a few specific Struts components, as well as application and business logic, encapsulated in a reusable component such as a JavaBean or an EJB. The Struts-specific Model components include ActionForm and Action classes.
The ActionForm class serves several purposes in Struts. Typically, when building a Struts application you'll implement a class that implements the ValidatingActionForm interface for each input form in your application. The ActionForm should contain the attributes that you've defined in your input form using the tag libraries provided by Struts. When the form is submitted, ActionServlet creates or reuses an instance of the ActionForm associated with the input form and adds this instance to the user's session. The attributes of the input form will be populated in the ActionForm instance by calling the corresponding mutator methods. You're required to implement accessor and mutator methods for each property defined in your ActionForm.
Once the ActionForm is populated, the validate method is invoked. The validate method is responsible for ensuring that the user populates the required fields with data in the appropriate format. As you can see from the ValidatingActionForm interface, the validate method returns an array of strings. If the validate method determines there's invalid data in the ActionForm (nonexistent or otherwise incorrect), the strings returned from the validate method are communicated to the user (through the <struts:errors/> tag). If errors are detected, the original form that was submitted is populated using the values in the ActionForm, and the error messages returned by your ActionForm are displayed back to the user. This way the user only has to change/correct the fields that were determined to be incorrect.
Once the validate method returns null, indicating there are no errors, the ActionServlet calls the corresponding perform method of the Action class. The perform method is responsible for processing the request and subsequently forwarding the request to the appropriate view component (a JSP) as indicated by the returned ActionForward instance. When implementing an Action, you can either implement the Action interface or extend the abstract base class ActionBase. ActionBase provides default implementations for the getLocale, setLocale, getResources, isCancelled, and saveErrors methods. It's not recommended that the Action contains business logic, but it should make calls into the business component stack that implements the logic. After the Action has processed the request, it should return an ActionForward object that identifies the JSP page to which control should be transferred. This JSP is responsible for generating the appropriate response to the requesting device.
The benefit Action provides is that business components don't need to be aware that they're accessed from a servlet/Web environment. Business objects shouldn't take ServletRequest and ServletResponse as parameters. This tightly couples business components to a Web environment and limits the scope in which they can be used.
Struts relies on JSPs to create the appropriate View for the requesting client. For convenience reasons Struts provides a comprehensive tag library (based on the JSP custom tag library facility in JSP 1.1). These tag libraries can be used to construct the user interface. The advantage of using these tag libraries is that they provide some additional functionality. For example, the following snippet may be found in an HTML/JSP form:
<input type="text" name="userName" value="<%= user.getUserName() %>">
Using Struts custom tag libraries, the above would become:
The advantage here is that HTML developers may not be familiar with scripting beans, such as the one shown in the first snippet. The Struts tag library gets around this by providing a simple tag library that can be used by nonprogrammers. The second snippet assumes the <struts> tag is nested within a Struts form tag, so the field will call upon the correct bean to get its values.
When implementing a Struts application, use the Struts tag libraries to construct the user interface. Included in this tag library are tags for typical form elements such as checkboxes, hidden fields, and radio controls. In addition, the library contains various tags for displaying data, creating hyperlinks, and internationalization.
The Controller in the Struts framework is implemented by the ActionServlet class. As the name describes, the Controller is implemented as a servlet. The servlet is responsible for delegating requests to the appropriate components as specified according to the action.xml file. Each Struts-based Web application requires an action.xml file, the same way you have one Web.xml per Web application. The action.xml file provides logical mappings that the ActionServlet will use to determine how to process the request. Specifically, the mapping tells ActionServlet which Struts components to use and what the program flow is. This is done by providing a mapping for each requested URI (i.e., /logon) to an Action class and an ActionForm class. The benefit of this is that Action classes can be leveraged for multiple requests; changes can be made to the application without requiring code modification. The action.xml mapping file can also provide a mechanism to separate program flow from business logic.
You'll need to implement an ActionMapping class if additional mapping information is specified in the action.xml file. However, if no such additional attributes are needed, Struts provides a default implementation (ActionMapping) that knows how to deal with the default XML format of action.xml.
In the sample application that's part of the Struts distribution, there are two additional attributes in action.xml - success and failure. These attributes define which JSP page should be forwarded to which request based on a success and failure condition of the validate method of the ActionForm class.
A Note on Internationalization (I18N)
We've already stated that Struts provides developers with an extensive tag library. One of the most striking features of this tag library is a message tag that deals with internationalization (I18N). The functionality provided through this tag is based on what's already provided by the Java platform: PropertyResourceBundle and MessageFormat. The approach is simple yet effective.
Beyond what's already provided by Java, Struts provides a MessageResources class that lets you treat a set of ResourceBundles as a database. In Java, when you request a message from a ResourceBundle, it's based on the default locale of the JVM. This is not useful when the JVM in which your application is running is serving up content for individuals with different preferences. Struts allows you to request a message string for a particular user for a specific language preference. This is implemented by having the application store a locale object within the user's session under the name "org.apache.struts.action.LOCALE". If no locale object is found in the user's session under this key, the default resource bundle will be used.
To support multiple languages in your application using Struts, provide a resource bundle for each locale that you want to support, along with the appropriate extension. The base name of the resource bundle to be used by the application is specified in the application's deployment descriptor.
The message tag is used as follows within an HTML/JSP form:
<struts:message key="mykey"> where "mykey" is the key into the properties file.
The Future of Struts
Interest in Struts has increased dramatically over the past few months. At the time of this writing, Struts has a following of 900 mailing list members as well as four committers.
Since Struts has such a large number of involved participants (and more are expected to join), it's likely that the Struts framework will mature significantly over the next few months. In addition, commercial software companies are starting to look at the Struts framework as a possibility on which to base their development efforts. Plus, as a J2EE developer, you'll be hearing more about Struts in the near future since Sun is planning to integrate the Struts framework into their Blueprints example application implementation.
There are a number of ways to participate in the Struts project. You can join one of the Struts mailing lists by sending e-mail to the user ([email protected]) or developer ([email protected]
apache.org) mailing lists. The user mailing list is made up of users of the Struts framework, while the dev mailing list is made up of developers interested in furthering the Struts framework.
You can contribute to Struts by providing patches and modules to the dev mailing list. There's also a "Todo" list on the Struts Web site, http://jakarta.apache.org/struts/, that outlines the immediate tasks the group is working on. Help is always welcomed.
Last, you can achieve committer status, which enables you to have direct access to the source control. To become a committer you must be voted in; the rules can be found on the Jakarta Web site, http://jakarta.apache.org/guidelines/index.html.
References and Resources
- Gamma, E., Helm, R., Johnson, R., and Vlissides, J. (1995). Design Patterns - Elements of Reusable Object-Oriented Software. Addison-Wesley.
Craig McClanahan was involved in the Apache JServ project, focused on implementing a next
generation architecture and feature set for the core servlet engine. He has recently joined Sun as technical lead for the servlet and JSP reference implementation, Tomcat. Craig has a BA in accounting from the University of Puget Sound.
Larry McCay is a senior architect at Bluestone Software and has been a major contributor to Bluestone's
Total-E-Business platform and its Application Manager. He's been designing and developing software for over 10 years. Larry has a BS in business administration with a specialization
Erik Bergenholtz is a development manager at Bluestone Software and has been a major
contributor to Bluestone's Total-E-Business platform. He's been designing and developing commercial software for the past 10 years. Erik has a BS in computer science and an MS in software