Struts2 Action Classes

Every operation that an application can perform is referred to as an action. Displaying a Login form, for example, is an action. So is saving a product's details. Creating actions is the most important task in Struts application development. Some actions are as simple as forwarding to a JSP. Others perform logic that needs to be written in action classes.
An action class is an ordinary Java class. It may have properties and methods and must comply with these rules.

• A property must have a get and a set methods. Action property names follow the same rules as JavaBeans property names. A property can be of any type, not only String. Data conversion from String to non-String happens automatically.

• An action class must have a no-argument constructor. If you don't have a constructor in your action class, the Java compiler will create a no-argument constructor for you. However, if you have a constructor that takes one or more arguments, you must write a no-argument constructor. Or else, Struts will not be able to instantiate the class.

• An action class must have at least one method that will be invoked when the action is called.

• An action class may be associated with multiple actions. In this case, the action class may provide a different method for each action. For example, a User action class may have login and logout methods that are mapped to the User_login and User_logout actions, respectively.

• Since Struts 2, unlike Struts 1, creates a new action instance for every HTTP request, an action class does not have to be thread safe.

• Struts 2, unlike Struts 1, by default does not create an HttpSession object. However, a JSP does. Therefore, if you want a completely session free action, add this to the top of all your JSPs:

<%@page session="false"%>
Below is a example of a struts2 Action class:

The Employee action class



