JAX London 2014: A retrospective
Getting Started with Apache Struts

Tutorial – Apache Struts 2 – From Soup to Nuts

TedHusted
Struts2

The man who managed the Apache Struts 2.0 release, Ted Husted gives us a quick-start guide into the enterprise-ready Java web framework

Background

Apache Struts 2 simplifies enterprise-ready web development by providing a flexible set of custom tags and an extensible application architecture. The framework is designed for professional developers creating sophisticated web applications that integrate with databases and other enterprise services. Originally known as WebWork, Struts 2 has been continuously maintained since March 2002, and most recently updated with the April 2012 release (2.3.3). Struts 2 is product of the Apache Software Foundation and distributed to the general public at no charge under the business-friendly Apache Software License 2.0. The ASF provides product support only through a public mailing list frequented by volunteer developers and users.

Getting Started

Struts 2 is directly supported by the three most popular integrated development environments (IDEs) for Java: IntelliJ IDEA by JetBrains, MyEclipse by Genutec, and NetBeans. For example, to create a Struts 2 application in IntelliJ IDEA, you can select the Struts 2 facet, and the IDE will download the JARs and setup a Java web application structure, ready for you to add your own pages and other Struts 2 elements.  

Figure 1 – IntelliJ IDEA ready for your Struts 2 elements

IntelliJ IDEA’s support for Struts 2 includes configuration via dedicated Struts 2 facet – with fileset manager, library validator, and configuration detector, dedicated Struts 2 structure tool windows, code inspectors that spot Struts 2-specific code issues, support for inplace Javascript and CSS code, smart coding completion within Struts elements, Struts 2-ready refactorings, and Struts 2-aware project navigation across Java, JSP and XML files. 

Likewise, with MyEclipse, you can add Struts 2 capabilities to a web project, including wizards to create new Struts 2 elements or edit existing elements. The wizards are context-sensitive and provide input assistance and validation as you edit Struts 2 elements. Not to be left behind, NetBeans offers its own set of wizards to create an example Struts 2 application, register the necessary library files, and then edit the various Struts 2 elements. In addition, NetBeans supports hyperlinking and code completion in Struts 2 configuration files. Struts 2 also provides a Maven prototype you can use to bootstrap a project, if you are so inclined, and, of course, the distribution has all the usual assets for hardcore hand-coders.

In Brief – The Elements of Struts Design

A dynamic Struts 2 application has seven building blocks:

  1. Pages with Struts Tags
  2. Message Properties
  3. Actions
  4. Interceptors
  5. Validators
  6. Results
  7. Annotations and Deployment Descriptors

 The elements can be organized into three groups:

  • Pages and Message Properties are used to create the application user interface.
  • Actions, Interceptors, and Validators process an incoming request, in order to render a page, or some other Result.
  • Annotations and Deployment Descriptors are used to define the initial state for the other elements of a Struts 2 application.

 Let’s take a look at each element in turn…

        

Terminally Pretty – Struts Tags

Often, much of the coding effort in a web application goes into the pages. The Struts 2 Tags help us create localized, dynamic web applications with a minimum of coding, reducing effort by reducing code. The listing “A localization-ready form using Struts tags.” shows the source code for a simple input form. 

A localization-ready form using Struts tags
<s:actionerror/>
<s:form action="RegisterSave" validate="true">
<s:textfield key"username"/>
<s:password key="password"/>
<s:password key=password2.label" name="Password2"/>e
<s:submit key="save"/>
<s:submit key="cancel" action="MainMenu"
onclick="form.onsubmit=null"/>
</s:form>

The key attribute refers to a Message Properties file, in the standard Java format, that contains the text to use as the label, along with other terms, such as error messages. The listing “A message properties file” shows a simple properties file for our form.

A message properties file

 

username = Username
password = Password
password2.label = Repeat password
save = Save
cancel = Cancel

The figure below “Struts 2 Data Entry Form” shows the page rendered in a web browser.

Figure – Struts 2 Data Entry Form

The two use cases for Message properties are normalization and localization. Many terms are used more than once, and so should be defined only once. Also, many enterprise applications are presented in multiple languages, and Struts 2 supports adding Message Property files for different locales. The key attribute can also be used as the name of the property used to populate the field from a dynamic value passed to the page.  

Telling it Like it is – Value Stack

