InfoQ

InfoQ

Article

My Bookmarks

Login or Register to enable bookmarks for unlimited time.

The content has been bookmarked!

There was an error bookmarking this content! Please retry.

Migrating Struts Apps to Struts 2

Posted by Ian Roughley on Sep 19, 2006

Sections
Process & Practices,
Development
Topics
Web Frameworks ,
Change ,
Java
Tags
Struts ,
migration

Most people are familiar with Struts, whether it is from direct experience or from reading articles or books. In this series of articles we will cover the features of Struts2 from a Struts perspective - by migrating a simple application.

Before we start the migration process, a little background to Struts2 is needed. The first part of this article will introduce Struts2, along with some of the core architectural differences that will help to conceptually put everything together. The second part will cover migrating the back-end - an in-depth look at the differences between actions; action related framework features; and action configuration. The final part of this article will address the user interface. We'll cover the architecture; talk about UI components, themes and tags; and put a new face on our application.

It is not my intent to cover every migration scenario available, but rather to introduce the concepts and new features available in Struts2 by starting from a common starting point. Armed with this knowledge, migrating an application of any size should be a piece of cake!

Introduction / History

The first version of Struts was released in June 2001. It was born out of the idea that JSPs and servlets could be used together to provide a clean separation between the view and the business or application logic of a web application. Before Struts, the most common options were to add business and application logic to the JSP, or to render the view from servlets using println() statements.

Since its release, Struts has become the de-facto standard for web application. With this popularity have come enhancements and changes - both to keep up with the ever-changing requirements for a web application framework, but also to match features with the ever-increasing number of competing frameworks available.

To that end, there have been several proposals for the next generation of Struts. The two alternatives that have become the most cohesive in the past year are Shale and Struts Ti. Shale is a component based framework, and just recently has become its own top-level Apache project, where Struts Ti continues the front controller or model-view-controller pattern that has made Struts so successful.

The WebWork project was started as a Struts revolution - as a fork of the Struts code to introduce new ideas, concepts and functionality that may not be compatible with the original Struts code - and it was first released in March 2002. WebWork is a mature framework, having undergone several minor and major releases.

In December 2005 it was announced that WebWork and the Struts Ti would join forces. Since that time, Struts Ti has become Struts Action Framework 2.0, and the successor to Struts.

Finally, it should be noted that neither the Struts nor WebWork projects are going away. While interest is high, and willing developers are available, both of these projects will continue - all the while having bugs fixed, and adding enhancements and new features.

A Request Walk-through

Before we start looking at the low level details of how to convert an application from Struts to Struts2, let's take a look at what the new architecture looks like by walking through the request processing.

As we walk through the request lifecycle you should notice one important fact - Struts2 is still a front controller framework. All of the concepts that you are familiar with will still apply.

This means:

  • Actions will still be invoked via URL's
  • Data is still sent to the server via the URL request parameters and form parameters
  •  
  • All those Servlet objects (request, response, session, etc.) are all still available to the Action

From a high-level overview, this is how the request is processed:

The processing of a request can be broken into these 6 steps:

  1. A request is made and processed by the framework - the framework matches the request to a configuration so that the interceptors, action class and results to use are known.
  2. The request passes through a series of interceptors - interceptors, and interceptor stacks, can be configured at a number of different levels for the request. They provide pre-processing for the request as well as cross-cutting application features. This is similar to the Struts RequestProcessor class which uses the Jakarta Commons Chain component.
  3. The Action is invoked - a new instance of the action class is created and the method that is providing the logic for this request is invoked. We will discuss this in more detail in the second part of this series; however, in Struts2 the configuration of the action can specify the method of the action class to be invoked for this request.
  4. The Result is invoked - the result class that matches the return from processing the actions' method is obtained, a new instance created and invoked. One possible outcome of the result being processed is rendering of a UI template (but not the only one) to produce HTML. If this is the case, then Struts2 tags in the template can reach back into the action to obtain values to be rendered.
  5. The request returns through the Interceptors - the request passes back through the interceptors in reverse order, allowing any clean-up or additional processing to be performed.
  6. The response is returned to the user - the last step is to return control back to the servlet engine. The most common outcome is that HTML is rendered to the user, but it may also be that specific HTTP headers are returned or a HTTP redirect is invoked.

As you may have noticed, there are some differences. The most obvious one is that Struts2 is a pull-MVC architecture. What does this mean? From a developers perspective it means that data that needs to be displayed to the user can be pulled from the Action. This differs from Struts, where data is expected to be present in beans in either the HTTP page, request or session scopes. There are other places that data can be pulled from, and we'll talk about those as the scenarios come up.