package app03a;
import java.util.Collection;
import java.util.Date;
public class Employee
 {
          private String firstName;
          private String lastName;
          private Date birthDate;
          private Collection emails;
  public Date getBirthDate()
    {  
       return birthDate;
    }
public void setBirthDate(Date birthDate)
 {
       this.birthDate = birthDate;
 }
public Collection getEmails()
 {
       return emails;
 }
public void setEmails(Collection emails)
 {
     this.emails = emails;
}
public String getFirstName()
 {
      return firstName;
 }
public void setFirstName(String firstName)
 {
      this.firstName = firstName;
 }
public String getLastName()
{
      return lastName;
}
 public void setLastName(String lastName)
 {
         this.lastName = lastName;
 }
 public String register()
  {
        // do something here return "success";    }
 }

If you implement Action, you will inherit the following static fields: • SUCCESS. Indicates that the action execution was successful and the result view should be shown to the user.
• NONE. Indicates that the action execution was successful but no result view should be shown to the user.
• ERROR. Indicates that that action execution failed and an error view should be sent to the user.
• INPUT. Indicates that input validation failed and the form that had been used to take user input should be shown again.
• LOGIN. Indicates that the action could not execute because the user was not logged in and the login view should be shown.
You need to know the values of these static fields as you will use the values when configuring results. Here they are.
public static final String SUCCESS = "success";
public static final String NONE = "none";
public static final String ERROR = "error";
public static final String INPUT = "input";
public static final String LOGIN = "login";
  

The struts.xml File

The struts.xml file is an XML file with a struts root element. You define all the actions in your Struts application in this file. Here is the skeleton of a struts.xml file.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts>
...
</struts>
The more important elements that can appear between <struts> and </struts> are discussed below.
The package Element
Since Struts has been designed with modularity in mind, actions are grouped into packages. Think packages as modules. A typical struts.xml file can have one or many packages:
<struts>
 <package name="package-1" namespace="namespace-1" extends="struts-default">
<action name="..."/> <action name="..."/>
...
</package>
<package name="package-2" namespace="namespace-2"> extends="struts-default">
<action name="..."/> <action name="..."/>
 ...
</package>
...
<package name="package-n" namespace="namespace-n"> extends="struts-default">
<action name="..."/> <action name="..."/>
...
 </package>
</struts>
A package element must have a name attribute. The namespace attribute is optional and if it is not present, the default value "/" is assumed.
 If the namespace attribute has a non-default value, the namespace must be added to the URI that invokes the actions in the package.
For example, the URI for invoking an action in a package with a default namespace is this: /context/actionName.action
To invoke an action in a package with a non-default namespace, you need this URI: /context/namespace/actionName.action
A package element almost always extends the struts-default package defined in struts-default.xml. By doing so, all actions in the package can use the result types and interceptors registered in struts-default.xml.
The include Element
A large application may have many packages. In order to make the struts.xml file easier to manage for a large application, it is advisable to divide it into smaller files and use include elements to reference the files. Each file would ideally include a package or related packages. A struts.xml file with multiple include elements would look like this.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
 <struts>
 <include file="module-l.xml" />
 <include file="module-2.xml" />
...
<include file="module-n.xml" />
</struts>

The action Element
An action element is nested within a package element and represents an action. An action must have a name and you may choose any name for it. A good name reflects what the action does. For instance, an action that displays a form for entering a product's details may be called displayAddProductForm. By convention, you are encouraged to use the combination of a noun and a verb. For example, instead of calling an action displayAddProductForm, name it Product_input. However, it is totally up to you.
An action may or may not specify an action class. Therefore, an action element may be as simple as this.
<action name="MyAction">
An action that does not specify an action class will be given an instance of the default action class. The ActionSupport class is the default action class.
If an action has a non-default action class, however, you must specify the fully class name using the class attribute. In addition, you must also specify the name of the action method, which is the method in the action class that will be executed when the action is invoked.
 Here is an example.
<action name="Address_save" class="app.Address" method="save">
If the class attribute is present but the method attribute is not, execute is assumed for the method name. In other words, the following action elements mean the same thing.
<action name="Employee_save" class="app.Employee" method="execute"> <action name="Employee_save" class="app.Employee">

The result Element
<result> is a subelement of <action> and tells Struts where you want the action to be forwarded to. A result element corresponds to the return value of an action method. Because an action method may return different values for different situations, an action element may have several result elements, each of which corresponds to a possible return value of the action method. This is to say, if a method may return "success" and "input," you must have two result elements. The name attribute of the result element maps a result with a method return value.
If a method returns a value without a matching result element, Struts will try to find a matching result under the global-results element (See the discussion of this element below). If no corresponding result element is found under global-results, an exception will be thrown. For example, the following action element contains two result elements.
 <action name="Product_save" class="app.Product" method="save"> <result name="success" type="dispatcher"> /jsp/Confirm.jsp </result>
<result name="input" type="dispatcher"> /jsp/Product.jsp </result>
</action>
The first result will be executed if the action method save returns "success," in which case the Confirm.jsp page will be displayed. The second result will be executed if the method returns "input," in which case the Product.jsp page will be sent to the browser.
By the way, the type attribute of a result element specifies the result type. The value of the type attribute must be a result type that is registered in the containing package or a parent package extended by the containing package. Assuming that the action Product_save is in a package that extends struts-default, it is safe to use a Dispatcher result for this action because the Dispatcher result type is defined in struts-default. If you omit the name attribute in a result element, "success" is implied. In addition, if the type attribute is not present, the default result type Dispatcher is assumed. Therefore, these two result elements are the same.
<result name="success" type="dispatcher">/jsp/Confirm.jsp</result> <result>/jsp/Confirm.jsp</result>
 An alternative syntax that employs the param element exists for the Dispatcher result element. In this case, the parameter name to be used with the param element is location. In other words, this result element
<result>/test.jsp</result>
is the same as this:
 <result> <param name="location">/test.jsp</param> </result>

The global-results Element
A package element may contain a global-results element that contains results that act as general results. If an action cannot find a matching result under its action declaration, it will search the global-results element, if any.
Here is an example of the global-results element.
<global-results>
 <result name="error">/jsp/GenericErrorPage.jsp</result>
<result name="login" type="redirect-action">Login</result> </global-results>

The Interceptor-related Elements
There are five interceptor-related elements that may appear in a struts.xml file: interceptors, interceptor, interceptor-ref, interceptor-stack, and default-interceptor-ref. They are explained in this section.
An action element must contain a list of interceptors that will process the action object. Before you can use an interceptor, however, you have to register it using an interceptor element under <interceptors>. Interceptors defined in a package can be used by all actions in the package. For example, the following package element registers two interceptors, validation and logger.
<package name="main" extends="struts-default">
<interceptors>
<interceptor name="validation" class="..."/>
<interceptor name="logger" class="..."/>
</interceptors>
 </package>

To apply an interceptor to an action, use the interceptor-ref element under the action element of that action. For instance, the following configuration registers four interceptors and apply them to the Product_delete and Product_save actions.
 <package name="main" extends="struts-default">
 <interceptors>
 <interceptor name="alias" class="..."/>
<interceptor name="i18n" class="..."/>
<interceptor name="validation" class="..."/>
<interceptor name="logger" class="..."/>
</interceptors>
 <action name="Product_delete" class="...">
<interceptor-ref name="alias"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="validation"/>
<interceptor-ref name="logger"/>
 <result>/jsp/main.jsp</result>
</action> <action name="Product_save" class="...">
<interceptor-ref name="alias"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="validation"/>
 <interceptor-ref name="logger"/>
 <result name="input">/jsp/Product.jsp</result> <result>/jsp/ProductDetails.jsp</result>
 </action>
 </package>

With these settings every time the Product_delete or Product_save actions are invoked, the four interceptors will be given a chance to process the actions. Note that the order of appearance of the interceptor-ref element is important as it determines the order of invocation of registered interceptors for that action. In this example, the alias interceptor will be invoked first, followed by the i18n interceptor, the validation interceptor, and the logger interceptor.
With most Struts application having multiple action elements, repeating the list of interceptors for each action can be a daunting task. In order to alleviate this problem, Struts allows you to create interceptor stacks that group required interceptors. Instead of referencing interceptors from within each action element, you can reference the interceptor stack instead.
For instance, six interceptors are often used in the following orders: exception, servletConfig, prepare, checkbox, params, and conversionError. Rather than referencing them again and again in your action declarations, you can create an interceptor stack like this:
 <interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="params"/>
 <interceptor-ref name="conversionError"/>
</interceptor-stack>

To use these interceptors, you just need to reference the stack:
<action name="..." class="...">
 <interceptor-ref name="basicStack"/>
 <result name="input">/jsp/Product.jsp</result> <result>/jsp/ProductDetails.jsp</result>
 </action>

The struts-default package defines several stacks. In addition, it defines a default-interceptor-ref element that specifies the default interceptor or interceptor stack to use if no interceptor is defined for an action:
 <default-interceptor-ref name="defaultStack"/>

If an action needs a combination of other interceptors and the default stack, you must redefine the default stack as the default-interceptor-ref element will be ignored if an interceptor element can be found within an action element.

The param Element
The param element can be nested within another element such as action, result-type, and interceptor to pass a value to the enclosing object.
The param element has a name attribute that specifies the name of the parameter. The format is as follows:
<param name="property">value</param>
Used within an action element, param can be used to set an action property. For example, the following param element sets the siteId property of the action.
<action name="customer" class="...">
<param name="siteId">california01</param>
</action>

And the following param element sets the excludeMethod of the validation interceptor-ref:
 <interceptor-ref name="validation">
 <param name="excludeMethods">input,back,cancel</param> </interceptor-ref>

The excludeMethods parameter is used to exclude certain methods from invoking the enclosing interceptor.

The constant Element
In addition to the struts.xml file, you can have a struts.properties file. You create the latter if you need to override one or more key/value pairs defined in the default.properties file, which is included in the struts2-core-VERSION.jar file. Most of the time you won't need a struts.properties file as the default.properties file is good enough. Besides, you can override a setting in the default.properties file using the constant element in the struts.xml file.
The constant element has a name attribute and a value attribute. For example, the struts.devMode setting determines whether or not the Struts application is in development mode. By default, the value is false, meaning the application is not in development mode. The following constant element sets struts.devMode to true.
<struts>
 <constant name="struts.devMode" value="true"/> ...
</struts>
 

Struts 2 Configuration Files

A Struts application uses a number of configuration files. The primary two are struts.xml and struts.properties, but there can be other configuration files. For instance, a Struts plug-in comes with a struts-plugin.xml configuration file. And if you're using Velocity as your view technology, expect to have a velocity.properties file.
It is possible to have no configuration file at all. The zero configuration feature, "Zero Configuration," is for advanced developers who want to skip this mundane task.
In struts.xml you define all aspects of your application, including the actions, the interceptors that need to be called for each action, and the possible results for each action.
Interceptors and result types used in an action must be registered before they can be used. Happily, Struts configuration files support inheritance and default configuration files are included in the struts2-core- VERSION.jar file. The struts-default.xml file, one of such default configuration files, registers the default result types and interceptors. As such, you can use the default result types and interceptors without registering them in your own struts.xml file, making it cleaner and shorter. The default.properties file, packaged in the same JAR, contains settings that apply to all Struts applications. As a result, unless you need to override the default values, you don't need to have a struts.properties file.

Advantages/Disadvantages of Struts 2 Framework

Struts 2 is a Framework which is an implementation of MVC-2 at server side. Struts 2 have many advantages over the standard servlet and JSP API alone. But struts 2 is complex so Struts2  have many disadvantages too.

 


Action Classes:-Struts 2 framework Action class implements Action interface and other interfaces are optional .Struts 2 provides a base ActionSupport class to implements Validatable ,ValidationAware ,TextProvider and Action interface. Any POJO object with a execute signature can be used as an Struts 2 Action object.

Threading Model:- Struts 2 framework instantiated Action object for each request, so there are no thread-safety issues.  

Servlet Dependency:- The Struts 2 framework servlet contexts are represented as simple Maps because it is not coupled to a container allowing Actions to be tested in isolation. Struts 2 Actions can still access the original request and response, if required. However, other architectural elements reduce or eliminate the need to access the HttpServetRequest or HttpServletResponse directly.

Testability:- Struts 2 Actions can be tested by instantiating the Action, setting properties, and invoking methods. Dependency Injection support also makes testing simpler.

Expression Language:- Struts 2 can use  "Object Graph Navigation Language" (OGNL).

Binding values into views:- Struts 2 uses a "ValueStack" concept so that the taglibs can access values without coupling your view to the object type it is rendering. 

Type Conversion:- Struts 2 uses OGNL for type conversion. The framework includes converters for basic and common object types and primitives.

Validation:- Struts 2 supports manual validation via the validate method and also contain the Sub Framework validation .

Control of Action Execution:- Struts 2 supports creating different lifecycles on a per Action basis via Interceptor Stacks. Custom stacks can be created and used with different Actions, as needed.

Disadvantages of the Struts2 framework:a) Convention problem:-The Struts2 framework more follow the convention.

