Mark's Struts 2 Cookbook

Struts 2 is the new version of Struts, under development at the Apache Group. It is based on WebWork 2, and has many modern web framework features, like user interface tags, type conversion, and validation. Struts 2 is highly flexible and extensible.

In this cookbook you will find HOWTO guides, and recipes for common scenarios in Struts 2.

Compiling JasperReports JRXML Files with Maven

I recently started using JasperReports in Quadran. I'm using Maven to manage the Quadran project, and I wanted the JasperReports to fit into the process like everything else. There is a Maven plugin in the Mojo collection for compiling jrxml files. Currently the plugin is in the sandbox, so you will need to check it out of Subversion and install it yourself in your local Maven repository. At a command prompt I did the following on OS X. You'll have to adapt this to your operating system. That will install the JasperReports Maven plugin into your local repository. Now you need to configure your pom.xml file to use the plugin. You will need to add the following to your build -> plugins section:
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jasperreports-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile-reports</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
The plugin expects your jrxml files to be in src/main/jasperreports. The compiled jasper files are placed in target/classses. You can have subdirectories and these will be preserved in the target/classes directory.

Creating a Login Interceptor in Struts 2

Controlling access to web resources with a a login process is a common use-case. Implementing this using an interceptor in Struts 2 is very straight forward. The parts of the solution:

Implementing the LoginInterceptor

In Struts 2 interceptors are called one after the other in a configured order for each invocation of an action class. The interceptors have an opportunity to interact with the input from your user, and to interact with the action after it has completed it's processing. They can also intercept the process between the running of your action and the hand off to the result, but I we will not need that for our purposes here. The main method in an interceptor is the intercept() method. This method is passed an ActionInvocation object, which contains the action, and the context for the action, such as the HttpRequest, HttpSession, etc. The intercept method returns a String that maps to a "result" in our struts.xml file. The intercept() method for our interceptor uses the HttpSession to determine if the user's "user" object is stored in the session. If the user object is in the HttpSession, then we consider the user to be logged in, and continue the chain of the interceptor stack by calling invocation.invoke (). If the user's "user" object isn't in the HttpSession we check to see if the user is attempting to log in, and process the login. If they're username and password validate the interceptor sends them the to the "login-success" result, otherwise we send them the "login" result.
public String intercept (ActionInvocation invocation) throws Exception {
    // Get the action context from the invocation so we can access the
    // HttpServletRequest and HttpSession objects.
    final ActionContext context = invocation.getInvocationContext ();
    HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
    HttpSession session =  request.getSession (true);

    // Is there a "user" object stored in the user's HttpSession?
    Object user = session.getAttribute (USER_HANDLE);
    if (user == null) {
        // The user has not logged in yet.

        // Is the user attempting to log in right now?
        String loginAttempt = request.getParameter (LOGIN_ATTEMPT);
        if (! StringUtils.isBlank (loginAttempt) ) { // The user is attempting to log in.

            // Process the user's login attempt.
            if (processLoginAttempt (request, session) ) {
                // The login succeeded send them the login-success page.
                return "login-success";
            } else {
                // The login failed. Set an error if we can on the action.
                Object action = invocation.getAction ();
                if (action instanceof ValidationAware) {
                    ((ValidationAware) action).addActionError ("Username or password incorrect.");
                }
            }
        }

        // Either the login attempt failed or the user hasn't tried to login yet, 
        // and we need to send the login form.
        return "login";
    } else {
        return invocation.invoke ();
    }
}
The actual validation of the username and password are left to the processLoginAttempt() method. The processLoginAttempt() method is responsible for using whatever means necessary to validate the username and password and saving the user's user object in the session. This is done this way, because there might be many ways to do the validation, and you might collect additional information on the user to store in their sesion, such as roles, or other credentials. Breaking this out allows you to override this method in your own interceptor and process this however you'd like. The default implementation uses a SecurityManager to lookup the user's information.
/**
 * Attempt to process the user's login attempt delegating the work to the 
 * SecurityManager.
 */
public boolean processLoginAttempt (HttpServletRequest request, HttpSession session) {
    // Get the username and password submitted by the user from the HttpRequest.
    String username = request.getParameter (USERNAME);
    String password = request.getParameter (PASSWORD);

    // Use the security manager to validate the user's username and password.
    Object user = securityManager.login (username, password);

    if (user != null) {
        // The user has successfully logged in. Store their user object in 
        // their HttpSession. Then return true.
        session.setAttribute (USER_HANDLE, user);
        return true;
    } else {
        // The user did not successfully log in. Return false.
        return false;
    }
}

Declaring our Interceptor in struts.xml

In our struts.xml configuration file we need to declare the LoginInterceptor, and add it to an interceptor class so it will be used.
<struts>
    <package name="my-default" extends="struts-default">
        <interceptors>
    
            ...

            <interceptor name="login" class="loginInterceptor" />
    
            ...

        </interceptors>
                

    </package>
</struts>
Notice that the fully qualified classname is not declared for the interceptor. We configure that in our Spring config, which allows us to wire our SecurityManager into it.

Configuring our Interceptor Stack to use the LoginInterceptor

We need to add the LoginInterceptor to an interceptor stack so it will be used when an action is invoked.
<struts>
    <package name="my-default" extends="struts-default">
        <interceptors>
    
            ...
    
            <interceptor-stack name="defaultLoginStack">
                <interceptor-ref name="servlet-config" />
                <interceptor-ref name="params" />
                <interceptor-ref name="login" /> <!-- Our LoginInterceptor -->
                <interceptor-ref name="prepare" />
                <interceptor-ref name="chain" />
                <interceptor-ref name="model-driven" />
                <interceptor-ref name="fileUpload" />
                <interceptor-ref name="static-params" />
                <interceptor-ref name="params" />
                <interceptor-ref name="conversionError" />
                <interceptor-ref name="validation" />
                <interceptor-ref name="workflow" />
            </interceptor-stack>

            ...

    </package>
</struts>

Adding the Global "login" Result

We need to add a global "login" result so that it is available no matter what protected action a user might invoke. This allows our interceptor to return "login" and have it properly mapped to our login page.
<struts>
    <package name="my-default" extends="struts-default">

        ...
        
        <global-results>
            <result name="login">/WEB-INF/pages/Login.jsp</result>
            <result name="login-success">/WEB-INF/pages/Index.jsp</result>
        </global-results>

        ...

    </package>
</struts>

The Complete struts.xml Package