Configuring the framework

The first, and most important configuration, is the one that enables the web application framework within the servlet containers web.xml file.

The configuration that everyone should be familiar with for Struts is:

    <servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

For Struts2 there are very few changes. The most significant is that the dispatcher has been changed from a servlet to a servlet filter. The configuration is just as easy as for a servlet, and shown here:

    <filter>
<filter-name>webwork</filter-name>
<filter-class>
org.apache.struts.action2.dispatcher.FilterDispatcher
</filter-class>
</filter>

<filter-mapping>
<filter-name>webwork</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Similar to the servlet configuration, the filter configuration defines a name (for reference) and the class of the filter. A filter mapping links the name with the URI pattern that will invoke the filter. By default, the extension is ".action". This is defined in the default.properties file (within the Struts2 JAR file) as the "struts.action.extension" property.

SIDEBAR: The "default.properties" file is the place that many configuration options are defined. By including a file with the name "struts.properties" in the classpath of your web application, with different values for the properties, you can override the default configuration.

For Struts, the servlet configuration provides an init-param tag that defines the names of the files used to configure Struts. Struts2 does not have such a configuration parameter. Instead, the default configuration file for Struts2 has the name "struts.xml" and needs to be on the classpath of the web application.

SIDEBAR/TIP: Since there is a namespace separation between the Struts actions (with a ".do" extension) and the Struts2 actions (with a ".action") extension, there is no reason why they cannot co-exist within the same web application. This is a great way to start the migration process - add the necessary configuration, and start developing all new functionality in Struts2. As time and resources permit, the remaining actions can be converted. Or, the two frameworks can co-exist peacefully forever, since there is no reason that the existing action ever needs to be migrated. Another migration strategy is to update only the actions by changing the Struts2 extension to ".do". This allows the existing JSP's to remain the same and be re-used.

Deconstructing the Actions

In the request walk-through we spoke about some of the differences between Struts and Struts2 from a high level. Let's take it a step deeper now, and look at the differences between the structures of the actions in each framework.

Let's first review the general structure of the Struts action. The general form of the Struts action looks like this:

public class MyAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
// do the work
return (mapping.findForward("success"));
}
}

When implementing a Struts action, you need to be aware of the following items:

  1. All actions have to extend the Action base class.
  2. All actions have to be thread-safe, as only a single action instance is created.
  3. Because the actions have to be thread-safe, all the objects that may be needed in the processing of the action are passed in the method signature.
  4. The name of the method that is invoked for the processing of the action is "execute" (there is a DispatchAction class available in Struts which can re-route the method to be executed to another method in the same action, however the initial entry point from the framework into the action is still the "execute" method).
  5. An ActionForward result is returned using a method from the ActionMapping class, most commonly via the "findForward" method call.

In contrast, the Struts2 action provides a much simpler implementation. Here's what it looks like:

public class MyAction {
public String execute() throws Exception {
// do the work
return "success";
}
}

The first thing you may have noticed is that the action doesn't extend any classes or interfaces. In fact, it goes further than this. By convention, the method invoked in the processing of an action is the "execute" method - but it doesn't have to be. Any method that follows the method signature public String methodName() can be invoked through configuration.

Next, the return object is a String. If you don't like the idea of string literals in your code, there is a helper interface Action available that provides the common results of "success", "none", "error", "input" and "login" as constants.