b) Harder to learn:-Struts are harder to learn, benchmark and optimize.

How Struts 2 Works ?

Struts has a filter dispatcher. Its fully qualified name is org.apache.struts2.dispatcher.FilterDispatcher. To use it, register it in the deployment descriptor (web.xml file) using this filter and filter-mapping elements.

<filter>
<filter-name>struts2</filter-name>
<filter-class> org.apache.struts2.dispatcher.FilterDispatcher </filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
 
There's a lot that a filter dispatcher in a Model 2 application has to do and Struts' filter dispatcher is by no means an exception. Since Struts has more, actually much more, features to support, its filter dispatcher could grow infinitely in complexity. However, Struts approaches this by splitting task processing in its filter dispatcher into subcomponents called interceptors. The first interceptor you'll notice is the one that populates the action object with request parameters. You'll learn more about interceptors in our later posts.
In a Struts application the action method is executed after the action's properties are populated. An action method can have any name as long as it is a valid Java method name.
An action method returns a String value. This value indicates to Struts where control should be forwarded to. A successful action method execution will forward to a different view than a failed one. For instance, the String "success" indicates a successful action method execution and "error" indicates that there's been an error during processing and an error message should be displayed. Most of the time a RequestDispatcher will be used to forward to a JSP, however JSPs are not the only allowed destination. A result that returns a file for download does not need a JSP. Neither does a result that simply sends a redirection command or sends a chart to be rendered. Even if an action needs to be forwarded to a view, the view may not necessarily be a JSP. A Velocity template or a FreeMarker template can also be used.

