Wednesday, September 22, 2010

Struts2 Overview

What is Struts2?

Struts2 is a MVC (model-view-controller) web application framework. It has a simple goal – make web development easier for developers. Struts2 aims at providing increased productivity through reduced XML configuration, smart conventions, and a modular and loosely-coupled architecture.

Originally started as WebWork, Struts 2 was designed to address several perceived deficiencies with Struts1. Struts1 was to tightly tied to the servlet specification and contained many Struts 1-specific constructs. Struts 2 takes advantage of the many lessons learned to present a cleaner implementation of MVC.

Features and Benefits of Using Struts2:

  • Action based framework
  • Mature with a vibrant developer and user community
  • Annotation and XML configuration options
  • POJO-based actions that are easy to test
  • Spring, SiteMesh and Tiles integration
  • OGNL expression language integration
  • Themes based tag libraries and Ajax tags
  • Multiple view options (JSP, Freemarker, Velocity and XSLT)
  • Plug-ins to extend and modify framework features

Struts2 Configuration

The majority (if not all) of the struts2 configuration should done using the struts.xml. Another option is to include a struts.properties file. However, it is not recommend when developing new applications. The struts.properties file is provided for backward-compatibility with WebWork. The struts.xml file needs to be located in the root of the classpath

The struts.xml file will contain the configuration for actions, interceptors, packages, namespaces, results and some validation. It can also be used to set Struts2 specific properties like the devMode. The alternative to configuring Struts2 with the struts.xml file is to use annotations. I prefer to the xml file approach over annotations since our entire configuration is kept in a single location not spread across several (maybe hundreds) classes. I also like to keep configuration details out of classes.

When defining configuration elements (like actions) in the struts.xml file it is important to think about grouping them into packages and namespaces. Packages and namespaces help group and classify various configuration elements, delineate areas of responsibility and provide package-specific resources. They help draw destinations between different sections of an application. For example, admin operations should have their own package and namespace separate from the other application operations.

Title, label, error and all other messages that need to be displayed to the end user should be built in the package.properties file (usually located in the action package). Package.properties is simple properties file that holds messages (and keys) in a single, common location for the entire application. Messages can be easily retrieved or throughout the entire application. Maintenance is reduced by having everything in a common location.

Actions

Actions are the basic building block the Struts2 framework (as well many other MVC frameworks). Each URL is mapped to a specific action, which provides the processing logic necessary to service the request from the user. They are the most basic unit of work that can be

associated with a HTTP request coming from a user.

In Struts 2 actions are POJOs (Plain Old Java Objects) and an object instance is created for every new request. This is a different from Struts 1 where actions are singletons and only one instance of the actions class is used to handle all requests. POJOs increases testability, reduces coupling in the framework and HTML form field data is converted to proper types for the action to use.

Much of the functionality that actions need is provided through a combination of interface implementations and interceptors (we’ll get more information on interceptors later). Most (if not all) of our actions should extend the ActionSupport class. ActionSupport is a utility class that implements the most commonly used interfaces (Action, Validateable, ValidationAware, TextProvider, Localprovider and Serializable.)

Since the bulk of the applications functionality should reside in service classes our actions are where the service operations are instantiated and invoked. Generally, actions should be kept highly cohesive. Meaning that each action should serve a single, well focused purpose. They should provide a single unit of work for a request. However, you can have actions with several methods that can be invoked separately.

Several actions may be built as “Model Driven” actions. Model driven actions implement the ModelDriven interface and provide access to domain objects. Struts will then populate the fields of this object with the request parameters, and this object will be placed on top of the stack once the action is executed. Validation will also be performed on this model object, instead of the action. See http://struts.apache.org/2.1.8/docs/model-driven.html for more information.

Interceptors

Interceptors are another of the core components that makes up a Struts2. The bulk of core framework functionally comes from interceptors. They provide common crosscutting functionality and features to be applied to actions in a constant and convenient manner, without the need of adding code in each and every action. Working very similar to Servlet Filters, interceptors provide a simple way to add processing logic around method calls in an action.

Interceptors are grouped into collections called “Interceptor Stacks”. Struts2 provides several pre-configured stacks for performing common application tasks. However, you can also customize and configure your own stacks. Either stacks or individual interceptors can be configured by action or by package. Configuring what interceptor an actor or package should use is done in the struts.xml.

All packages and actions configuration should include the defaultStack or paramPrepareParamsStack provided with Struts 2. The defaultStack contains interceptors for exceptions, servletConfiguration, params, debugging, modelDriven, validation and many others. The paramPrepareParamsStack is very similar to the defaultStack except it does not contain interceptors for debugging and profiling. Another important difference between the two stacks is that the paramPrepareParamsStack includes an additional params interceptor before the prepare interceptor (if action is preparable.) In the defaultStack the params interceptor is called after the prepare interceptor. What does this all mean? If a parameter from the UI is needed for the prepare method to execute properly it will fail if the defaultStack is used because the parameters are set after the prepare call. Just be ware of the difference.