To manage values being passed to a page, Struts 2 uses a “Value Stack”. When a Struts tag needs a value, the framework searches the Value Stack in Last In First Out order (LIFO). If you push a JavaBean with a Username property onto the stack last, then the tag will find that value first. The Value Stack encapsulates the standard Java scopes, along with framework elements, and any custom objects you would like to push onto the stack. The Struts 2 Validators use the Value Stack to redisplay incorrect form input. A default value might have been set by a database call, and another value entered by the user into a form. The user’s value is last on stack, and so it’s found first if the page is redisplayed. Figure 3 “Struts 2 Value Stack” illustrates how the system searches for property values.  

Figure 3: Struts 2 Value Stack

The Value Stack solves a thorny problem in validating input. You might have an Integer field on a JavaBean, but on the input form, the user enters “Blue” instead of a number. The framework can’t store “Blue” in an Integer field. So, we either have to throw-away the incorrect value, or complicate how we store a value destined for an Integer property. In Struts 1, for example, we use ActionForms to capture and validate input as Strings.

Many developers would then code a similar but different set of JavaBeans to capture the value in its native type, for transfer to a database system. In Struts 2, the framework can validate input and transfer it to a “POJO” JavaBean with typed properties, without creating and maintaining a special ActionForm. The Struts 2 Validators push the offending input onto the Value Stack, so it can be validated and corrected before populating a value object.

Hard Name, Easy Code – OGNL

Underlying the tags is a powerful expression and binding language called OGNL, or Object Graph Notation Language. Most Java web developers will find the feature set similar to the JST Expression Language, but much more capable. OGNL works hand-in-glove with the Value Stack, making it easy to retrieve a value from a certain scope, or just the last value pushed. 

  • Get the username from the User object in Session scope only: <p>Username: <s:property name=”#session.user.username” /> </p>
  • Get the username propery last pushed onto the stack: <p>Username: <s:property name=”username” /> </p>

New Tags for Old – Control, Data, and UI

A variety of custom tags are available in Struts 2, which can be grouped into three flavors: Control, Data, and UI. The Control tags allow a page to 

  • change its presentation on the fly, by using operations like if, elseif, and else; or
  • generate markup with operations like append, iterator, merge, sort, and subset

The Data tags mange dynamic values and behaviors, with operations like a, action, bean, date, debug, i18n, include, param, property, push, set, text, and url. The Form UI Tags replicate and extend the standard HTML tags, with operations like form, label checkbox, radio, optgroup, textfield, textarea, and password – along with enhanced controls like checkboxlist, combobox, doubleselect, among several others. Finally, Non-Form UI Tags, provide error handling with operations like fielderror, actionerror, and actionmessage.  

Less is More – Themes

Most often, the dynamic data emitted by many of the tags is wrapped in a predictable envelope of basic HTML. To make pages easier to build, the UI Tags can include routine markup, so you don’t have to. The framework ships with standard themes that include different sets of standard markup.

  • The Simple Theme does not output markup. You can add your own – pretty much like a standard HTML tag.
  • The XHMTL Theme is the default theme, and does things like put forms into a two-column table layout, with labels, client and server-side validation, and error handling (just by specifying the field).
  • The CCS XHTML Theme is designed to replicate the XHTML theme, but entirely in CSS.

The listing “HTML source generated by Struts Tags” shows the code the XHTML template generated for our data entry form.  

HTML Source generated by Struts Tags
<form id="RegistrationSave" name="RegistrationSave" action="/struts2-mailreader/RegistrationSave.do" method="post">
<table class="wwFormTable">
    <tr>
    <td class="tdLabel"><label for="Registration_save_username" class="label">Username:</label></td>
    <td><input type="text" name="username" value="" id="Registration_save_username"/></td>
    </tr>
    <tr>
    <td class="tdLabel"><label for="RegistrationSavePassword" class="label">Password:</label></td>
   <td><input type="password" name="password" value="" id="RegistrationSavePassword"/></td>
</tr>
    <tr>
    <td class="tdLabel"><label for="RegistrationSavePassword2" class="label">(Repeat) Password:</label></td>
    <td><input type="password" name="password2" id="RegistrationSavePassword2"/></td>
</tr>
</table></form>

The templating system is designed so that you override the markup for a single control, or replace all the standard markup with your own custom theme.

    

It Takes a Village – Actions, Interceptors, Validators, Results