Benefits of Struts 2 Farmework

Struts is an MVC framework that employs a filter dispatcher as the controller. When writing a Model 2 application, it is your responsibility to provide a controller as well as write action classes. Your controller must be able to do these:

1. Determine from the URI what action to invoke.

2. Instantiate the action class.

3. If an action object exists, populate the action's properties with request parameters.

4. If an action object exists, call the action method.

5. Forward the request to a view (JSP).

The first benefit of using Struts is that you don't have to write a controller and can concentrate on writing business logic in action classes. Here is the list of features that Struts is equipped with to make development more rapid:

• Struts provides a filter dispatcher, saving you writing one.

• Struts employs an XML-based configuration file to match URIs with actions. Since XML documents are text files, many changes can be made to the application without recompilation.

• Struts instantiates the action class and populates action properties with user inputs. If you don't specify an action class, a default action class will be instantiated.

• Struts validates user input and redirects user back to the input form if validation failed. Input validation is optional and can be done programmatically or declaratively. On top of that, Struts provides built-in validators for most of the tasks you may encounter when building a web application.

• Struts invokes the action method and you can change the method for an action through the configuration file.

• Struts examines the action result and executes the result. The most common result type, Dispatcher, forwards control to a JSP. However, Struts comes with various result types that allow you to do things differently, such as generate a PDF, redirect to an external resource, send an error message, etc.

Whats in Struts 2 ?

If you have programmed with Struts 1, this post provides a brief introduction of what to expect in Struts 2.

• Instead of a servlet controller like the ActionServlet class in Struts 1, Struts 2 uses a filter to perform the same task.