Finally, and perhaps the most revolutionary difference from the original Struts implementation, is that the method invoked in the processing of an action (the "execute" method) has no parameter. So how do you get access to the objects that you need to work with? The answer lies in the "inversion of control" or "dependency injection" pattern (for more information Martin Fowler has an informative article at http://www.martinfowler.com/articles/injection.html). The Spring Framework has popularized this pattern, however, the predecessor to Struts2 (WebWork) started using the pattern around the same time.

To understand the inversion of control better, let's look at an example where the processing of the action requires access to the current requests HttpServerRequest object.

The dependency injection mechanism used in this example is interface injection. As the name implies, with interface injection there is an interface that needs to be implemented. This interface contains setters, which in turn are used to provide data to the action. In our example we are using the ServletRequestAware interface, here it is:

public interface ServletRequestAware {
public void setServletRequest(HttpServletRequest request);
}

When we implement this interface, our simple action from above becomes a little more complex - but now we have a HttpServerRequest object to use.

public class MyAction implements ServletRequestAware {
private HttpServletRequest request;
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
public String execute() throws Exception {
// do the work using the request
return Action.SUCCESS;
}
}

At this point, some alarm bells are probably going off. There are now class level attributes in the action - which, although not thread-safe, is actually okay. In Struts2, an action instance is created for each request. It's not shared and it's discarded after the request has been completed.

There is one last step left, and that is to associate the ServletConfigInterceptor interceptor with this action. This interceptor provides the functionality to obtain the HttpServletRequest and inject it into actions that implement the ServletRequestAware interface. For the moment, don't worry about the details of the configuration - we'll go into much more detail in the next article. The important thing at the moment is to understand that the interceptor and the interface work hand-in-hand to provide the dependency injection to the action.

The benefit to this design is that the action is completely de-coupled from the framework. The action becomes a simple POJO that can also be used outside of the framework. And for those that encourage unit testing, testing a Struts2 action is going to be significantly easier than wrestling to get a Struts action into a StrutsTestCase or a MockStrutsTestCase unit test.

Conclusion / Wrap-Up

By now you should be familiar with the basics of Struts2 - the high level architecture and basic request workflow. You should be able to configure Struts2 in a servlet container, and know the differences between the action for Struts and Struts2.

In the next article we will introduce the example application that will be migrated, as well as building on the knowledge attained here to migrate the example applications' actions from Struts to Struts2. What we'll end up with is a working application using JSTL, JSP and Struts2. We'll also further investigate the differences between actions; configuration of actions and other framework elements; and talk more about the action related framework features.

About the author

Ian Roughley is a speaker, writer and independent consultant based out of Boston, MA. For over 10 years he has been providing architecture, development, process improvement and mentoring services to clients ranging in size from fortune 10 companies to start-ups. Focused on a pragmatic and results-based approach, he is a proponent for open source, as well as process and quality improvements through agile development techniques.

16 comments

Watch Thread Reply

One typo? by Wendong Li Posted
Re: One typo? by Ian Roughley Posted
Re: One typo? by Ian Roughley Posted
I dont like the idea of Action helper interface by karan malhi Posted
Re: I dont like the idea of Action helper interface by Ian Roughley Posted
Re: I dont like the idea of Action helper interface by karan malhi Posted
Re: I dont like the idea of Action helper interface by Pete the Wheat Posted
Re: I dont like the idea of Action helper interface by Nathan Hughes Posted
Re: I dont like the idea of Action helper interface by Mikel Masquefa Posted
Re: I dont like the idea of Action helper interface by Edward Song Posted
Example by Sudip Kundu Posted
Inject things into actions by Thai Dang Vu Posted
Re: Inject things into actions by Ian Roughley Posted
How to Send form data to DAO Layer. by Rajagopal Y Posted
some doubts by K Sathya Narayanan Posted
Re: some doubts by Den hoss Posted
  1. Back to top

    One typo?

    by Wendong Li

    December 2002 -> December 2005

  2. Back to top

    I dont like the idea of Action helper interface

    by karan malhi

    If you don't like the idea of string literals in your code, there is a helper interface Action available that provides the common results of "success", "none", "error", "input" and "login" as constants.


    If I dont like the idea of string literals, then I would create my own helper interface. In fact, I dont like the idea of getting a helper interface just for some constants, which I may not even use. This is a domain specific thing and its place is in a domain specific model , rather than a framework.

  3. Back to top

    Re: One typo?

    by Ian Roughley

    yes - you're right.

  4. Back to top

    Re: I dont like the idea of Action helper interface

    by Ian Roughley

    I tend to disagree, but this is your choice. I would never place the results for an action call in a domain object, it just doesn't belong there. It has nothing to do with the domain in question, but rather what happened during the processing of an action, and what is the next step in the flow of processing actions / views.

  5. Back to top

    Re: One typo?

    by Ian Roughley

    Actually, I was wrong in my comment, and the article is correct. WebWork was forked in March 2002 and in December 2005 is was announced that Struts and WebWork would join forces.

  6. Back to top

    Re: I dont like the idea of Action helper interface

    by karan malhi

    What I meant was, that in my application, I may not have the notion of success or login etc. These terms are more application specific rather than framework specific. Just choosing a bunch of terms and adding them to the framework doesnt make sense to me. I think the choice of terminology and its interpretation is totally related to the domain/application in question

  7. Back to top

    Re: I dont like the idea of Action helper interface

    by Pete the Wheat

    Shouldn't "org.apache.struts.action2.dispatcher.FilterDispatcher" be "org.apache.struts2.dispatcher.FilterDispatcher"?

  8. Back to top

    Example

    by Sudip Kundu

    Can Anyone send a simple application developed with struts 2 ?

  9. Back to top

    Re: I dont like the idea of Action helper interface

    by Nathan Hughes

    so where you work, 'success' is not an option?

  10. Back to top

    Re: I dont like the idea of Action helper interface

    by Mikel Masquefa

    I agree with Karan's comment: the choice of terminology and its interpretation is totally related to the domain/application.

    My reason is very simple: many applications are developed by teams from countries who speak languages different from English and that don't want use english's words to determine webflow concepts.

    For example, instead of using the word 'success' I could want to use the word 'exito', spanish, or 'sucesso', portuguesse.

  11. Back to top

    Inject things into actions

    by Thai Dang Vu

    If we can inject the HttpServletRequest into an action, can we inject other things (e.g. a Spring bean)? The reason I ask this question is that I'm thinking of declaring a service bean in Spring which is bounded in a transaction (this feature is provided by Spring), then I have this service when I am in this action (no need to use <code>applicationContext.getBean("my service");</code>)

  12. Back to top

    Re: Inject things into actions

    by Ian Roughley

    yes - in fact spring injection come as a plugin to the framework.

  13. Back to top

    How to Send form data to DAO Layer.

    by Rajagopal Y

    Hi,
    I Just started workign with Struts2.
    Here is my doubt.

    Assume that i am developing a loing application where user enters username and password, i have the setter/getter methods in my action for username& password.

    Form action i have to invoke the Service/DAO method, which takes a Value Object as paramater, which contains username& password.

    Here is few Questions:

    => Why can't we have a seperate bean for form properties and map it to the action class.
    => If the properties are defined in Action class, what is the right place to create the Value object (in my example with username& password).

    Any Suggestions....

  14. Back to top

    some doubts

    by K Sathya Narayanan

    hi
    i have a jsp named "displayEmployeeRecords.jsp"

    which should display the list of employee details like name , empid , salary

    i have implemeted this in struts1.2.

    i have implemented the action class and other xml files .


    i have a Arraylist object which contains a list of EmployeeModel object

    1)if Arraylist is empty then the action class should be called
    to populate the ArrayList
    else the ArrayList should be iterated to display its content
    2)tell me how to display this using struts2.0

    i have done this in struts 1.2 but i dont know how to call a Action class

    in Struts1.2-> /EmployeeData.do -> will call the Action class
    in Strut22.0->?

    in struts 1.2 -> logic:iterate to iterate the ArrayList and display the data
    in strut2.0->?

  15. Back to top

    Re: I dont like the idea of Action helper interface

    by Edward Song

    The idea of convention over configuration, I think is what is to be interpreted here, rather than the exact choice of string literals chosen for success and forward. In most conventions, actions have one of two results, success or failure. Providing "success" and "failure" as conventional string literal forwarding terms is just a convention over configuration feature, and can be overrided anyway by your choice of terminology.

  16. Back to top

    Re: some doubts

    by Den hoss

    Struts2: /EmployeeData.action, <s:iterator></s:iterator>