Web pages are only the last mile between the user and the backend business logic. In order to acquire the data that a dynamic page needs, a request passes through a set of handlers. The image below shows this in context.

Lights, Cameras – Actions

Actions are the framework’s basic unit of work. Most framework requests are handled by an Action, with help from Interceptors, Results, and the Struts Tags. An application can map an action handler to logical resource names, like Welcome.action or AccountInsert.action. When a browser submits a request for one of these resources, the framework selects an Action class to handle the exchange. The input values from the request (if any) are transferred to properties on an Action class (or some other class of your choosing). The framework then calls a method on the Action to invoke the business logic associated with the request. The class can return a string token to indicate the outcome of the transaction. Usually, these tokens are generic terms like “success”, “failure”, “input”, “error”, or “cancel”. The framework passes the token returned by an Action to a Result handler for further processing.

Getting There from Here – Results

The result handler either creates output or dispatches to another resource, like a server page, to create the output. There are several result handlers bundled with the framework and several more are available as plugins. For example, there are plugins for rendering reports with JFreeChart or JasperReports.

Another plugin converts output to JSON for AJAX applications. Yet another lets Struts 2 applications utilize JavaServer Faces components as a result. Other custom results can be created and plugged into the framework as needed. Each action handler can have one or more result handlers, mapped to whatever result types are needed.

Regardless of what type of result is being generated, the action handler only needs to return a logical name. The action does not need to know how the response is being handled.

Thank You Sir, May I have Another – Interceptors

Most of the framework’s business-logic utility is provided by Interceptors. All requests can be handled by a single set of Interceptors, or different sets of Interceptors can handle different requests.

Interceptors can invoke code both before and after the Action executes, encapsulating standard utility that can be shared between Actions into a reusuable object. Services like property population, validation, and authorization are provided by standard Interceptors.

The set of Interceptors acts as a “gauntlet” for the request. The request object passes through each Interceptor in turn. The Interceptor can ignore the request, or act on the request, as appropriate.

Trust but Verify – Validators

Validators vet incoming data and generate an error message when input is invalid. The framework provides all the validators that most applications will need, though custom Validators are easy to implement for special situations.

Ready, Set, Go – Annotations and Deployment Descriptors

A web application uses a deployment descriptor to initialize resources like filters and listeners. The web deployment descriptor is formatted as a XML document. The web container reads the XML document and creates an internal configuration object. When the container starts up, it loads and configures the components specified by the deployment descriptor.

Likewise, Struts uses an internal configuration object to tie together various parts of the application, like the Action and the Result. An application can specify the Struts configuration by using Java annotations or by providing one or more XML documents.

  • web.xml – Standard web deployment descriptor with the framework’s bootstrap components, including the FilterDispacther that detects Action URLs.
  • struts.xml – Main configuration, contains result/view types, action mappings, interceptors, and so forth.
  • struts-plugin.xml – Optional configuration file for plugins. Each plugin JAR may have its own descriptor.

Below shows a typical XML-style configuration for a logon action:

Example Logon XML Document

 

<struts>
  <package name="default"
    extends="struts-default">
    <action name="Logon"
      class="mailreader2.Logon">
      <result type="redirect-action">MainMenu</result>
      <result name="input">/pages/Logon.jsp</result>
      <result name="cancel"
       type="redirect-action">Welcome</result>
      <result name="expired"
        type="chain">ChangePassword</result>
    </action>
  </package>
</struts>

 

And the corresponding annotations for the same logon action:

Example Logon Java Annotation

 

@Results({
@Result(name="success", value="MainMenu"),
@Result(name="input", value="pages/Logon.jsp"),
@Result(name="cancel", value="Welcome",
type="redirect-action"),
@Result(name="expired", value="ChangePassword",
type="chain")})
public class Logon extends ActionSupport {
// .... 
}

 

Tip – Configuration by Java annotation or by XML document are not mutually exclusive. We can use either or both in the same application.

   

Same Stuff, Different Day – Struts 2 Life Cycle

A framework is a semi-complete application. By providing a backbone structure, the framework lets developers add the code that makes this application unique, and reuse the underlying architecture again and again.

The Struts 2 architecture strives for simple elegance. When a web client sends a request to a Struts 2 application, the framework provides a seven step processing cycle

  1. Accept Request,
  2. Select Action,
  3. Push Interceptors,
  4. Invoke Action,
  5. Select Result,
  6. Pop Interceptors, and
  7. Return Response.