<struts>
    <package name="my-default" extends="struts-default">
        <interceptors>

            <interceptor name="login" class="loginInterceptor" />

            <interceptor-stack name="defaultLoginStack">
                <interceptor-ref name="servlet-config" />
                <interceptor-ref name="params" />
                <interceptor-ref name="login" />
                <interceptor-ref name="prepare" />
                <interceptor-ref name="chain" />
                <interceptor-ref name="model-driven" />
                <interceptor-ref name="fileUpload" />
                <interceptor-ref name="static-params" />
                <interceptor-ref name="params" />
                <interceptor-ref name="conversionError" />
                <interceptor-ref name="validation" />
                <interceptor-ref name="workflow" />
            </interceptor-stack>

            <interceptor-stack name="defaultInsecureStack">
                <interceptor-ref name="servlet-config" />
                <interceptor-ref name="params" />
                <interceptor-ref name="prepare" />
                <interceptor-ref name="chain" />
                <interceptor-ref name="model-driven" />
                <interceptor-ref name="fileUpload" />
                <interceptor-ref name="static-params" />
                <interceptor-ref name="params" />
                <interceptor-ref name="conversionError" />
                <interceptor-ref name="validation" />
                <interceptor-ref name="workflow" />
            </interceptor-stack>
        </interceptors>

        <!-- Make the defaultLoginStack the default one used
                for all actions unless otherwise configured. -->
        <default-interceptor-ref name="defaultLoginStack" />

        <default-action-ref name="index" />

        <global-results>
            <result name="login">/WEB-INF/pages/Login.jsp</result>
            <result name="login-success">/WEB-INF/pages/Index.jsp</result>
        </global-results>

        <action name="index">
            <result name="input">/WEB-INF/pages/Index.jsp</result>
            <result name="success">/WEB-INF/pages/Index.jsp</result>
        </action>

    </package>
</struts>

A Login Page

We need a JSP page to allow the user to enter their username and password.
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Login</title>
</head>
<body>
<s:actionerror />
<s:form namespace="/" action="index.action" method="post">
    <s:hidden name="QUADRAN_LOGIN_ATTEMPT" value="%{'1'}" />
    <s:textfield name="QUADRAN_USERNAME" label="Username" />
    <s:password name="QUADRAN_PASSWORD" label="Password" />
    <s:submit value="Login" align="center">
        <s:param name="colspan" value="%{2}" />
        <s:param name="align" value="%{'center'}" />
    </s:submit>
</s:form>
</body>
</html>
Notice the hidden QUADRAN_LOGIN_ATTEMP property in the form. That is what triggers the processing of the login by the LoginInterceptor.

The SecurityManager Service Bean

I use plain POJO service beans and wire them using Spring. Here's a simple SecurityManager interface. Just enough to do the login. I leave the rest as a practice to the user.
package net.vitarara.quadran.core.business.api.security;

public interface SecurityManager {

    public Object login (String username, String password);
}
And the implementation in Groovy:
package net.vitarara.quadran.core.business.impl.security;

import net.vitarara.quadran.core.business.api.security.SecurityManager;

class SecurityManagerImpl implements SecurityManager {

    def partyDao;

    Object login (String username, String password) {
        return partyDao.findByUsernameAndPassword (username, password);
    }
}
I delegate the lookup to my PartyDao which is a class for looking up all types of parties, users, customers, vendors, etc. You will need to figure out how you want to look users up in your system.

Wire it Together with Spring

In my Spring applciationContext.xml file I have the following entry for my interceptor. This entry wires my SecurityManager into the interceptor allowing it to delegate the actual lookup to my business service beans.
<bean id="loginInterceptor" scope="singleton" class="net.vitarara.quadran.core.web.util.LoginInterceptor">
    <property name="securityManager"><ref local="securityManager" /></property>
</bean>
If you are using the Struts 2 Spring plugin whe Struts attempts to load the interceptor at startup it will use Spring to instantiate it.

Conclusion

It's a few steps, but the basics are fairly straight forward. Using this same pattern you can address many cross cutting issues in Struts 2. Such as: The interceptor pattern is a very powerful one, well worth looking at. Struts 2 uses it to implement a great deal of its functionality.

Creating a Struts 2 Action in Groovy

(N.B.: For the latest on Struts 2 and Groovy see: Groovy Works) Actions in Struts 2 are POJO's. Actions also serve the same purpose of the ActionForm from Struts 1, storing all of the data submitted by your user. Additionally Struts 2 action classes store the information you wish to display back to your user. (NB: Struts 2 also supports a ModelDriven style, where the Action does not need to store this data, but the ideas are largely the same.) Over the course of developing a Struts 2 application you will write a lot of accessors, setThis(String in), getThat(). Personally I'm sick of writing those methods. Yes, I know Eclipse could write them for me, but I don't like Eclipse, and I haven't taken the time to learn another IDE. I like my Unix shell, maven, screen and vi (vim), thank you very much. So, what's a guy to to? Groovy Beans! Groovy Beans are a way of writing classes in Groovy that comply with the Java Beans spec. Nice this is they are a lot shorter. An example:

class Person {
    String firstName, lastName, address1, address2, city, state, zip, country;
}

That creates a bean with a default no arg constructor. All of the String members that I have declared, firstName, etc., have a private scope, and Groovy create a setXxx() and a getXxx() for each member. For more information see Groovy Beans. What does this get us in Struts 2? Simple actions. Here's an example of an action that accepts an id as a request parameter, uses a service bean to look up an order with that id, and stores it for retrieval in the presentation layer (JPS's, FreeMarker, etc.).

package example;

import com.opensymphony.xwork2.ActionSupport;

public class MyAction extends ActionSupport {

    // Service Bean
    def myServiceBean;

    // Model Beans
    String id; // Id of an order in the database to go look up.
    def order; // The order we're going to display.

    String execute () throws Exception {
        order = myServiceBean.findOrder (id);
        return SUCCESS;
    }
}