• There are no action forms in Struts 2. In Struts 1, an HTML form maps to an ActionForm instance. You can then access this action form from your action class and use it to populate a data transfer object. In Struts 2, an HTML form maps directly to a POJO. You don't need to create a data transfer object and, since there are no action forms, maintenance is easier and you deal with fewer classes.

• Now, if you don't have action forms, how do you programmatically validate user input in Struts 2? By writing the validation logic in the action class.

• Struts 1 comes with several tag libraries that provides custom tags to be used in JSPs. The most prominent of these are the HTML tag library, the Bean tag library, and the Logic tag library. JSTL and the Expression Language (EL) in Servlet 2.4 are often used to replace the Bean and Logic tag libraries. Struts 2 comes with a tag library that covers all. You don't need JSTL either, even though in some cases you may still need the EL.

• In Struts 1 you used Struts configuration files, the main of which is called struts-config.xml (by default) and located in the WEB-INF directory of the application. In Struts 2 you use multiple configuration files too, however they must reside in or a subdirectory of WEB-INF/classes.

• Java 5 and Servlet 2.4 are the prerequisites for Struts 2. Java 5 is needed because annotations, added to Java 5, play an important role in Struts 2. Considering that Java 6 has been released and Java 7 is on the way at the time of writing, you're probably already using Java 5 or Java 6.

• Struts 1 action classes must extend org.apache.struts.action.Action. In Struts 2 any POJO can be an action class. However, for reasons that will be explained in Chapter 3, "Actions and Results" it is convenient to extend the ActionSupport class in Struts 2. On top of that, an action class can be used to service related actions.

• Instead of the JSP Expression Language and JSTL, you use OGNL to display object models in JSPs.

• Tiles, which started life as a subcomponent of Struts 1, has graduated to an independent Apache project. It is still available in Struts 2 as a plug-in.



Introduction To Struts 2 Framework

Servlet expert Craig R. McClanahan's donated his brainchild to the Apache Software Foundation in May 2000 and Struts 1.0 was released in June 2001. It soon became, and still is, the most popular framework for developing Java web applications. Its web site is http://struts.apache.org/.

In the meantime, on the same planet, some people had been working on another Java open source framework called WebWork. Similar to Struts 1, WebWork never neared the popularity of its competitor but was architecturally superior to Struts 1. For example, in Struts 1 translating request parameters to a Java object requires an "intermediary" object called the form bean, whereas in WebWork no intermediary object is necessary. The implication is clear, a developer is more productive when using WebWork because fewer classes are needed. As another example, an object called interceptor can be plugged in easily in WebWork to add more processing to the framework, something that is not that easy to achieve in Struts 1.

Another important feature that WebWork has but Struts 1 lacks is testability. This has a huge impact on productivity. Testing business logic is much easier in WebWork than in Struts 1. This is so because with Struts 1 you generally need a web browser to test the business logic to retrieve inputs from HTTP request parameters. WebWork does not have this problem because business classes can be tested without a browser.

A superior product (WebWork) and a pop-star status (Struts 1) naturally pressured both camps to merge. According to Don Brown in his blog (www.oreillynet.com/onjava/blog/2006/10/my_history_of_struts_2.html), it all started at JavaOne 2005 when some Struts developers and users discussed the future of Struts and came up with a proposal for Struts Ti (for Titanium), a code name for Struts 2. Had the Struts team proceeded with the original proposal, Struts 2 would have included coveted features missing in version 1, including extensibility and AJAX. On WebWork developer Jason Carreira's suggestion, however, the proposal was amended to include a merger with WebWork. This made sense since WebWork had most of the features of the proposed Struts Ti. Rather than reinventing the wheel, 'acquisition' of WebWork could save a lot of time.

As a result, internally Struts 2 is not an extension of Struts 1. Rather, it is a re-branding of WebWork version 2.2. WebWork itself is based on XWork, an open source command-pattern framework from Open Symphony (http://www.opensymphony.com/xwork). Therefore, don't be alarmed if you encounter Java types that belong to package com.opensymphony.xwork2 throughout the struts2 programs.
Struts is a framework for developing Model 2 applications. It makes development more rapid because it solves many common problems in web application development by providing these features:

• page navigation management

• user input validation

• consistent layout

• extensibility

• internationalization and localization

• support for AJAX

Because Struts is a Model 2 framework, when using Struts you should stick to the following unwritten rules:

• No Java code in JSPs, all business logic should reside in Java classes called action classes.

• Use the Expression Language (OGNL) to access model objects from JSPs.

• Little or no writing of custom tags (because they are relatively hard to code).

Twitter Delicious Facebook Digg Stumbleupon Favorites More