Educational Content

10 tips on how to prevent business value risk

One category of risk that project teams need to ensure they address is business value failure – delivering a product that fails to provide value for the business investor.

Interview: Software Systems Architecture: Working With Stakeholders Using Viewpoints and Perspectives

InfoQ spoke to the authors of Software Systems Architecture on a couple of new topics, the System Context viewpoint and Agile, which have been added to the second edition.

Beauty Is in the Eye of the Beholder

Alex Papadimoulis discusses ugly code, where it comes from, how to avoid it, and how to get rid of it.

Architecting Visa for Massive Scale and Continuous Innovation

John Davies examines Visa’s architecture and shows how enterprises have architected complex integrations incorporating Hadoop, memcached, Ruby on Rails, and others to deliver innovative solutions.

Max Protect: Scalability and Caching at ESPN.com

Sean Comerford unveils ESPN.com’s architecture, what components are used and why, and the current changes the website goes through.

The Seven Deadly Sins of Enterprise Agile Adoption

Are there repeated patterns of failure on Enterprise Agile Enablement efforts? Sanjiv and Arlen discuss Seven Deadly Sins to avoid when adopting Agile in an enterprise.

Questions for an Enterprise Architect

Erik Dörnenburg answers: What is Enterprise and Evolutionary Architecture?, discussing 4 issues: Turning strategy into execution, Ensuring conformance, Where do the architects sit? Buying or building?

Wrap Your SQL Head Around Riak MapReduce

Sean Cribbs explains what Map-Reduce and Riak are, why and how to use Map-Reduce with Riak, and how to convert SQL queries into their Map-Reduce equivalents.