Simple isn't it. No setters and getters cluttering the code. Groovy creates all of those for you. Also the service bean can be injected using Spring. (Just be sure it has a findOrder method, or you will get an Exception. You need to test for that with your integration tests.) One trick is to make sure that you declare the type of the parameters you want to take in from the http request. That will allow Strut 2 to do its type conversion for you. By declaring the id property of type String it causes Struts 2 to populate that property from the http request with a String. If you wanted it to be an int you could also declare it as an int. Simple isn't it. It also looks a lot like Java too. So, why would you want to do this? For me the motivation was search forms that did not map to a domain model object. Frequently these had a lot of fields on them. Searching for a purchase order you might want to be able to search by customer, person who entered it, date entered from, date entered to, date of shipping from, date of shipping to, product, and the list could go on. In Java you would need a setter and getter for each of these form properties. (I've tried using Map backed forms in Struts 2, but you loose the type conversion.) In Groovy this Action could be very small.

package net.vitarara.quadran.core.web.order.purchasing;

import com.opensymphony.xwork2.Preparable;
import net.vitarara.quadran.core.business.api.purchasing.PurchasingManager;
import net.vitarara.quadran.core.web.QActionSupport;
import net.vitarara.utils.VRContext;
import org.apache.commons.lang.StringUtils;

class ListPurchaseOrdersAction extends QActionSupport implements Preparable {

    // Service Beans
    PurchasingManager purchasingManager;

    // Model Bean(s)
    List carriers, issuers, destinationAreas, products, purchaseOrders, vendors;

    // Form Properties
    Date dateEnteredFrom, dateEnteredTo, dateOfReceiptFrom, dateOfReceiptTo;
    String status, issuedById, orderNumber, vendorId;
    String destinationAreaId, carrierId, productId, fob;
    Boolean dutyPrepaid;

    void prepare () throws Exception {
        // Get the data for the drop downs.
        carriers =  purchasingManager.getCarriers ();
        destinationAreas = purchasingManager.getDestinationAreas ();
        products = purchasingManager.getProducts ();
        vendors = purchasingManager.getVendors ();
        issuers = purchasingManager.getIssuers ();
    }

    /** 
     * Marshall that data from our form input to the service layer to 
     * find purchase orders.
     */
    String execute () throws Exception {
        if (isFormFilledIn () ) {
            VRContext context = new VRContext ();
            context.dateEnteredFrom = dateEnteredFrom;
            context.dateEnteredTo = dateEnteredTo;
            context.dateOfReceiptFrom = dateOfReceiptFrom;
            context.dateOfReceiptTo = dateOfReceiptTo;
            context.status = status;
            context.issuedById = issuedById;
            context.orderNumber = orderNumber;
            context.vendorId = vendorId;
            context.destinationAreaId = destinationAreaId;
            context.carrierId = carrierId;
            context.productId = productId;
            context.fob = fob;
            context.dutyPrepaid = dutyPrepaid;
            context = purchasingManager.listPurchaseOrders (context);
            this.purchaseOrders = context.purchaseOrders;
        }
        return SUCCESS;
    }
    /** Determine if the user has filled out web the form. */
    boolean isFormFilledIn () {
        if (status || issuedById || orderNumber || vendorId || 
            destinationAreaId || carrierId ||
            productId || fob || dateEnteredFrom || dateEnteredTo || 
            dateOfReceiptFrom || dateOfReceiptTo ) {
            
            return true;
        } else {
            return false;
        }   
    }   

}  

This example is definitely more complicated. First and foremost for me, the vi loving guy, I didn't have to write 20 sets of setter and getter methods. That's about 80 lines of saved typing. All of the code in the class actually does something or declares the existence of a property of the class. The boilerplate code is gone. This action still uses the type conversion that Struts 2 provides. When the user fills in the dateEnteredFrom field on the HTML form, Struts 2 will convert that to a Date object for me, because dateEnteredFrom is of type java.util.Date. Also notice I didn't need to import java.util.blah blah blah... How many time have I wished javac just imported it. No need to worry, Groovy does. Walking through the example. The class starts with property declaration. The purchasingManger is injected using Spring in my application. The rest of the properties are either used for display purposes in the form, or are used to collect user input. The prepare() method is called as normal. Notice my Groovy class implements the Preparable interface, and extends QActionSupport, both of which are Java classes. In my execute I marshal the users input from my Action into a VRContext, which implements Map. Notice I use very OGNL like notation to put the values into the map, map.somekey = value. In the isFormFilledIn() method I check to see if the user has filled in the form. Notice that if structure, if (somestring), no need to check for null, no need for something like StringUtils.isBlank, etc. Short sweet, and everything means something. If you're using the Struts 2 maven archetype, or Maven in general you can use it to compile your Groovy files to .class files. Groovy Maven Wiki Entry I'm just getting started with Groovy. If you're a Groovy master, and have pointers, please post them.

Creating a Theme in Struts 2

Struts 2 has a very powerful set of user interface tags (UI Tags). These tags are tightly integrated with the framework, taking full advantage of things like the OGNL Value Stack. The power this gives to a user it tremendous.

Struts 2 UI Tags

The Struts 2 UI Tags are backed with templates that do the actual rendering of HTML. You can change them without any need to touch the implementing classes. As of Struts 2.0.2 these templates are written in the FreeMarker template language. A quick look at the Freemarker Manual will provide you a quick overview of the language, and is helpful if you have questions about the language. Anyone familiar with JSP, PHP, or other template languages can quickly grasp it.

The Sample Application

Download the sample application, linked below. This is a Maven 2 project. To build the application run: "mvn package". This will create a war file in the target directory called: struts2themes.war. Deploy this war file to your Servlet container, such as Tomcat.

The XHTML Theme

Struts 2 ships with several themes, including a simple one that simply outputs the html form tags. The theme we are going to start with is the XHTML theme. This theme is designed to output valid XHTML markup, and by default lays forms out in a two column table with the label for each input field in the left column and the input field in the right column. This will get us started. To see the layout created by this theme click the "Standard XHTML Form" button in the sample application. This JSP markup to create this form is quite simple, and is a testament to the power of the Struts 2 UI Tags:

<s:form action="some.action" method="post" theme="%{currentTheme}">
    <s:textfield label="First Name" name="firstName"/>
    <s:textfield label="Last Name" name="lastName"/>

    <s:textfield label="Address 1" name="address1"/>
    <s:textfield label="City" name="city"/>

    <s:textfield label="State" name="state"/>
    <s:textfield label="Zip" name="postalCode"/>

    <s:submit value="Create Party" align="center">
        <s:param name="colspan" value="%{tableColSpan}" />
        <s:param name="align" value="%{'center'}" />
    </s:submit>
</s:form>

As you can see the template contains no HTML markup at all. All of the layout is done by the tags, and the templates that back them. Using these tags you can save an enormous amount of time writing table, tr and td tags. The issue though is that many web applications contain forms that are far more complicated than are accommodated using a two column layout. Sometimes we need to do column spans, row spans, and use more then two columns. Sometimes we need a form that looks like this: This is an eight (8) column layout from a project I'm currently working on called Quadran. An excerpt from the JSP source code:
<s:textfield label="Requested Delivery Date" name="order.dutyPrepaid"> 
    <s:param name="labelcolspan" value="%{2}" /> 
    <s:param name="inputcolspan" value="%{2}" /> 
</s:textfield>
<s:textfield label="Third Party Bill To" name="order.dutyPrepaid"> 
    <s:param name="labelcolspan" value="%{2}" /> 
    <s:param name="inputcolspan" value="%{2}" /> 
</s:textfield>
    
<s:textfield label="Trucker" name="order.dutyPrepaid" size="70"> 
    <s:param name="labelcolspan" value="%{2}" /> 
    <s:param name="inputcolspan" value="%{6}" /> 
</s:textfield>
    
<s:textfield label="Loading Instructions" name="order.dutyPrepaid" size="70"> 
    <s:param name="labelcolspan" value="%{2}" /> 
    <s:param name="inputcolspan" value="%{6}" /> 
</s:textfield>
    
<s:textfield label="Shipping Instructions" name="order.dutyPrepaid" size="70"> 
    <s:param name="labelcolspan" value="%{2}" /> 
    <s:param name="inputcolspan" value="%{6}" /> 
</s:textfield>

S2 Tags Overview

The Struts tags are a powerful set of tags usable in JSP, FreeMarker and Velocity. They are completely integrated into the Struts 2 framework, taking advantage of the ValueStack and the OGNL expression language. Additionally the UI tags are backed by template. This allows the markup they generate to be changed without resorting to editing the Java source files. It's as easy as including your template files on your classpath. Let's start with a simple example. We will examine the template that backs the <s:textfield> tag from the simple theme. (This file can be found in core/src/main/resources/template/simple in the Struts 2 source.)

<input type="text"<#rt/>
 name="${parameters.name?default("")?html}"<#rt/>
<#if parameters.get("size")?exists>
 size="${parameters.get("size")?html}"<#rt/>
</#if>
<#if parameters.maxlength?exists>
 maxlength="${parameters.maxlength?html}"<#rt/>
</#if>
<#if parameters.nameValue?exists>
 value="<@s.property value="parameters.nameValue"/>"<#rt/>
</#if>
<#if parameters.disabled?default(false)>
 disabled="disabled"<#rt/>
</#if>
<#if parameters.readonly?default(false)>
 readonly="readonly"<#rt/>
</#if>
<#if parameters.tabindex?exists>
 tabindex="${parameters.tabindex?html}"<#rt/>
</#if>
<#if parameters.id?exists>
 id="${parameters.id?html}"<#rt/>
</#if>
<#if parameters.cssClass?exists>
 class="${parameters.cssClass?html}"<#rt/>
</#if>
<#if parameters.cssStyle?exists>
 style="${parameters.cssStyle?html}"<#rt/>
</#if>
<#if parameters.title?exists>
 title="${parameters.title?html}"<#rt/>
</#if>
<#include "/${parameters.templateDir}/simple/scripting-events.ftl" />
<#include "/${parameters.templateDir}/simple/common-attributes.ftl" />
/>

This template is written in FreeMarker. It starts by emitting the beginning of an input tag of type text on the first line. Then using #if statements it examines the various possible parameters to the tag and outputs the appropriate HTML. Near the bottom it includes two additional scripts: scripting-events.ftl and common-attributes.ftl for handling scripting and attributes that are common to all HTML tags. This method of building scripts by including others is used pervasively throughout the templates. The parameters that are passed into the tag via attributes are available using the parameters object. We will use this object to access additional parameters to extend the XHTML theme.

Our New Theme

The goal of our new theme is to extend the XHTML theme to support layout of forms using an arbitrary number of columns. The default XHTML theme only support a two column layout, with labels on the left and inputs on the right, each in their own <td>. Our theme will have the following attributes:

The qTableLayout Bean

To specify the configuration of our table layout for our form we need to create a bean prior to the opening <s:form> tag. I have experimented to no avail using the <s:param> tag to parameterize the <s:form>, but have not succeeded. To work around this we simple create a bean holding our table configuration before we start our form.

<s:bean name="java.util.HashMap" id="qTableLayout">
    <s:param name="tablecolspan" value="%{4}" />
</s:bean>

The qTableLayout is a HashMap and holds one property, tablecolspan, which is the number of columns we want our form to use. The sample above would produce a layout using four columns.

Accessing the qTableLayout Bean in FreeMarker

One of the keys to making our theme work is being able to access the qTableLayout bean in our FreeMarker templates, change values contained in it, using it as a means of passing information between our tags. We use it to maintain the state of our table. Particularly the number of columns we have emitted for the current row. To update the qTableLayout bean we use the following in the FreeMarker template:
${stack.setValue('#qTableLayout.currentColumnCount', columnCount)}
This statement accesses the OGNL ValueStack and stores the currentColumnCount in our qTableLayout bean. This allows our theme to maintain state between each invocation of the FreeMarker templates that back the Struts 2 tags.

Table Layout Logic

When creating a new theme it's usually better to start with an existing theme and extend it. For our example we will start with the XHTML theme. To start the new theme you would make a template directory in your WEB-INF/classes directory, then in that one make a directory with the same name as your theme, in our case "qxhtml". Then copy all of the files from the XHTML theme in the Struts 2 distribution into qxhtml to form the basis of our new theme. (NB: You don't need to do all of this. It's already done in the sample app.) With all of our templates in our directory it's time to start hacking. We need to control the emitting of the <tr> tags. These are emitted by default in the XHMTL theme. The first thing we need to do is remove these from the XHTML template. These statements are in the controlheader-core.ftl and controlfooter.ftl templates in the XHTML theme. In qxhtml these have been removed and two new files have been introduced: controlheader-trlogic.ftl and controlfooter-trlogic.ftl.

<#--
    	controlheader-trlogic.ftl

	This template handles:
        * intializing qTable.currentColumnCount if it has not been initialzed,
        * emiting a <tr> tag if the currentColumnCount == 0,
-->
<#if qTableLayout.exists && ! qTableLayout.currentColumnCount?exists >
    <#-- Set the currentColumnCount to 0 because this is the first row of the table. -->
    ${stack.setValue('#qTableLayout.currentColumnCount', 0)}
</#if>
<#-- Do we need to write the opening tr tag. -->
<#if qTableLayout?exists && qTableLayout.tablecolspan?exists >
    <#assign columnCount = qTableLayout.currentColumnCount />
<#else>
    <#-- Set the currentColumnCount to 0 because this is the first row of the table. -->
    ${stack.setValue('#qTableLayout.currentColumnCount', 0)}
    <#assign columnCount = 0 />
</#if>
<#if columnCount == 0>
    <#-- Write out the opening tr tag to start the table row. -->
    <tr><#rt/>
</#if>

As you can see in this listing the qTableLayout bean is used to hold the currentColumnCount, which is used to if we need to emit a <tr> tag when the column count equals zero (0). In the controlfooter-trlogic.ftl template if the current column count is equal to or greater than the qTableLayout.tablecolspan the template will emit our closing <tr> tag.

Using Our New Theme

The qxhtml theme supports more than just doing a multi-column layout. It also supports specifying the number of columns you would like the label and the input to be using <s:param> tags. Here's a quick snippet from our complex example above:

<s:textfield label="Loading Instructions" name="order.dutyPrepaid" size="70"> 
    <s:param name="labelcolspan" value="%{2}" /> 
    <s:param name="inputcolspan" value="%{6}" /> 
</s:textfield>


Inside our <s:textfield> tag we have nested two <s:param> tags, one to specify the number of columns for our label, and the input. This allows us great flexibility in laying out our forms. Out theme also supports simply out putting an input without a label. Just omit the label from your tag:
<s:textfield name="someProperty" />>
This will emit a <td> containing an HTML input only. No label will be generated. This allows you to do tabular inputs very simply as follows:
<s:textfield name="propertyOne" />>
<s:textfield name="propertyTwo" />>
<s:textfield name="propertyThree" />>
<s:textfield name="propertyFour" />>
If you configured your form to have four (4) columns this would result in one row. Wrap this in an <s:iterator> tag and you can quickly create tabular input screens for updating large numbers of records.

The Sample App

The sample application contains one form in form.jsp. Deploy the application and view it. If you've deployed this on your local machine using Tomcat you can go to: http://localhost:8080/struts2themes/. Click the "Standard XHTML Form," "Four Column," and "Six Column" buttons to view the form in two, four and six column layout. Each of these layouts is produced from the exact same markup. The only difference is the a property of the action that sets the number of columns to use. To see a complex form click "Complex Form" in the navigation. This is a subset of the complex form in the screen shot above. The source for the form is:

<%-- Setup the number of columns to be in the table layout for the form. --%>
<s:bean name="java.util.HashMap" id="qTableLayout">
    <s:param name="tablecolspan" value="%{8}" />
</s:bean>
<s:form action="complexForm.action" method="post" theme="qxhtml">
    <s:textfield label="SO Number" name="order.fromPartyOrderNumber"> 
        <s:param name="labelcolspan" value="%{2}" /> 
        <s:param name="inputcolspan" value="%{2}" /> 
    </s:textfield>
    <s:select name="salespersonId" label="Salesperson" list="genericList" listKey="id" listValue="name"> 
        <s:param name="labelcolspan" value="%{2}" /> 
        <s:param name="inputcolspan" value="%{2}" /> 
    </s:select>

    <s:textfield label="Trucker" name="order.dutyPrepaid" size="70"> 
        <s:param name="labelcolspan" value="%{2}" /> 
        <s:param name="inputcolspan" value="%{6}" /> 
    </s:textfield>

    <s:select name="newPoRequired" label="New PO Required" list="genericList"
               listKey="id" listValue="name" />
    <s:select name="shipdateConfirmed" label="Ship Date Confirmed" 
               list="genericList" listKey="id" listValue="name" />
    <s:select name="accounting90EntryDone" label="Acctg Entry Done" 
               list="genericList" listKey="id" listValue="name" />
    <s:select name="factored" label="Factored" list="genericList" listKey="id" 
               listValue="name" />

    <tr><th align="center" colspan="8">Line Items</th></tr>

    <tr>
        <th>#</th>
        <th>Product</th>
        <th>Qty</th>
        <th>Unit Price</th>
        <th>Allocation Instructions</th>
        <th>Label Instructions</th>
        <th>Description</th>
        <th>Override Reason</th>
    </tr>

    <s:iterator value="lineItems" status="status">
        <s:component template="/components/textcell.ftl" value="%{#status.index}" />
        <s:select name="termsId" list="genericList" listKey="id" listValue="name" />
        <s:textfield name="test" size="1"/>
        <s:textfield name="test" size="1"/>
        <s:textfield name="test" size="1"/>
        <s:textfield name="test" size="1"/>
        <s:textfield name="test" size="1"/>
        <s:textfield name="test" size="1"/>
    </s:iterator>

    <s:submit value="Create Sales Order" align="center">
        <s:param name="colspan" value="%{8}" />
        <s:param name="align" value="%{'center'}" />
    </s:submit>
</s:form>

This sample shows the full power of the theme at this point. It uses variable label and input column spans, textfield without labels, and a custom component for outputting text in a table data, but including it in the theme and counting columns so the table rows are started appropriately. (Look at the first tag inside the iterator for the component.) Here's what it looks like:

Future Improvements

This theme is very usable in its current form. There are some things I'd like to add. The most important of these is row spanning. I have some ideas on how to do it, but haven't tackled it. Other improvements could be had with a minor change to the existing Struts 2 tags, but that involved actually digging into the class files, and I'm not ready for that yet. To be honest I've never written a JSP tag. I have asked for some pointers on the Struts users list though. So, we'll see.

Creating a UI Component in Struts 2

Problem

You have a form "element" that consists of several HTML actual elements. You'd like to create these using one Struts 2 UI tag, rather then write the HTML out everywhere it's needed.

Background

The Struts 2 UI tag library provide a component tag, which can be used to create your own "tags" without needing to dive into the JSP tag library API. Creating a tag using the Struts 2 component tag, also allows it to directly take advantage of the Struts 2 framework, such as OGNL support, and the existing Struts 2 UI tag themes.

Recipe

In this recipe we will creating an HTML control using the component tag that will display two input fields. This is a simple example, but it will show the process of creating a component, and tying it into the existing Struts 2 Xhtml theme. For our recipe we will pretend that we are collecting a US zip+4 zip code, using a separate input for the two components of the zip code. Using a component to do this will allow our double input "field" to coexist with the Xhtml theme and use the automatic layout provided by the theme. Unless we created a component to handle this situation, of needing two HTML input elements to be treated as one "component" by the Struts 2 tags, we would have to resort to using the Struts 2 Simple theme and writing our own HTML.

<s:textfield label="City" name="city" />
<s:textfield label="State" name="state" />
<tr>
	<td>Zip+4</td> <!-- Manually outputting our label -->
	<td>
		<s:textfield name="zip" theme="simple" />
		<s:textfield name="plus4" theme="simple" />
	</td>
</tr>

Although this is serviceable, it would be better if we could allow the Struts 2 tags to handle our layout. It simplifies form creation and allows uniform styling to be automatically applied. Also, should a change happen in how zip codes are collected, we would have to revisit every form that has this HTML construct on it, and change it. If we were to replace this with a component, all of our markup for zip+4 would be contained in one place in our code, and could be changed simply by changing our component template.

The Struts 2 UI Xhtml Theme

We will start with the standard Struts 2 Xhtml theme. To control the layout of the table elements that wrap our form elements the Xhtml theme uses two files, controlheader.ftl and controlfooter.ftl. All of the logic for the table elements, arrangement of labels, and presentation of field errors is located in these files. We don't want to re-create these so we will use them as the basis for our component.

The Xhtml Theme text.ftl Template

To create our component we will start with the text.ftl template from the Xhtml theme.

1: <#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
2: <#include "/${parameters.templateDir}/simple/text.ftl" />
3: <#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />

First let's examine this template: As you can see the theme template uses many common templates to create their output and to extend other themes. Throughout the Xhtml theme you will see it including template files from the simple theme to create the actual input element. This allows the Xhtml theme to concentrate on the layout of the form in the table, and the presentation of errors.

Our Component Template

We start with the text.ftl template and simply replace the second line with the content we want. In our case two textfield's. We use the existing Struts 2 textfield UI tag to do this.

<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
<@s.textfield theme="simple" name="${parameters.zipName?default('')}" 
                 value="${parameters.zipValue?default('')}" /> + 
<@s.textfield theme="simple" name="${parameters.plus4Name?default('')}" 
                 value="${parameters.plus4Value?default('')}" />
<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />

Using the existing Struts 2 textfield allows us to leverage the existing tags. This allows a markup to remain highly consistent. Accessing the information passed into our component is done using the parameters variable. Our component will take four values: Let's revisit our example from earlier and use our new tag:

    <s:textfield name="" label="City" />
    <s:textfield name="" label="State" />
    <s:component template="/components/zipplus4field.ftl" label="Zip+4">
        <s:param name="zipName" value="%{'zip'}" />
        <s:param name="zipValue" value="%{zip}" />
        <s:param name="plus4Name" value="%{'plus4'}" />
        <s:param name="plus4Value" value="%{plus4}" />
    </s:component>

All of the boilerplate HTML code is gone. Instead we are left with very clean Struts 2 tags.

Discussion

Using the Struts 2 UI tags and custom components you can encapsulate repetitive HTML patterns. Keeping your HTML mark up isolated in your component templates keeps it all in one place. Should you need to change it you will only have to do this in one place. Also, using UI components and extending the existing themes allows your HTML markup to participate in the Struts 2 themes, freeing you from laying out your forms in tables, or using other layout techniques. To see how it all fits together download the example project.

Integration Testing Struts 2, Spring, and Hibernate JPA

Last night with the help of loraxorg on the Spring Forums I got integration testing working under Maven 2 with Struts 2, Spring, and Hibernate JPA working. This was failing priorly due to a transient dependency in Maven 2 to an old version of Xerces. (See the Spring Forum thread for the solution.) I have not done a lot of test driven development in the past, and personally I don't really get a lot of value out of isolated Unit tests. Integration testing on the other hand I like. Real data, real connections, real functionality, and at the moment for me real failures. I'd rather know now though. One of the main issues in using JUnit for integration testing is that it instantiates a copy of your test class for each test in the class. This guarantees an isolated environment for testing, but present issues with integration testing. The main issue is that you don't want to have to reload your Spring context over and over again. In my case this is painful because Spring also triggers the initialization of my persistence context.

The Code

To overcome this I created a factory class that stores the references to my application context in a static member, and has a static method for getting a handle to the context.
package net.vitarara.quadran.core.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.ApplicationContext;

class SpringContextTestFactory {

        private static final jpaContext
        private static final datasourceContext

        public static ApplicationContext getJpaContext () {
                if (jpaContext == null) {
                        jpaContext = new ClassPathXmlApplicationContext 
                                     ("classpath*:applicationContext.xml");
                }
                return jpaContext
        }

        public static ApplicationContext getDatasourceContext () {
                if (datasourceContext == null) {
                        datasourceContext = new ClassPathXmlApplicationContext 
                                            ("classpath*:test-applicationContext.xml");
                }
                return datasourceContext
        }
}
Notice that is written in Groovy. I'm using Groovy for all of my test cases. The same principles would apply to a factory class written in Java. I have two potential application contexts, a simple one that only has a datasource, and my full one supporting my JPA environment, and all of my Struts 2 action beans, DAO's and service beans. In other words my whole application environment. Here's a sample test of a DAO:
package net.vitarara.quadran.core.data.jpa;

import net.vitarara.quadran.core.data.*;
import net.vitarara.quadran.core.test.SpringContextTestFactory;
import org.springframework.context.ApplicationContext;


class ShipmentDaoITest extends GroovyTestCase {

    void testFindForOutstandingOblReport () {
        def dao = SpringContextTestFactory.getJpaContext().getBean ("shipmentDao");
        def shipments = dao.findForOutstandingOblReport ();
        assertTrue ("Issuficient records returned", shipments.size > 20);
    }

}
I simply use my factory to get a handle to my Spring ApplicationContext, and use it to get a "shipmentDao." Then I can call any methods on it I like, testing the results. Testing a Struts 2 Action is substantially the same.
package net.vitarara.quadran.core.web.shipping

import net.vitarara.quadran.core.test.SpringContextTestFactory;

class ListShipmentsITest extends GroovyTestCase {


    void testFindByOrderNumber () {
        def action = SpringContextTestFactory.getJpaContext().getBean  
                     ("listShipmentsAction");
        def model = new ListShipmentsModel ()
        model.orderNumber = "SI142784"
        action.model = model
        action.execute ()
        assertTrue ("No shipments were found", action.shipments.size > 0)
    }
}
I use my SpringContextTestFactory to get a handle to my ApplicationContext, and get a "listShipmentsAction" bean. The listShipmentsAction beans has a dependency on a ShippingManager service bean, which has a dependency on a ShipmentDao bean, which has a dependency on a JPA EntityManagerFactory. All of these dependencies are injected by Spring, giving me an action I can test against my database. I instantiate a ListShipmentsModel, which holds my query parameters, plug in a value, set the model on the action, and call the action's execute method. Once the action has executed I can check the results any way I'd like. In this case there is a list "shipments" that is a member of the action, I check to be sure that its size is greater than 0.

Configuring Maven 2

To get all of this running you need to: Configuring Maven to compile Groovy files is quite easy. Just add the following to your <build><plugins> section.
<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
        <executions>
            <execution>
                <id>compile</id>
                <phase>compile</phase>
                <configuration>
                    <tasks>
                        <taskdef name="groovyc" 
                                    classname="org.codehaus.groovy.ant.Groovyc">
                            <classpath refid="maven.compile.classpath"/>
                        </taskdef>
                        <mkdir dir="${project.build.outputDirectory}"/>
                        <groovyc destdir="${project.build.outputDirectory}" 
                                    srcdir="${basedir}/src/main/java/" 
                                    listfiles="true">
                            <classpath refid="maven.compile.classpath"/>
                        </groovyc>
                    </tasks>
                </configuration>
                <goals>
                    <goal>run</goal>
                </goals>
            </execution>
            <execution>
                <id>test-compile</id>
                <phase>test-compile</phase>
                <configuration>
                    <tasks>
                        <taskdef name="groovyc" 
                                    classname="org.codehaus.groovy.ant.Groovyc">
                            <classpath refid="maven.compile.classpath"/>
                        </taskdef>
                        <mkdir dir="${project.build.testOutputDirectory}"/>
                        <groovyc destdir="${project.build.testOutputDirectory}" 
                                     srcdir="${basedir}/src/test/java/" 
                                     listfiles="true">
                            <classpath refid="maven.test.classpath"/>
                        </groovyc>
                    </tasks>
                </configuration>
                <goals>
                    <goal>run</goal>
                </goals>
            </execution>
        </executions>
</plugin>
Now we need to create a profile that tells Maven to run our itegration tests.
<profiles>
    <profile>
        <id>itest</id>
        <activation>
            <property>
                <name>itest</name>
            </property>
        </activation>
        <build>  
            <plugins>
                <plugin> 
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>surefire-it</id>
                            <phase>integration-test</phase>
                            <goals>
                                <goal>test</goal>
                            </goals>   
                            <configuration>
                                <excludes>
                                    <exclude>none</exclude>
                                </excludes>
                                <includes>
                                    <include>**/*ITest.java</include>
                                </includes>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>
This profile attaches itself to the integration test phase and only runs test that end in ITest. (I'm not sure why the include uses **/*ITest.java, but it works.) If you already have profiles configured leave off the profiles tags. Then we need to exclude the integration tests from our unit test run. This snipped goes in your <build><plugins> section.
<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <excludes>
            <exclude>**/*ITest.java</exclude>
        </excludes>
    </configuration>
</plugin>
The final issue you need to take care of is speficying the correct xerces dependency. Add the following to your dependencies:
<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.8.1</version>
    <scope>test</scope>
</dependency>
That tells Maven to use Xerces 2.8.1 when running tests. I place my Groovy test files in src/test/java. I don't have a separate directory for them. You could do that by configuring the Groovy compilation to look elsewhere very easily. I haven't done it because all of my tests are in Groovy, and well, I'm lazy.

Post and Redirect in Struts 2

Redirecting a user of a web application after submitting an HTTP POST is a common pattern. A common use case is to redirect to a display page after a user has created something, such as a purchase order or sales order. This post and redirect pattern is supported by Struts 2. The means of doing this wasn't obvious to me, but some reading and searching turned up the answer. There are some examples around for doing a redirect using static parameters, but that doesn't help when you want to redirect someone say to display the order they just placed on your website. Redirects in Struts 2 can use static or dynamic parameters. Here's a simple static redirect:
<action name="createSalesOrderConfirmation" class="sales.CreateSalesOrderAction">
    <result name="redirect" type="redirect-action">
        <param name="actionName">displaySalesOrder</param>
        <param name="namespace">/order/sales</param>
    </result>
</action>
This is fairly straight forward. The type of the result is "redirect-action". You set parameters on the result using the param tags. In this case you set the actionName to displaySalesOrder, and the namespace to "/order/sales".

Dynamic Parameters for Redirects

Struts 2 supports passing dynamic parameters to a redirect, such as the id of a newly created entity, so you can display it. The action-redirect result takes several parameters to help with this, which will not be parsed: To pass dynamic parameters to a redirect-action result you at a minimum you need to set "parse" to true. As follows:
<action name="createSalesOrderConfirmation" class="sales.CreateSalesOrderAction">
    <result name="redirect" type="redirect-action">
        <param name="actionName">displaySalesOrder</param>
        <param name="namespace">/order/sales</param>
        <param name="parse">true</param>
        <param name="id">${order.id}</param>
    </result>
</action>

In this redirect-action result we've added two parameters using param tags. The parse parameter tells Struts 2 to parse any additional parameters using the OGNL expression language. The "id" parameter tells Struts 2 to add this as a parameter to the next action by evaluating the OGNL statement against the current value stack. In this case my current action, not the one I'm forward to, has an order property, which has an id property. This statement will add the value of this property to the redirect resulting in a forwarding URL like this:
http://www.mydomain.com/mycontext/order/sales/displaySalesOrder.action?id=123
You can set additional parameters on the redirect, and have them encoded using the "encode" parameter, or set the method using the "method" parameter.

Updating a List of Domain Entities in Struts 2

I've been working on Quadran a lot, and I'm creating pages for editing lists of entities. The CRUD example from the Struts 2 Showcase application does this in a very simple manner. It recreates all of the entities every time you update the list. That's fine for an example but unusable in real life. In real life we have to present entities from our database and then put the values back into the same entities, and update our database. We can't just re-create them.

The Entity

So, we'll start with a simple domain object and assume that we're using something like JPA or Hibernate to persist it via a Data Access Object (DAO), and that it contains a property called "id".
public class MyEntity {
	private String id, value;

	public String getId () { return id; }
	public void setId (String in) { id = in; }

	public String getValue () { return value; }
	public void setValue (String in) { value = in; }
}
This is a simple JavaBean that contains two properties id and value.

Our Struts 2 Action Class and JSP

In our action we will have a List and a Map. The map is the key to mapping the values back to our beans. Our action looks like this:

public class EditMyEntitiesAction extends ActionSupport implements Preparable {
	
	// Service Beans
	MyEntityDao myEntityDao = new MyEntityDao (); // A data access object for managing MyEntity objects.

	// Model Beans
	List<MyEntity> myEntities;
	Map<String,MyEntity> myEntitiesMap;

	public void prepare () {
		// Get the List of MyEntity objects from the datastore.
		this.setMyEntities (myEntityDao.findAll () );

		// Create a Map using this.myEntities as the basis for it keyed on myEntity.id.
		Map<String,MyEntity> this.myEntitiesMap = new HashMap ();
		for (MyEntity myEntity : this.getMyEntities () ) {
			this.myEntitiesMap.put (myEntity.getId (), myEntity);
		}		
	}

	public String execute () throws Exception {
		// Iterate over the List of MyEntity objects and persist them using our DAO
		for (MyEntity myEntity : this.getMyEntities () ) {
			this.myEntityDao.updateDatabase (myEntity);
		}		
	}


	/* Accessors */

	public void setMyEntities (List<MyEntity> in) {
		this.myEntities = in;
	}

	public List<MyEntity> getMyEntities () {
		return this.myEntities;
	}

	public Map<String,MyEntity> getMyEntitiesMap () {
		return this.myEntitiesMap;
	}
}
That's all there is to the action. In the prepare we get the List of MyEntity objects and then put them into a map keyed on MyEntity.id. Pretty straight forward. The Map is the key to the whole process. We will use the OGNL EL notation to access that Map and fill the values back into it when a user submits the form. Here's the pertinent section of the JSP:

<s:iterator value="myEntities">
    <s:textfield name="myEntitiesMap['%{id}'].value" value="%{value}" />
</s:iterator>

How OGNL Fills in our Domain Objects

In this we iterate over the myEntities List. On the textfield tag we set the name to "myEntitiesMap['%{id}'].value", this would result in something that looks like "myEntitiesMap['1'].value". When the user submits the form Struts2 will evaluate this name as so:
ExpressionResult
myEntitiesMapThis will call getMyEntitiesMap() on our EditMyEntitiesAction.
['1']This will call get("1") on the Map that was returned by getMyEntitiesMap(), which will return a MyEntity object.
.valueWill call setValue() on the MyEntity object returned previously. Setting the value of the property to the value that was submitted by our user.
Basically myEntitiesMap['1'].value results in: EditMyEntitiesAction.getMyEntitiesMap().get ("1").setValue (<our user submitted value>). It took me a while to figure out how to do this. I was struggling over how to get the values back into the "List" of entities in my action, then I hit on the idea of putting them into a Map keyed on the id of the entities, and voila, it all fits together.

What's Not Here

This is by no means an enterprise ready update mechanism. The primary things I've left out is validation. This can be added by implementing a validate() method in our Action. Best practice would be to delegate that validation to some other bean responsible for the management of MyEntity objects.