Several other interceptors may be used for specific areas of the application. For example, the roles interceptor may be used for admin type functionality, clearSession interception for logout operation.

Since interceptions are such an important concept in Struts 2 it is important to know what interceptors are available and what they are used for. See http://struts.apache.org/2.x/docs/interceptors.html for a list of all framework interceptors and their functions.

User Interface

Struts2 Tag Library

When developing a UI (User Interface) with JSPs, tag libraries should be used. Tag libraries are nothing new to Java. They provide an easy, uniform way to render information to the user while minimizing the simple, repetitive programming that usually happens with UI development. Tag libraries help with maintainability by keeping the logic encapsulated, and reducing the temptation of cutting and pasting code.

Struts2 provides a rich tag library that is very similar to JSTL (JavaServer Pages Standard Tag Library) except it has a tight integration with the framework. It provides the intersection between actions and views, allowing dynamic information from actions to be rendered as well as making rendering decisions on the information to display at runtime. Tags can also access action methods and can use OGNL to evaluate expressions. See http://www.struts2.net/reference.htm

for more information on Struts2 tags.

OGNL (Object-Graph Navigation Language)

OGNL is open-source EL (Expression Language) that Struts2 uses (In the future Struts2 will allow for other expression languages to be plugged in instead). It provides a mechanism to navigate object graphs using dot notation and evaluate expressions, including calling methods on the objects being retrieved. OGNL can be a very valuable tool in Struts2. See

http://www.opensymphony.com/ognl/ for more information.

SiteMesh

SiteMesh is a templating technology (similar to Apache Tiles) that is used to construct a common look and feel for an entire application. It uses a decorator design pattern to establish HTML with additional HTML provided from a secondary file. In other words, SiteMesh builds an HTML template for a page and then decorates additional HTML to that template. See http://www.opensymphony.com/sitemesh/ for more information.

Struts2 Validation Configuration

Input validation is a very important part of every application. This is no different for Struts2 applications. Validation helps us ensure that only appropriate data is passed to our actions. Like most of the configuration within Struts 2, validation can be done either through XML or annotations. I would recommend taking the XML approach for the same reasons stated in the Struts2 configuration section.

Any action class that extends ActionSupport or implements the ValidationAware interface can easily tie into the Struts2 validation framework. Action validation configuration can either be done in the struts.xml file or in individual action validation XML files (located in the same package as the action). I recommend using the individual action validation files in order to minimize the size and complexity of the struts.xml file. An action validation file has the same name as the action but with “-validation.xml” appended on the end. For example, if we have an action class called ILikeBaconAction.java then we use a validation file called ILikeBaconAction-validation.xml. Within the validation XML file, field and action validation rules are configured by building validators and setting their validation types and properties. See http://struts.apache.org/2.x/docs/validation.html for a full list of validation types and what can be done within Struts2 validation.

The validation XML files can handle the majority of the validation rules for actions. However, there are situations where the business rules are too complex and the XML configuration gets complicated and unreadable. When this situation occurs a no argument validate method can be added to the action. If the action extends ActionSupport or implements the ValidationAware interface the validate method will be automatically invoked when the actions is called. Within the validate method the validation rules can then be coded in pure Java and error messages can be added to the action.

References / Helpful Links:

Struts2 Home: http://struts.apache.org/2.1.8/index.html

Struts2 Wiki: http://cwiki.apache.org/WW/home.html

Struts2 FAQ: http://struts.apache.org/2.0.14/docs/faqs.html

Free Struts2 Book: http://www.infoq.com/minibooks/starting-struts2

Struts 1 vs. Struts2 http://struts.apache.org/2.0.14/docs/comparing-struts-1-and-2.html

Struts2 Tags: http://www.struts2.net/reference.htm

More Struts2 Tags: http://www.roseindia.net/struts/struts2/struts-2-tags.shtml

Model Driven Actions: http://struts.apache.org/2.1.8/docs/model-driven.html

Interceptors: http://struts.apache.org/2.x/docs/interceptors.html

More Interceptors: http://struts.apache.org/2.0.14/docs/interceptors.html

Even More Interceptors: http://jodd.org/doc/madvoc/interceptors.html

Struts2 Validation: http://struts.apache.org/2.x/docs/validation.html

OGNL: http://www.opensymphony.com/ognl/

SiteMesh: http://www.opensymphony.com/sitemesh/

More SiteMesh: http://today.java.net/pub/a/today/2004/03/11/sitemesh.html