At each step in the cycle, developers can provide their own code to define how their application reacts to a particular request.

  1. Accept Request: First, a web browser makes a request. The request might be for a resource like a HTML page, a PDF, or (among other things) the special “Action” resource that can create a dynamic response.
  2. Select Action: The incoming request is transferred to a Struts 2 component called a Filter Dispatcher. Whenever this request is for a Struts Action, our dispatcher passes the request through to the rest of the framework. (Otherwise, the request just passes through our dispatcher, untouched.)
  3. Push Interceptors: Whenever a request enters the framework, we might want to validate input, or transfer values to an internal object, or upload a file, or any combination of similar operations. (In other words, we want to intercept the request to do some housekeeping before going on to the main event.) The framework Interceptor components handle operations that need to be applied to more than one request.
  4. Invoke Action: Aside from the Interceptor operations, we will also want to invoke an operation unique to the request (the “main event”). For example, we might want to work with a database to store or retrieve information. After a request passes through the outer layer of Interceptors, a method on an Action class can be called to handle any special processing for the request.
  5. Select Result: After the Action method fires, we need to tell the rest of the framework what to do next. We’ve handled the request, and now we need to create the response (or “result”). As aforementioned, to bootstrap the response process, the Action method returns a string token representing the outcome of the request, such as “success”, “failure”, “cancel”, or something more specific, like “logon”. The framework matches that token with the name of a Result component. The Result is responsible for handling the response, either by rendering output for the browser, or by transferring control to another resource that will render the response. Most often, “another resource” will be a JavaServer Page formatted with Struts Tags.
  6. Pop Interceptors: After the Result handler fires, the request passes back through the set of Interceptors. Some Interceptors work with incoming requests, some work with outgoing requests, and some work with both.
  7. Return Response: The request exits the framework, and the web server sends our response back to the web browser.

Architecturally, Struts 2 is an Enterprise Model View Controller framework where the Action provides the Model, the Result represents the Controller, and Tags render the View.

But wait, there’s more – Plugins

Struts 2 provides a simple plugin architecture so that developers can extend the framework just by adding a JAR to the application’s classpath. Since plugins are contained in a JAR, they are easy to share with others. Here’s a sampling of the many plugins available for Struts 2.

  • JQuery: Ajax functionality and UI Widgets based on the jQuery javascript framework.
  • Hibernate: Hibernate Validator integration, Hibernate Core Sessions and Transactions injection capabilities and a Configuration Management Web Tool.
  • Guice: Actions, Interceptors, and Results to be injected by Guice.
  • OSGI: starting an instance of Apache Felix inside a web application, and scanning installed bundles for Struts configuration
  • REST: provides tools to build RESTful applications
  • Sitemesh: Sitemesh templates functionality access Struts information.

Next Steps

If you’re ready to take Struts 2 for a spin, the simplest thing is to fire up your favorite editor or IDE, and start coding.

To give you a staring place, the Struts 2 distribution bundles a “Struts Blank” application. It’s a ready-to-deploy WAR, designed to serve as a starting place for your applications.  

The Blank application is internationalized and includes a number of example pages, to help you get started.  

Of course, there are a number of online resources for learning more about Struts 2, most of which are documented on the official website at struts.apache.org. Another great resource is Struts 2 in Action by Don Brown, et al. Highly recommended!

Ted Husted is the co-author of Struts in Action (first edition), a former Struts committer, and served as Release Manager for the initial Stuts 2 distribution. When he can, Ted now helps out with the Vosao CMS project (www.vosao.org), an open source web content management system for the Google Apps Engine. Ted will be speaking at ApacheCon NA in November 2010 on the “Secret Life of Open Source” and “.NET @ Apache.org”. He works as a Business Analyst with NimbleUser, a technology company helping professional and trade associations do more with web-based applications.

 

This article originally appeared in Java Tech Journal – Java Web Frameworks – check out more of that issue here!


Author
TedHusted
Ted Husted is a business analyst, best-selling author, and regular speaker at ApacheCon and the Ajax Experience. He now works with NimbleUser, a systems integrator specializing in non-profits. Ted is also a former member of the Apache Struts project and co-founder of the Apache (Jakarta) Commons
Comments
comments powered by Disqus