Using a Conversation Scope in Struts 2

What is a conversation scope?

A conversation scope fits between a Session scope and a Request scope in J2EE terms. An object in a session is specific to a particular user of a web app. If you place an object in the users session it will be available on every page hit the user makes. A conversation scope defines a long lived set of data that is specific to a process, such as configuring a product, or filling out a customers personal and credit information. It differs from a session scope in that one user should be able to have multiple of th same type of conversation at the same time. You might actually have to help more than one customer at a time, or configure multiple products, one on each tab in your web browser.

Does Struts 2 Support This?

Not directly. I have written an Interceptor that implements a Conversation Scope for possible inclusion in Struts 2 in the future. We'll see what happens. In the mean time I've created an example, including the supporting classes.

How Does it Work?

This extension to Struts 2 consists of two classes, an Interceptor and an Interface for your Actions to implement. That's it. The Interceptor does most of the heavy lifting. It creates new conversation id's. Marshals the data from the users conversation scope into your Action, and cleans up when you mark the conversation complete. The interface consists of only a few methods:
package org.apache.struts2.interceptor;

public interface ConversationScopeAware {

    public static final String S2_CONVERSATION_SCOPE = "S2_CONVERSATION_SCOPE";
    public static final String S2_CONVERSATION_ID = "S2_CONVERSATION_ID";
    public static final String S2_VALUE_STACK_MODEL_KEY = "s2cmodel";
    public static final String S2_VALUE_STACK_MODEL_ID_KEY = "modelid";

    /** Get the id of the current conversation the action is handling. */
    public String getConversationId ();

    /** Set the id of the current conversation the action is handling. */
    public void setConversationId (String in);

    /** Get the conversation model. */
    public Object getConversationModel ();

    /** Set the conversation model. */
    public void setConversationModel (Object in);

    /** 
     * Prepare the conversationModel. So it can be saved in the conversationScope and
     * pushed onto the top of the value stack. The action needs to maintain a reference
     * to the prepared model.
     */
     public Object prepareConversationModel ();

     /** 
      * Find out if the conversation is finished. If true the conversation model can 
      * be removed from the conversationScope. 
      */
     public boolean isConversationFinished ();
}
The most important concept to grasp is the conversationModel. This is very similar to the ModelDriven actions. Basically you have some Object that represents the data you want to collect and process as you have a conversation with your user. Your model object can be almost anything, including your rich domain objects. I would discourage you from using a Map though. When Struts 2 receives a request for a ConversationScopeAware action it will check to see if there is a stored conversation using the conversation id. If there is no conversation it will ask the Action to prepare the conversation model by calling ConversationScopeAware#prepareConversationModel(). This is your chance to setup your data model that you will fill in over your conversation. Once you have prepared your model the interceptor will push it onto the top of the stack, so the properties can be filled in with the user's parameters. In your view you will need to include the conversation id in a hidden field of your form: <s:hidden name="S2_CONVERSATION_ID" value="%{conversationId}" /> Once you have finished with the conversation you can mark it for removal from the users conversation scope. After running the action the interceptor will call isConversationFinished(). If this returns true it will dispose of the saved conversation model.

An Example

Attached to this post is a Maven project, which demonstrates the use of a conversation. Download it and build it using: mvn package. This will create a war file under the target directory. Deploy that to your favorite servlet container and point your browser at it (ex: http://localhost:8080/tutorial/). You will be prompted to enter your name, and click the next button. Also at the bottom there is a link to start another conversation. You can have as many conversations going as you like. The data for each of them is independent. Take a look at src/main/java/tutorial/ConversationAction.java to see how it all works. In short you have a simple Action, which includes an inner class to store its data called ConversationModel. It instantiates a copy of ConversationModel when prepareConversationModel() is called. The Interceptor stores it transparently for the Action. On subsequent hits the model will already be injected into the action by the Interceptor allowing the Action to act on any data that has been previously entered by the user. The example takes the user through a few steps using logic in the execute() method, eventually sending the result page which displays all of the collected data.

What's Missing?

This example doesn't show use of the prepare() method, nor the validate() method in conjunction with our conversation scope. You can use the prepare() to add data to your conversation model as the user fills out forms, and you can use th validate() to validate each screen the user submits.