STRUTS

Step 0: Downloading and installing Struts

Installing JDK:

Download JDK 1.4 or above from sun site. Follow the instruction given in the installation manual and install JDK.

Installing Tomcat:

Download Tomcat from the apache site and install it. I have downloaded jakarta-tomcat-5.0.4 and installed for this tutorial. To  test your installation go to your installation directory/bin and issue startup command to run the server. Open browser and type http://localhost:8080/ to test the server. It should display the welcome page. If not consult tomcat documentation before going further.

Installing Struts Application:

Download latest version of Struts from the official site of Struts http://jakarta.apache.org/struts. Extract the file ito your favorite directory and copy struts-blank.war, struts-documentation.war and struts-example.war from "jakarta-struts-1.1\webapps" directtory into "jakarta-tomcat-5.0.4\webapps" directory.

struts-blank.war is the blank struts application which is useful in creating struts application from scratch. We will use this file to create our web application.

struts-documentation.war contains API and important documents for the struts application development.

struts-example.war is simple MailReader Demonstration Application.

Developing First Struts Application

Rename struts-blank.war  to struts-tutorial.war from jakarta-tomcat-5.0.4\webapps and copy it to the "jakarta-tomcat-5.0.4\webapps" directory. Tomcat automatically extracts the file and loads the application. 

Note: I have decided to use JBoss 3.2.3 for next parts as it is very easy to deploy the application in JBoss and I have developed the Ant script for easy deployment of the tutorial. The hot deployment feature of JBoss is very useful and it pickups the new ear files and deploys automatically.

 

 

 

 

 

Step 1: The directories and files of a Struts application

You'll need to know the directory structure of a Struts application, and what's put in the directories. The "struts-blank" application is well-suited for this presentation, since it contains a minimum number of files:

- Figure 3: The Struts directory structure - 

File or Directory name

Purpose

META-INF

Contains meta information. Used by utilities etc.

WEB-INF/classes

This is where you place you own Java classes.

WEB-INF/classes/ApplicationResources.properties

Contains the messages (fixed texts) of the application. Error messages are also put here.

WEB-INF/lib/struts.jar

Contains the Struts servlet, helper classes, taglib code etc.

WEB-INF/*.tld

The Struts tag libraries.

WEB-INF/struts-config.xml

A Struts configuration file. More on this later.

WEB-INF/web.xml

The usual configuration file for the servlet container. More on this later.

index.jsp

The jsp-files (and html-files) may be placed in the root of the application directory. "struts-blank" contains this single jsp-file.

- Table 1: The files and directories in a Struts application -

 

 

 

 

 

 

 

The class org.apache.struts.action.ActionServlet is the heart of the Struts Framework. It is the Controller part of the Struts Framework. ActionServlet is configublak as Servlet in the web.xml file as shown in the following code snippets.

Step 3: The web.xml file

The web.xml file is where servlets and other stuff are defined to the servlet container. We'll remove some unnecessary things from the web.xml file so it looks like this:

<?xml version="1.0" encoding="ISO-8859-1"?>

     
<!DOCTYPE web-app

      PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"

      "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

     
<web-app>

     

      <!-- Standard Action Servlet Configuration (with debugging) -->

      <servlet>

        <servlet-name>action</servlet-name>

        <servlet-class>

              
    org.apache.struts.action.ActionServlet

            </servlet-class>

        <init-param>

          <param-name>application</param-name>

          <param-value>ApplicationResources</param-value>

        </init-param>

        <init-param>

          <param-name>config</param-name>

          <param-value>/WEB-INF/struts-config.xml</param-value>

        </init-param>

        <init-param>

          <param-name>debug</param-name>

          <param-value>2</param-value>

        </init-param>

        <init-param>

          <param-name>detail</param-name>

          <param-value>2</param-value>

        </init-param>

        <init-param>

          <param-name>validate</param-name>

          <param-value>true</param-value>

        </init-param>

        <load-on-startup>2</load-on-startup>

      </servlet>

     
 

      <!-- Standard Action Servlet Mapping -->

      <servlet-mapping>

        <servlet-name>action</servlet-name>

        <url-pattern>*.do</url-pattern>

      </servlet-mapping>

     
 

      <!-- Struts Tag Library Descriptors -->

      <taglib>

        <taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>

        <taglib-location>/WEB-INF/struts-bean.tld</taglib-location>

      </taglib>

     

      <taglib>

        <taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>

        <taglib-location>/WEB-INF/struts-html.tld</taglib-location>

      </taglib>

     

      <taglib>

        <taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>

        <taglib-location>/WEB-INF/struts-logic.tld</taglib-location>

      </taglib>

     
</web-app>

- Figure 4: The web.xml file -

The file contains three sections:

a.        the definition of the Struts servlet named "ActionServlet"

b.        the URL mapping for the calls to this servlet

c.        the definitions of the Struts tag libraries

The struts-config.xml file

 

a.        First of all the Struts servlet will automatically transfer the data from your form into a JavaBean that you should supply. This bean is called the ActionForm bean, because your bean must extend the Struts "ActionForm" class. You may think of this bean as a buffer between the browser and your database. The ActionForm bean may also be used to initialize form controls and to validate the data enteblak by the user.

b.        Secondly the Struts servlet will call a class which you specify and it is referblak to as the Action class. This class may use the data in the ActionForm bean. The Action class is where your application coding starts. When your class finishes it returns control to the Struts servlet.

 

- Figure 5: The Action and ActionForm classes -

 

This servlet is responsible for handing all the request for the Struts Framework, user can map the specific pattern of request to the ActionServlet. <servlet-mapping> tag in the web.xml file specifies the url pattern to be handled by the servlet. By default it is *.do, but it can be changed to anything. Following code form  the web.xml file shows the mapping.

<!-- Standard Action Servlet Mapping -->
<servlet-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

The above mapping maps all the requests ending with .do to the ActionServlet. ActionServlet uses the configuration defined in struts-config.xml file to decide the destination of the request. Action Mapping Definitions (described below) is used to map any action. For this lesson we will create Welcome.jsp file and map the "Welcome.do" request to this page.

Welcome.jsp

<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<html:html locale="true">
<head>
   <title><bean:message key="welcome.title"/></title>
   <html:base/>
</head>
  <body bgcolor="white">
  <h3><bean:message key="welcome.heading"/></h3>
  <p><bean:message key="welcome.message"/></p>
</body>
</html:html>

Forwarding the Welcome.do request to Welcome.jsp

The "Action Mapping Definitions" is the most important part in the struts-config.xml. This section takes a form defined in the "Form Bean Definitions" section and maps it to an action class.

Following code under the <action-mappings> tag is used to forward the request to the Welcome.jsp.

<action  path="/Welcome"
        forward="/pages/Welcome.jsp"
/>
  

To call this Welcome.jsp file we will use the following code.

<html:link page="/Welcome.do">First Request to the controller</html:link>

Once the use clicks on on First Request to the controller link on the index page, request (for Welcome.do) is sent to the Controller and the controller forwards the request to Welcome.jsp. The content of Welcome.jsp is displayed to the user.

 

What is Action Class?

The Action Class is part of the Model and is a wrapper around the business logic. The purpose of Action Class is to translate the HttpServletRequest to the business logic. To use the Action, we need to  Subclass and overwrite the execute() method. In the Action Class all the database/business processing are done. It is advisable to perform all the database related stuffs in the Action Class. 

The ActionServlet (commad) passes the parameterized class to Action Form using the execute() method. The return type of the execute method is ActionForward which is used by the Struts Framework to forward the request to the file as per the value of the returned ActionForward object.

Developing our Action Class?

Our Action class (TestAction.java) is simple class that only forwards the TestAction.jsp. Our Action class returns the ActionForward  called "testAction", which is defined in the struts-config.xml file (action mapping is show later in this page). Here is code of our Action Class:

TestAction.java

package roseindia.net;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

public class TestAction extends Action
{
  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response) throws Exception{
      return mapping.findForward("testAction");
  }
}

   
Understanding Action Class
Here is the signature of the Action Class.

public ActionForward execute(ActionMapping
    mapping,

                           
         ActionForm form,

                           
         javax.servlet.http.HttpServletRequest request,

                           
         javax.servlet.http.HttpServletResponse response)

                          
    throws java.lang.Exception

Action Class process the specified HTTP request, and create the corresponding HTTP response (or forward to another web component that will create it), with provision for handling exceptions thrown by the business logic. Return an ActionForward instance describing where and how control should be forwarded, or null if the response has already been completed.

Parameters:

mapping - The ActionMapping used to select this instance

form - The optional ActionForm bean for this request (if any)

request - The HTTP request we are processing

response - The HTTP response we are creating

Throws:

Action class throws java.lang.Exception - if the application business logic throws an exception

Adding the Action Mapping in the struts-config.xml
To test the application we will add a link in the index.jsp 
<html:link page="/TestAction.do">Test the Action</html:link>

Following code under the <action-mappings> tag is used to for mapping the TestAction class.


       <action

          path="/TestAction"

          type="roseindia.net.TestAction">

          <forward name="testAction" path="/pages/TestAction.jsp"/>

       </action>  
         
    

To test the new application click on Test the Action link on the index page. The content of TestAction.jsp should be displayed on the user browser.

In this lesson you learned how to create Action Class and add the mappings in the struts-config.xml. Our Action Class returns the ActionForward  mapping of the TestAction.jsp.

What is ActionForm?
An ActionForm is a JavaBean that extends org.apache.struts.action.ActionForm. ActionForm maintains the session state for web application and the ActionForm object is automatically populated on the server side with data enteblak from a form on the client side.

We will first create the class AddressForm which extends the ActionForm class. Here is the code of the class:

AddressForm.java

package roseindia.net;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.*;

/**
 * Form bean for the Address Entry Screen.
 *
*/
public class AddressForm extends ActionForm
{
  private String name=null;
  private String address=null;
  private String emailAddress=null;

  public void setName(String name){
    this.name=name;
  }

  public String getName(){
    return this.name;
  }

  public void setAddress(String address){
    this.address=address;
  }

  public String getAddress(){
    return this.address;
  }


  public void setEmailAddress(String emailAddress){
    this.emailAddress=emailAddress;
  }

  public String getEmailAddress(){
    return this.emailAddress;
  }


    /**
     * Reset all properties to their default values.
     *
     * @param mapping The mapping used to select this instance
     * @param request The servlet request we are processing
     */
    public void reset(ActionMapping mapping, HttpServletRequest request) {
    this.name=null;
    this.address=null;
    this.emailAddress=null;
    }

    /**
     * Reset all properties to their default values.
     *
     * @param mapping The mapping used to select this instance
     * @param request The servlet request we are processing
   * @return errors
     */
  public ActionErrors validate( 
      ActionMapping mapping, HttpServletRequest request ) {
      ActionErrors errors = new ActionErrors();
      
      if( getName() == null || getName().length() < 1 ) {
        errors.add("name",new ActionMessage("error.name.requiblak"));
      }
      if( getAddress() == null || getAddress().length() < 1 ) {
        errors.add("address",new ActionMessage("error.address.requiblak"));
      }
      if( getEmailAddress() == null || getEmailAddress().length() < 1 ) {
        errors.add("emailaddress",new ActionMessage("error.emailaddress.requiblak"));
      }

      return errors;
  }

}

The above class populates the Address Form data and validates it. The validate() method is used to validate the inputs. If any or all of the fields on the form are blank, error messages are added to the ActionMapping object.  Note that we are using ActionMessage class, ActionError is now deprecated and will be removed in next version.

Now we will create the Action class which is the model part of the application. Our action class simply forwards the request the Success.jsp. Here is the code of the AddressAction class:

AddressAction.java

package roseindia.net;

/**
* @author Deepak Kumar
* @Web http://www.roseindia.net
* @Email roseindia_net@yahoo.com
*/

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

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

Now we have to create an entry for form bean in the struts-config.xml. Add the following lines in the struts-config.xml file:

<form-bean
name="AddressForm"
type="roseindia.net.AddressForm"/>

Add the following line in the struts-config.xml file for handling the action "/Address.do":

<action
     path="/Address"
     type="roseindia.net.AddressAction"
     name="AddressForm"
     scope="request"
     validate="true"
     input="/pages/Address.jsp">
    <forward name="success" path="/pages/success.jsp"/>
</action>

Now create Address.jsp, which is our form for entering the address details. Code for Address.jsp is as follows:

Address.jsp


       <%@ taglib uri="/tags/struts-bean" prefix="bean" %>

       <%@ taglib uri="/tags/struts-html" prefix="html" %>
  
    

       <html:html locale="true">

     

       <head>

     

       <title><bean:message key="welcome.title"/></title>

     

       <html:base/>

     

       </head>

     

       <body bgcolor="white">

     

       <html:form action="/Address">

     

       <html:errors/>

     

       <table>

     

            <tr>

     

              <td align="center" colspan="2">

                   <font size="4">Please
    Enter the Following Details</font>

           </tr>

            <tr>

              <td align="right">

                Name

              
    </td>

              <td align="left">

                <html:text property="name" size="30"
    maxlength="30"/>

              </td>

            </tr>

            <tr>

              <td align="right">

                Address

              </td>

              <td align="left">

                <html:text property="address"
    size="30" maxlength="30"/>

              </td>

            </tr>

     

            <tr>

              <td align="right">

                E-mail address

              </td>

              <td align="left">

                <html:text property="emailAddress"
    size="30" maxlength="30"/>

              </td>

            </tr>

            <tr>

              <td align="right">

                <html:submit>Save</html:submit>

              </td>

              <td align="left">

                <html:cancel>Cancel</html:cancel>

              </td>

            </tr>

      </table>

       </html:form>

       </body>

       </html:html>

User enter the values in the form and click on the submit form. Form  validation is done on the server side and error message is displays on the jsp page. To display the error on the jsp page <html:errors/> tag is used. The <html:errors/> tag displays all the errors in one go.  To create text box <html:text .../> is used in jsp page. 

e.g.

<html:text property="address" size="30" maxlength="30"/>

Above tag creates text box for entering the address. The address is retrieved from and later stoblak in the property named address in the form-bean. The tag <html:submit>Save</html:submit> creates the submit button and the tag <html:cancel>Cancel</html:cancel> is used to create the Cancel button.

Add the following line in the index.jsp to create a link for testing the Address.jsp form:

<html:link page="/pages/Address.jsp">Test the Address Form</html:link>

Build the application and click on the Test the Address Form link on the index page to test the newly created screen. You should see the following screen.

In this lesson you learned how to create data entry form using struts, validate and finally send process the business logic in the model part of the struts.

 

Struts provides HTML tag library for easy creation of user interfaces. In this lesson I will show you what all Struts HTML Tags are available to the JSP for the development of user interfaces.

To use the Struts HTML Tags we have to include the following line in our JSP file:

<%@ taglib uri="/tags/struts-html" prefix="html" %>

above code makes available the tag to the jsp.

Struts HTML Tags

<html:message key="thekey"/>

Looks up the message corresponding to the given key in the message resources and displays it.

<html:password property="prop" size="10"/>

Tag creates the password field. The string is stoblak in the property named prop in the form bean.

<html:text property="text1" size="5"/>

Tag creates the text field. The string is retrieved from and later stoblak in the property named text1 in the form bean.

<html:submit>Submit</html:submit>

Tag creates a submit button with the provided content as the button text. 

<html:reset>Reset</html:reset>

Tag creates a reset button with the provided content as the button text. 

<html:errors/>

Tag prints all the available error on the page.

<html:file property="fileSelectionBox"/>

Tag creates the file upload element on the form. The property must be of the type org.apache.struts.upload.FormFile.

<html:checkbox property="myCheckBox"/>

Tag creates check box on the form.

<html:hidden property="hiddenfield"/>

Tag creates the hidden html element on the form.

<html:radio value="abc" property="myCheckBox"/>

Tag creates the check box on the form.

<html:select multiple="true" property="selectBox">

Tag creates list box on the form. The property selectBox must be an array of supported data-types, and the user may select several entries. Use <html:options> to specify the entries.

<html:textarea property="myTextArea" value="Hello Struts" />

Tag creates the text area on the form.

<html:form action="/Address" method="post">

Tag is used to create the HTML Form for posting the data on the server.

<html:base/>

Tag generates the base tag. <BASE ...> tells the browser to pretend that the current page is located at some URL other than where the browser found it. Any relative reference will be calculated from the URL given by <BASE HREF="..."> instead of the actual URL. <BASE ...> goes in the <HEAD> section.

<html:html>

Tag renders an HTML <html> Element.

 

 

 

Introduction to Validator Framework

Struts Framework provides the functionality to validate the form data. It can be use to validate the data on the users browser as well as on the server side. Struts Framework emits the java scripts and it can be used to validate the form data on the client browser. Server side validation of the form can be accomplished by sub classing your From Bean with DynaValidatorForm class. 

The Validator framework comes integrated with the Struts Framework and can be used without doing any extra settings.

Using Validator Framework

Validator uses the XML file to pickup the validation rules to be applied to an form. In XML validation requirements are defined applied to a form. In case we need special validation rules not provided by the validator framework, we can plug in our own custom validations into Validator.

The Validator Framework uses two XML configuration files validator-rules.xml and validation.xml. The validator-rules.xml defines the standard validation routines, these are reusable and used in validation.xml. to define the form specific validations. The validation.xml defines the validations applied to a form bean.

Structure of validator-rule.xml

The validation-rules.xml is provided with the Validator Framework and it declares and assigns the logical names to the validation routines. It also contains the client-side javascript code for each validation routine. The validation routines are java methods plugged into the system to perform specific validations.

Following table contains the details of the elements in this file: 

Element

Attributes and Description

form-validation

This is the root node. It contains nested elements for all of the other configuration settings.

global

The validator details specified within this, are global and are accessed by all forms.

validator

The validator element defines what validators objects can be used with the fields referenced by the formset elements.

The attributes are:

·         name: Contains a logical name for the validation routine

·         classname: Name of the Form Bean class that extends the subclass of ActionForm class

·         method: Name of the method of the Form Bean class

·         methodParams: parameters passed to the method

·         msg:Validator uses Struts' Resource Bundle mechanism for externalizing error messages. Instead of having hard-coded error messages in the framework, Validator allows you to specify a key to a message in the ApplicationResources.properties file that should be returned if a validation fails. Each validation routine in the validator-rules.xml file specifies an error message key as value for this attribute.

·         depends: If validation is requiblak, the value here is specified as 'requiblak' for this attribute.

·         jsFunctionName: Name of the javascript function is specified here. 

javascript

Contains the code of the javascript function used for client-side validation. Starting in Struts 1.2.0 the default javascript definitions have been consolidated to commons-validator.  The default can be overridden by supplying a <javascript> element with a CDATA section, just as in struts 1.1.

The Validator plug-in (validator-rules.xml) is supplied with a pblakefined set of commonly used validation rules such as Requiblak, Minimum Length, Maximum length, Date Validation, Email Address validation and more. This basic set of rules can also be extended with custom validators if requiblak.

Structure of validation.xml

This validation.xml configuration file defines which validation routines that is used to validate Form Beans. You can define validation logic for any number of  Form Beans in this configuration file. Inside that definition, you specify the validations you want to apply to the Form Bean's fields. The definitions in this file use the logical names of Form Beans from the struts-config.xml file along with the logical names of validation routines from the validator-rules.xml file to tie the two together.

Element

Attributes and Description

form-validation

This is the root node. It contains nested elements for all of the other configuration settings

global

The constant details are specified in <constant> element within this element.

constant

Constant properties are specified within this element for pattern matching.

constant-name

Name of the constant property is specified here

constant-value

Value of the constant property is specified here.

formset

This element contains multiple <form> elements

form

This element contains the form details.
The attributes are:
name
:Contains the form name. Validator uses this logical name to map the validations to a Form Bean defined in the struts-config.xml file

field

This element is inside the form element, and it defines the validations to apply to specified Form Bean fields.

The attributes are:

·         property: Contains the name of a field in the specified Form Bean

·         depends: Specifies the logical names of validation routines from the validator-rules.xml file that should be applied to the field.

arg

A key for the error message to be thrown incase the validation fails, is specified here

var

Contains the variable names and their values as nested elements within this element.

var-name

The name of the criteria against which a field is validated is specified here as a variable

var-value

The value of the field is specified here

 

Example of  form in the validation.xml file:

<!-- An example form -->
<form name="logonForm">
<field property="username"
       depends="requiblak">
       <arg key="logonForm.username"/>
      </field>
     <field property="password"
         depends="requiblak,mask">
         <arg key="logonForm.password"/>
         <var>
            <var-name>mask</var-name>
            <var-value>^[0-9a-zA-Z]*$</var-value>
        </var>
    </field>
  </form>

The <html:javascript> tag to allow front-end validation based on the xml in validation.xml. For  example the code: <html:javascript formName="logonForm" dynamicJavascript="true" staticJavascript="true" /> generates the client side java script for the form "logonForm" as defined in the validation.xml file. The <html:javascript> when added in the jsp file generates the client site validation script.

In the next lesson we will create a new form for entering the address and enable the client side java script with the Validator Framework.

In this lesson we will create JSP page for entering the address and use the functionality provided by Validator Framework to validate the user data on the browser. Validator Framework emits the JavaScript code which validates the user input on the browser. To accomplish this we have to follow the following steps:

  1. Enabling the Validator plug-in: This makes the Validator available to the system.
  2. Create Message Resources for the displaying the error message to the user.
  3. Developing the Validation rules We have to define the validation rules in the validation.xml for the address form. Struts Validator Framework uses this rule for generating the JavaScript for validation.
  4. Applying the rules: We are requiblak to add the appropriate tag to the JSP for generation of JavaScript.
  5. Build and test: We are requiblak to build the application once the above steps are done before testing. 

Enabling the Validator plug- in
To enable the validator plug-in open the file struts-config.xml and make sure that following line is present in the file.

<!--  Validator plugin -->
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
          <set-property
            property="pathnames"
           value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>

Creating Message Resources
Message resources are used by the Validator Framework to generate the validation error messages. In our application we need to define the messages for name, Address and E-mail address. Open the Struts\strutstutorial\web\WEB-INF\MessageResources.properties file and add the following lines:
AddressForm.name=Name
AddressForm.address=Address
AddressForm.emailAddress=E-mail address

Developing Validation rules
In this application we are adding only one validation that the fields on the form should not be blank.  Add the following code in the validation.xml. 

<!-- Address form Validation-->
<form name="AddressForm">
    <field  property="name"
          depends="requiblak">
         <arg key="AddressForm.name"/>
    </field>
    <field  property="address"
         depends="requiblak">
         <arg key="AddressForm.address"/>
     </field>
     <field  property="emailAddress"
         depends="requiblak">
        <arg key="AddressForm.emailAddress"/>
     </field>
</form>

The above definition defines the validation for the form fields name, address and emailAddress. The attribute depends="requiblak" instructs the Validator Framework to generate the JavaScript that checks that the fields are not left blank. If the fields are left blank then JavaScript shows the error message. In the error message the message are taken from the key defined in the <arg key=".."/> tag. The value of key is taken from the message resources (Struts\strutstutorial\web\WEB-INF\MessageResources.properties).

Applying Validation rules to JSP
Now create the AddressJavascriptValidation.jsp file to test the application. The code for AddressJavascriptValidation.jsp is as follows:

<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>

<html:html locale="true">
<head>
    <title><bean:message key="welcome.title"/></title>
<html:base/>
</head>
<body bgcolor="white">
<html:form action="/AddressJavascriptValidation" method="post" onsubmit="return validateAddressForm(this);">

<div align="left">
<p>
This application shows the use of Struts Validator.<br>
The following form contains fields that are processed by Struts Validator.<br> 
Fill in the form and see how JavaScript generated by Validator Framework validates the form.
</p>

<p>
<html:errors/>
</p>
<table>

<tr>
<td align="center" colspan="2">
<font size="4"><b>Please Enter the Following Details</b></font>
</tr>
<tr>
<td align="right">
<b>Name</b>
</td>
<td align="left">
<html:text property="name" size="30" maxlength="30"/>
</td>
</tr>
<tr>
<td align="right">
<b>Address</b>
</td>
<td align="left">
<html:text property="address" size="30" maxlength="30"/>
</td>
</tr>

<tr>
<td align="right">
<b>E-mail address</b>
</td>
<td align="left">
<html:text property="emailAddress" size="30" maxlength="30"/>
</td>
</tr>

<tr>
<td align="right">
<html:submit>Save</html:submit>
</td>
<td align="left">
<html:cancel>Cancel</html:cancel>
</td>
</tr>
</table>
</div>

<!-- Begin Validator Javascript Function-->
<html:javascript formName="AddressForm"/>
<!-- End of Validator Javascript Function-->

</html:form>
</body>
</html:html>

The code <html:javascript formName="AddressForm"/> is used to plug-in the Validator JavaScript.

Create the following entry in the struts-config.xml for the mapping the /AddressJavascriptValidation url for handling the form submission through AddressJavascriptValidation.jsp.

<action
     path="/AddressJavascriptValidation"
     type="roseindia.net.AddressAction"
     name="AddressForm"
     scope="request"
     validate="true"
     input="/pages/AddressJavascriptValidation.jsp">
     <forward name="success" path="/pages/success.jsp"/>
</action>

Add the following line in the index.jsp to call the form.

<li>
<html:link page="/pages/AddressJavascriptValidation.jsp">Client Side Validation for Address Form</html:link>
<br>
The Address Form that validates the data on the client side using Stuts Validator generated JavaScript.
</li>

Building Example and Testing

To build and deploy the application go to Struts\strutstutorial directory and type ant on the command prompt. This will deploy the application. Open the browser and navigate to the AddressJavascriptValidation.jsp page. Your browser should show the following out put.

If the fields are left blank and Save button is clicked, browser shows the error message.

In this lesson you learned how to use Struts Validator Framework to validate the form on client browser.

 

 

 

 

 

 

 

 

 

 

What is Struts Tiles?
Tiles is a framework for the development user interface. Tiles is enables the developers to develop the web applications by assembling the reusable tiles (jsp, html, etc..). Tiles uses the concept of reuse and enables the developers to define a template for the web site and then use this layout to populate the content of the web site. For example, if you have to develop a web site having more that 500 page of static content and many dynamically generated pages. The layout of the web site often changes according to the business requirement. In this case you can use the Tiles framework to design the template for the web site and use this template to populate the contents. In future if there is any requirement of site layout change then you have to change the layout in one page. This will change the layout of you whole web site.

Steps To Create Tiles Application
Tiles is very useful framework for the development of web applications. Here are the steps necessary for adding Tiles to your Struts application:

  1. Add the Tiles Tag Library Descriptor (TLD) file to the web.xml.
  2. Create layout JSPs.
  3. Develop the web pages using layouts.
  4. Repackage, run and test application.

Add the Tiles TLD to web.xml file
Tiles can can be used with or without Struts. Following entry is requiblak in the web.xml file before you can use the tiles tags in your application.

<taglib>
     <taglib-uri>/tags/struts-tiles</taglib-uri>
      <taglib-location>/WEB-INF/struts-tiles.tld</taglib-location>
</taglib>

   
Create layout JSPs.

Our web application layout is divided into four parts: To Banner, Left Navigation Bar, Content Area and Bottom of the page for copy right information. Here is the code for out template (template.jsp):

<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<html>

<head>
    <title>
<tiles:getAsString name="title" ignore="true"/></title>
</head>

<body>

<table border="1" cellpadding="0" cellspacing="0" width="100%" bordercolor="#000000" bgcolor="#E7FDFE">
<tr>
<td width="100%" colspan="2" valign="top">
<tiles:insert attribute="header"/></td>
</tr>
<tr>
<td width="23%">
<tiles:insert attribute="menu"/></td>
<td width="77%" valign="top" valign="top">
<tiles:insert attribute="body"/></td>
</tr>
<tr>
<td width="100%" colspan="2" valign="top">
<tiles:insert attribute="bottom"/></td>
</tr>
</table>

</body>

</html>

We have defined the structure for web application using the appropriate html and did the following things:

  • Referenced the /WEB-INF/struts-tiles.tld TLD.
  • Used the string parameters to display title using the tiles:getAsString tag. If the attribute ignore="true" then Tiles ignore the missing parameter. If this is true then the Tiles framework will through the exception in case the parameter is missing.
  • To insert the content JSP, the tiles:insert tag is used, which inserts any page or web resources that framework refers to as a title. For Example <tiles:insert attribute="header"/> inserts the header web page.

Develop the web pages using layouts
Now we will use tile layout create a page to display the content page in the in our application. For every content page there is additional jsp file for inserting the content in the Layout, so we have to create two jsp files one for content and another for displaying the content. In our example these file are example.jsp and content.jsp. Here is the code for both the files:

content.jsp

<p align="left"><font color="#000080" size="5">Welcome to the Title Tutorial</font></p>
<p align="left"><font color="#000080" size="5">This is the content page</font></p>

The content.jsp simply define the content of the page. The content may be dynamic or static depending on the requirements.

example.jsp

<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>

<tiles:insert page="/tiles/template.jsp" flush="true">
   <tiles:put name="title" type="string" value="Welcome" />
   <tiles:put name="header" value="/tiles/top.jsp" />
   <tiles:put name="menu" value="/tiles/left.jsp" />
   <tiles:put name="body" value="/tiles/content.jsp" />
   <tiles:put name="bottom" value="/tiles/bottom.jsp" /> 
</tiles:insert>

The code <tiles:insert page="/tiles/template.jsp" flush="true"> specifies the tiles layout page to be used. We have set the flush attribute to true, this makes the tile file to be written to browser before the rest of the page. To specify the title of the page <tiles:put name="title" type="string" value="Welcome" /> is used. The following code is used to insert the actual pages in the template.:

   <tiles:put name="header" value="/tiles/top.jsp" />
   <tiles:put name="menu" value="/tiles/left.jsp" />
   <tiles:put name="body" value="/tiles/content.jsp" />
   <tiles:put name="bottom" value="/tiles/bottom.jsp" /> 

The top.jsp will be inserted in the layout's header region. The left.jsp will be inserted in the layout's menu region. The content.jsp wil be inserted in the layout's body region and the bottom.jsp will be inserted in the bottom region.

Repackage, run and test application
Add the following code in the index.jsp to test the this tile example:

<li>
<html:link page="/tiles/example.jsp">Tiles Example</html:link>
<br>
Example of creating first tile application.
</li>

Use the ant tool to build the application and deploy on the server. To test the application go to the index.jps and click on the Tiles Example link.

In the last section we studied how to forward the request (call) to a jsp page which specifies which tiles layout definition should be used to apply to the content. In this section I will show you how to use the a definition in the tiles-defs.xml for generating the content. 

In Tiles we can define the definition in the tiles-defs.xml which specifies the different components to "plugin" to generate the output. This eliminates the need to define extra jsp file for each content file. For example in the last section we defined example.jsp to display the content of content.jsp file. In this section I will show you how to eliminate the need of extra jsp file using tiles-defs.xml file.

Steps to Use the tiles-defs.xml

Setup the Tiles plugin in struts-config.xml file. 
Add the following code in the struts-config.xml (If not present). This enables the TilesPlugin to use the /WEB-INF/tiles-defs.xml file.

   

<plug-in className="org.apache.struts.tiles.TilesPlugin" >
       <!-- Path to XML definition file -->
       <set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml" />
       <!-- Set Module-awareness to true -->
       <set-property property="moduleAware" value="true" />
</plug-in>

Defining the tiles-defs.xml
In this file we are defining the different components to "plugin". Here is the code:

     <definition name="Tiles.Example" page="/tiles/template.jsp">
          <put name="title" type="string" value="Welcome" />
          <put name="header" value="/tiles/top.jsp" />
          <put name="menu" value="/tiles/left.jsp" />
          <put name="body" value="/tiles/content.jsp" />
          <put name="bottom" value="/tiles/bottom.jsp" /> 
     </definition>

The name of the definition is Tiles.Example, we will use this in struts-config.xml (While creating forwards in struts-config.xml file) file. The page attribute defines the template file to be used and the put tag specifies the different components to "plugin". Your tiles-defs.xml should look like:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/tiles-config_1_1.dtd">

<tiles-definitions>


     <definition name="Tiles.Example" page="/tiles/template.jsp">
          <put name="title" type="string" value="Welcome" />
          <put name="header" value="/tiles/top.jsp" />
          <put name="menu" value="/tiles/left.jsp" />
          <put name="body" value="/tiles/content.jsp" />
          <put name="bottom" value="/tiles/bottom.jsp" /> 
     </definition>


<definition name="${YOUR_DEFINITION_HERE}">
</definition>

</tiles-definitions>

Configure the Struts Action to use Tiles Definition
Open the struts-config.xml file and add the following code:

<action path="/Tiles/Example"
       forward="Tiles.Example"/>

With Tiles, the action points to the Tiles definition, as shown in the above code. In this code we are using the Tiles.Example definition which we have defined in the tiles-defs.xml file. Without Tiles, forward and action definitions point directly to JSPs. With Tiles, they point to the page's definition in the Tiles configuration file.

Testing the Application
Create a link in index.jsp to call the Example. Code added are: 

<li>
<html:link page="/Tiles/Example.do">Using tiles-defs.xml</html:link>
<br>
Example shows you how to use tiles-defs.xml file.
</li>

To test the application build it using ant and deploy on the JBoss server. Type http://localhost:8080/strutstutorial/index.jsp in the bowser and select the Using tiles-defs.xml link. Your browser should show the page.

 

 

 

 

 

In this tutorial you will learn how to create Struts DynaActionForm. We will recreate our address form with Struts DynaActionForm. DynaActionForm is specialized subclass of ActionForm that allows the creation of form beans with dynamic sets of properties, without requiring the developer to create a Java class for each type of form bean. DynaActionForm eliminates the need of FormBean class and now the form bean definition can be written into the struts-config.xml file. So, it makes the FormBean declarative and this helps the programmer to blakuce the development time.

In this tutorial we will recreate the add form with the help of DynaActionForm. It also shows you how you can validate use input in the action class. 

Adding DynaActionForm Entry in struts-config.xml

First we will add the necessary entry in the struts-config.xml file.  Add the following entry in the struts-config.xml file. The form bean is of org.apache.struts.action.DynaActionForm type. The <form-property/> tag is used to define the property for the form bean. We have defined three properties for our dynamic form bean.

<form-bean name="DynaAddressForm"   
         type="org.apache.struts.action.DynaActionForm">
         <form-property name="name" type="java.lang.String"/>
         <form-property name="address" type="java.lang.String"/>
         <form-property name="email" type="java.lang.String" />
</form-bean>

Adding action mapping

Add the following action mapping in the struts-config.xml file:

<action path="/DynaAddress" type="roseindia.net.AddressDynaAction"
     name="DynaAddressForm"
     scope="request"
     validate="true"
     input="/pages/DynaAddress.jsp">

    <forward name="success" path="/pages/success.jsp"/>
    <forward name="invalid" path="/pages/DynaAddress.jsp" />

</action>

Creating Action Class

Code for action class is as follows:

package roseindia.net;

/**
@author Deepak Kumar
* @Web http://www.roseindia.net
* @Email roseindia_net@yahoo.com
*/

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.action.ActionMessage;


public class AddressDynaAction extends Action
{
  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response) throws Exception{

    DynaActionForm addressForm = (DynaActionForm)form;

    //Create object of ActionMesssages
        ActionMessages errors = new ActionMessages();
    //Check and collect errors
        if(((String)addressForm.get("name")).equals("")) {
         errors.add("name",new ActionMessage("error.name.requiblak"));
        }

        if(((String)addressForm.get("address")).equals("")) {
         errors.add("address",new ActionMessage("error.address.requiblak"));
        }

        if(((String)addressForm.get("email")).equals("")) {
         errors.add("email",new ActionMessage("error.emailaddress.requiblak"));
        }
    //Saves the error
    saveErrors(request,errors);
    //Forward the page
    if(errors.isEmpty()){
    return mapping.findForward("success");
    }else{
    return mapping.findForward("invalid");
    }
  }
}

Creating the JSP file

We will use the Dyna Form DynaAddressForm created above in the jsp file. Here is the code of the jsp(DynaAddress.jsp) file.

<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>

<html:html locale="true">
<head>
<title><bean:message key="welcome.title"/></title>
<html:base/>
</head>
<body bgcolor="white">
<html:form action="/DynaAddress" method="post">
<table>
<tr>
<td align="center" colspan="2">
<font size="4">Please Enter the Following Details</font>
</tr>

<tr>
<td align="left" colspan="2">
<font color="blak"><html:errors/></font>
</tr>



<tr>
<td align="right">
Name
</td>
<td align="left">
<html:text property="name" size="30" maxlength="30"/>
</td>
</tr>
<tr>
<td align="right">
Address
</td>
<td align="left">
<html:text property="address" size="30" maxlength="30"/>
</td>
</tr>

<tr>
<td align="right">
E-mail address
</td>
<td align="left">
<html:text property="email" size="30" maxlength="30"/>
</td>
</tr>

<tr>
<td align="right">
<html:submit>Save</html:submit>
</td>
<td align="left">
<html:cancel>Cancel</html:cancel>
</td>
</tr>
</table>


</html:form>
</body>
</html:html>

Add the following line in the index.jsp to call the form.

<li>
<html:link page="/pages/DynaAddress.jsp">Dyna Action Form Example</html:link>
<br>
Example shows you how to use DynaActionForm.
</li>

Building Example and Testing

To build and deploy the application go to Struts\strutstutorial directory and type ant on the command prompt. This will deploy the application. Open the browser and navigate to the DynaAddress.jsp page. Without entering anything in the form and submitting the submit button, your browser should show the following out put.

 

Struts File Upload Example

 

In this tutorial you will learn how to use Struts to write program to upload files. The interface org.apache.struts.upload.FormFile is the heart of the struts file upload application. This interface represents a file that has been uploaded by a client. It is the only interface or class in upload package which is typically referenced directly by a Struts application.

Creating Form Bean

Our form bean class contains only one property theFile,  which is of type org.apache.struts.upload.FormFile. Here is the code of FormBean (StrutsUploadForm.java):

import org.apache.struts.action.*;
import org.apache.struts.upload.FormFile;

/**
 * Form bean for Struts File Upload.
 *
*/
public class StrutsUploadForm extends ActionForm
{
  private FormFile theFile;

  /**
   @return Returns the theFile.
   */
  public FormFile getTheFile() {
    return theFile;
  }
  /**
   @param theFile The FormFile to set.
   */
  public void setTheFile(FormFile theFile) {
    this.theFile = theFile;
  }
}

 

 

 

 

 

Creating Action Class

Our action class simply calls the getTheFile() function on the FormBean object to retrieve the reference of the uploaded file. Then the reference of the FormFile is used to get the uploaded file and its information. Here is the code of our action class(StrutsUploadAction.java):

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;

/**
 * Struts File Upload Action Form.
 *
*/
public class StrutsUploadAction extends Action
{
  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response) throws Exception{
    StrutsUploadForm myForm = (StrutsUploadForm)form;

        // Process the FormFile
        FormFile myFile = myForm.getTheFile();
        String contentType = myFile.getContentType();
        String fileName    = myFile.getFileName();
        int fileSize       = myFile.getFileSize();
        byte[] fileData    = myFile.getFileData();
    System.out.println("contentType: " + contentType);
    System.out.println("File Name: " + fileName);
    System.out.println("File Size: " + fileSize);
    
      return mapping.findForward("success");
  }
}

 

Defining form Bean in struts-config.xml file

Add the following entry in the struts-config.xml file for defining the form bean:

<form-bean
    name="FileUpload"
    type="roseindia.net.StrutsUploadForm"/>

Defining Action Mapping

Add the following action mapping entry in the struts-config.xml file:

<action
     path="/FileUpload"
     type="roseindia.net.StrutsUploadAction"
     name="FileUpload"
     scope="request"
     validate="true"
     input="/pages/FileUpload.jsp">
     <forward name="success" path="/pages/uploadsuccess.jsp"/>
</action>

Developing jsp page

Code of the jsp (FileUpload.jsp) file to upload is as follows:

<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>

<html:html locale="true">
<head>
<title>Struts File Upload Example</title>
<html:base/>
</head>
<body bgcolor="white">
<html:form action="/FileUpload" method="post" enctype="multipart/form-data">
<table>
<tr>
<td align="center" colspan="2">
<font size="4">Please Enter the Following Details</font>
</tr>

<tr>
<td align="left" colspan="2">
<font color="blak"><html:errors/></font>
</tr>



<tr>
<td align="right">
File Name
</td>
<td align="left">
<html:file property="theFile"/> 
</td>
</tr>


<tr>
<td align="center" colspan="2">
<html:submit>Upload File</html:submit>
</td>
</tr>
</table>


</html:form>
</body>
</html:html>

Note that we are setting the encrypt property of the form to enctype="multipart/form-data".

code for the success page (uploadsuccess.jsp) is:

<html>

<head>
<title>Success</title>
</head>

<body>

<p align="center"><font size="5" color="#000080">File Successfully Received</font></p>

</body>

</html>

Add the following line in the index.jsp to call the form.

<li>
<html:link page="/pages/FileUpload.jsp">Struts File Upload</html:link>
<br>
Example shows you how to Upload File with Struts.
</li>

Building Example and Testing

To build and deploy the application go to Struts\strutstutorial directory and type ant on the command prompt. This will deploy the application. Open the browser and navigate to the FileUpload.jsp page. Your browser should display the file upload form:
  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

In this tutorial we shall see how to implement Internationalization (abbreviated as I18N) in Struts.

The Multinational Corporations have their branches in various parts of the world. so, they must provide products and services to their clients and customers in their traditional way. The customers will expect the product to work in their native languages especially the date, time, currency etc.,. So, the we should not make any assumptions about their clients region or language. If such assumptions become invalid, we have to re-engineer the applications.

Internationalization or I18N is the process of designing the software to support multiple languages and regions, so that we don't need to re-engineer the applications every language or country needs to be supported.

Struts provides various locale sensitive JSP tags which can be used to make the applications simpler. With this short introduction we shall see how to implement i18n in a Simple JSP file of Struts.

 


g:\>md localedemo
g:\>cd localedemo
g:\localedemo>edit localedemo.jsp

// g:\localedemo\localedemo.jsp

<%@ page language="java" %>

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<html:html locale="true">
<body bgcolor=pink>

<bean:message key="index.info" />

</body>
</html:html

 

Next copy struts-blank.war to f:\tomcat41\webapps and start the tomcat with JAVA_HOME as jdk1.4. A folder named struts-blank will be created. Rename the folder as localedemo. Copy the above JSP file to f:\tomcat41\webapps\localedemo.

Now we have to edit the property files for various locales. The struts framework(struts1.1) provides a property file named application.properties. It is present in the folder f:\tomcat41\webapps\localedemo\web-inf\classes\resources. We have to add our own property file in this folder only. Our property file much be named along with the language code

For example the language code of
    
1. German - de
     2. Spanish - es
     3. English - en
     4. Korean - ko
     5. French - fr
     6. Italy - it

So, when we write i18n message in German language it must be placed in property file named application_de.properties and all the properties files must be present in the resources folder only. Also when we write the property file of a particular language it need not be of the same language. For example we can create application_de.properties and write the message in french or english. In fact, the message does not depend on any language. It is a simple key value pair. The message we give for the key is just substituted. The property file to locate the value of key depends on the language settings of the browser. For this example, we will write four properties file as follows.

f:\tomcat41\webapps\localedemo\web-inf\classes\resources\ application_de.properties

index.info=GERMANY
---------------------------------------------------------
f:\tomcat41\webapps\localedemo\web-inf\classes\resources\ application_es.properties

index.info=SPAIN
-----------------------------------------------------------
f:\tomcat41\webapps\localedemo\web-inf\classes\resources\ application_en.properties

index.info=ENGLISH
-----------------------------------------------------------
f:\tomcat41\webapps\localedemo\web-inf\classes\resources\ application_fr.properties

index.info=FRANCE
------------------------------------------------------------
Also append this text in the application.properties file
    index.info=STRUTS TUTORIAL.

Now we have to add entry in the
struts-config.xml file for all the properties files. The entry and its corresponding portion is shown below.

<!-- Message Resources Definitions -->

        <message-resources parameter="resources.application_fr"/>
        <message-resources parameter="resources.application_es"/>
        <message-resources parameter="resources.application_en"/>
        <message-resources parameter="resources.application_de"/>
        <message-resources parameter="resources.application"/>

Now restart the Tomcat server. Open the Internet Explorer and type the URL as http://localhost:8080/localedemo/localedemo.jsp. We will get the message 'ENGLAND'. This is because our default browser language is 'United States English'.

Now we have to change the language settings of the browser to change the locale. For that, Open a new Internet Explorer, goto 'Tools' menu and select the 'Internet Options'. In the 'Internet Option' dialog box, select 'General' tab and click the 'Languages...' button. We will get 'Language Preference' dialog box. There click 'Add...' button and add the languages. For this example add English, Spanish, German and French. Here we have languages specific to particular region. For example we have, French Belgium, French Canada, French France etc., we can select any one of these in all cases. Next select 'German' and by using the 'Move up' button, place it on the top. Now type the URL as http://localhost:8080/localedemo/localedemo.jsp. We will get the message 'GERMAN' Similarly place 'Spanish' and 'French' at the top, we will get the message 'SPAIN' and 'FRANCE' respectively.
---------------------------------------------------------------------------

 

Struts error reporting

Struts was using two different classes to report errors and messages back to the user: ActionErrors and ActionMessages. As the ActionErrors and ActionError classes were deprecated since 1.2.0. version I will talk now only about ActionMessages and ActionMessage.

From an action class when you need to send a message to the page all that must be done is to set it up using the ActionMessages class.

Struts ActionMessages example:

ActionMessages actionMessages = new ActionMessages();
actionMessages.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("my.error"));
saveMessages(request, actionMessages);

This error will be displayed in JSP using:

<logic:messagesPresent message="true">
<html:messages message="true" id="msg">
<bean:write name="msg" ignore="true"/>
</html:messages>
</logic:messagesPresent>

One issue to be mentioned here is that "my.error" is a key that will be used to look up message text in an appropriate message resources database, like Application.properties for example.

But if you do not need to report a generic error message you will have to use the following code:

ActionMessages actionMessages = new ActionMessages();
actionMessages.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("my.error"));
request.setAttribute("warnings", actionMessages);

This code will set up an error message under an arbitrary key and display it with the html:messages tag:

<html:messages name="warnings" id="message">
<bean:write name="message" />
</html:messages>

There are some differences to be noticed here.

  1. There is no message="true" attribute present that signals to look up for an ActionMessage under the Globals.MESSAGE_KEY.
  2. There is no <logic:messagePresent> tag as it will not be validated.

If your error message gets constructed dynamically the ActionMessage class offers four constructors that allow message customization with up to four parameters.

So the message:

new ActionMessage("my.error", "p1", "p2", "p3", "p4")

where

my.error=You are not allowed to do {0}, {1}, {2} and {3}

will render

You are not allowed to do p1, p2, p3 and p4

Use Declarative Exception Handling

Specifying runtime behavior outside of the source code rather than hardcoding it within the application is almost always preferblak; the world of J2EE is filled with examples of this. From the security and transactional behavior of Enterprise JavaBeans to the relationships between JMS messages and destinations, many of the runtime aspects can be declablak outside of the application.

The Struts architects have taken this approach from the beginning by utilizing the Struts configuration file to specify runtime aspects of an application. That approach continues with the new 1.1 features, including the new exception-handling capabilities. In earlier versions of the framework, developers were left to their own devices when handling error situations that occurblak in a Struts application. With the latest version, that's no longer the case. The framework includes a class called ExceptionHandler that by default is responsible for processing any exceptions that occur during action execution. As the previous tip on extending the framework mentioned, this is one of the many extension points that is available within the framework.

The default Struts exception handler class creates an ActionError object and stores it in the appropriate scope object. This allows the JSP pages to use the errors to inform the user of a problem. If this behavior does not fulfill your requirements, you are free to plug in one of your own ExceptionHandler classes.

Customizing the Exception Handling

To install your customized exception handler, the first step is to create a class that extends org.apache.struts.action.ExceptionHandler. There are two methods that you can override, execute() and storeException(). In most cases, however, you will just need to override the execute() method. The signature for the execute() method in the ExceptionHandler class is shown here:

public ActionForward execute( Exception ex, 
                              ExceptionConfig exConfig,
                              ActionMapping mapping,
                              ActionForm formInstance,
                              HttpServletRequest request,
                              HttpServletResponse response
  ) throws ServletException;

The method takes in several arguments, including the original exception, and returns an ActionForward object, which directs the controller as to where the request should be forwarded after the exception is dealt with.

You can perform whatever behavior you like, but generally you should inspect the exception that was thrown and do something based on the type of exception. Again, the default behavior is to create an error message and forward to the resource specified in the configuration file. An example of why you would want or need to customize this functionality is to support nested exceptions. Suppose the exception contained nested exceptions, and those exceptions also may contain other exceptions. You would need to override the execute() method to create error messages for each of these.

Once you have created your specialized ExceptionHandler class, you will need to inform the Struts framework to use your version instead of the default Struts exception handler. To do this, you will just need to declare your class in the Struts configuration file; this is the declarative part.

You can configure your ExceptionHandler to be used by certain Action mappings or by all Actions. For specific Action mappings, you include an <exception> element inside of the <action> element. To utilize the ExceptionHandler for all Action mappings, you can specify it inside the <global-sections> element. For example, suppose we want to use a customized exception handler called CustomizedExceptionHandler for all Action mappings. The <global-exceptions> element might look like this:

<global-exceptions>
  <exception
    handler="com.cavaness.storefront.CustomizedExceptionHandler"
    key="global.error.message"
    path="/error.jsp"
    scope="request"
    type="java.lang.Exception"/>
</global-exceptions>

There are various attributes that you can specify for the <exception> element. The most important of these, for this discussion, is the handler attribute. This attribute is the fully- qualified class name of the ExceptionHandler subclass. If this attribute is not specified, the framework will default to the one provided by the Struts framework. The other attributes are also important, but this one is of the utmost importance if you are trying to override the default behavior.

One final thing should be pointed out. You can have different exception handlers for different exceptions. In the example above, the CustomizedExceptionHandler was configublak to process any exceptions that were children of java.lang.Exception. However, you can create multiple exception handlers, each one worrying about different exception trees. The following XML fragment shows how this can be configublak:

<global-exceptions>
  <exception
    handler="com.cavaness.storefront.CustomizedExceptionHandler"
    key="global.error.message"
    path="/error.jsp"
    scope="request"
    type="java.lang.Exception"/>
 
  <exception
    handler="com.cavaness.storefront.SecurityExceptionHandler"
    key="security.error.message"
    path="/login.jsp"
    scope="request"
    type="com.cavaness.storefront.SecurityException"/>
</global-exceptions>

In this case, when an exception is thrown, the framework will attempt to find an ExceptionHandler configublak for the exact match. If there's no exact match, the framework will proceed up the superclass chain of the exception until a match is found. With this approach, you can have a hierarchical relationship of handlers, and all of it declarative.

Struts Internationalization (i18n)

Struts Internationalization (i18n) can be done with some handy modifications in our existing application. We have to know the two Internationalization (i18n) components that are packaged with the Struts Framework. The first of these components, which is managed by the application Controller, is a Message class that references a resource bundle containing Locale-dependent strings. The second Internationalization (i18n) component is a JSP custom tag, <bean:message />, which is used in the View layer to present the actual strings managed by the Controller.

In this section we will move with an example to understand the whole process. We are continuing the same example which we used earlier to understand the simple struts example in the section Struts Example.

First thing we will require for Internationalization (i18n) is a set of simple Java properties files. Each file contains a key/value pair for each message that you expect your application to present, in the language appropriate for the requesting client.

This property file contains the key/value pairs for the default language of your application. The naming format for this file is ResourceBundleName.properties. An example of this default file, using English as the default language, would be ApplicationResources.properties A sample entry in this file would be app.name=Name, this tells Struts that for every occurrence of the app.name key the Name will be substituted.

We must define a properties file for each language that your application will use. This file must follow the same naming convention as the default properties file, except that it must include the two-letter ISO language code of the language that it represents. Example of this naming convention
For an German-speaking client would be ApplicationResources_de.properties
For an French-speaking client would be ApplicationResources_fr.properties
For an Italian-speaking client would be ApplicationResources_it.properties
For an Spanish-speaking client would be ApplicationResources_es.properties

Now add the respective entries in each properties files you require.

After you define all of the properties files for your application, you need to make Struts aware of them. It is achieved by adding a <message-resources> sub-element to the struts-config.xml file. Then you should copy all the resource bundles into the application classpath, /WEB-INF/classes/example, and then use the package path plus the base file name as the value of the <message-resources> subelement. The following snippet shows an example of using the <message-resources> subelement to configure a resource bundle, using the properties files described above

<message-resources parameter="example.ApplicationResources"/>

Once this part is done we customise the view part , this is achieved throught the second i18n component defined by the Struts Framework is a JSP custom tag, <bean:message />, which is used to present the actual strings that have been loaded by the Controller.

To use the <bean:message />, we must first deploy the bean tag library, which contains the <bean:message /> tag. Deploying a tag library is a very simple process that requires only the addition of a new <taglib> entry in the web.xml file of the Web application using the bean library. Here is an example of this
entry:

<taglib>

 

<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>

</taglib>

Also check that the struts-bean.tld file is copied to the /WEB-INF/ folder.


<bean:message /> tag and how it is configublak for use.

Now we are done we will check step by step of our saple application.

1. WeCreate the resource bundles that will contain the key/value pairs used in your application. For our application, we will have four properties files that contain our resource bundles.

The German ApplicationResources_de.properties file.
app.name=Name
app.hello=Hallo

The French ApplicationResources_fr.properties file.
app.name=Nom
app.hello=Bonjour

The Italian ApplicationResources_it.properties file.
app.name=Nome
app.hello=Ciao

The Spanish ApplicationResources_fr.properties file.
app.name=Nombre
app.hello=Hola

The English ApplicationResources.properties file.
app.name=Name
app.hello=Hello

2. Copy all of the properties files to the /WEB-INF/classes/example directory.
Add an application <message-resources /> subelement, naming the wiley. ApplicationResources to the struts-config.xml file, as shown

<struts-config>

 

<form-beans>

 

 

<form-bean name="nameForm" type="example.NameForm"/>

 

</form-beans>

 

<action-mappings>

 

 

<action path="/Name" type="example.NameAction" name="NameForm" >

 

 

 

<forward name="success" path="/quote.jsp"/>
<forward name="failure" path="/index.jsp"/>

 

 

</action>

 

</action-mappings>

 

 

 

<message-resources parameter="example.ApplicationResources"/>

</struts-config>

3. Modify the web.xml file as discussed above by adding

<taglib>

 

<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>

</taglib>


4. Modify the index.jsp file
index.jsp

<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>

<html>
<head>
<title>Sample Struts Application</title>
</head>
<body>

 

<html:form action="Name" name="nameForm" type="example.NameForm">

 

 

<table width="80%" border="0">

 

 

 

<tr>

 

 

 

 

<td><bean:message key="app.name" />:</td>

 

 

 

 

<td><html:text property="name" /></td>

 

 

 

</tr>

 

 

 

<tr>

 

 

 

 

<td><html:submit /></td>

 

 

 

</tr>

 

 

</table>

 

</html:form>

</body>
</html>

Modify the diplayname.jsp
displayname.jsp


<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>

<html>
<head>
<title>Sample Struts Display Name</title>
</head>
<body>

 

 

<table width="80%" border="0">

 

 

 

<tr>

 

 

 

 

<td><bean:message key="app.hello" /><%= request.getAttribute("NAME") %> !!</td>

 

 

 

</tr>

 

 

</table>

</body>
</html>

So we are done with Internationalization (i18n) you need to open your Web browser to the following URL:
http://localhost:port/example/

 

Struts Best Practices

 

Introduction
Struts, a Jakarta project hosted by Apache, is a framework for building Web applications based on the MVC2 design pattern. The framework, built upon standard technologies like Java Servlets, JavaBeans, ResourceBundles, and XML, aims to provide an extensible Web application architecture that the development team can build on. The use of Struts enforces modularity and separation of concern, increases code manageablity, extensibility, and consistency.

The information flow of an application based on the Struts framework is shown in the following figure:


Fig. 1: Information Flow in a Struts application


As shown in the figure, all user requests are dispatched through the Controller, which controls the flow of the application thereon. The Controller creates Action classes, which are built by the developer to perform the work of the application. These Action classes extend the Struts Action class, and the Action instances create Model Beans that perform domain specific activities. Depending on the user request it calls different actions on the Model. The Model represents the application data and business rules. Although Struts doesn't provide any model object, at times, ActionForms are referblak to as models. The Controller gets the user inputs from the View. Though Struts in itself doesn't provide any View component, it provides a number of JSP custom tags that facilitates UI development in JSP.

Let's do a quick rundown of the Struts components that are relevant from the context of this article:

  • Actions: Actions are multi-threaded like servlets. They communicate with the Model, invoke business logic, and return the Model objects to the View. All application Actions have to extend Struts' org.apache.struts.action.Action. Every Action has to provide application specific implementation by overriding the execute() method.
  • ActionForm: ActionForm provides data transfer to and from HTML forms. They also provide field validations. Every application ActionForm has to extend Struts' org.apache.struts.action.ActionForm and provide application specific implementation of validate() method.
  • ActionErrors: ActionErrors are a collection of ActionError instances that are used to support exception handling. They encapsulate error messages that are displayed in the Presentation layer through .
  • Struts-config.xml: The struts-config.xml file is the deployment descriptor for Struts-based applications. It has to confirm to the Document Type Definition (DTD) provided at http://struts.apache.org/dtds/struts-config_1_2.dtd.

Best Practices
We shall use an Online Shopping Application example to highlight the best practices that can be followed in the Struts-based implementation of a typical Web-based J2EE application. Such an application typically includes features such as a search catalogue, browse item details, shopping cart updation, purchase order submission, customer profile maintenance, and user registration. In the following sections we shall see how to follow certain techniques to fine tune the features of such an application.

Use intermediate Action class for common operations
At times, common operations need to be included in all the actions. An example of such a requirement in our sample Online Shopping application would be to perform user authorization before processing all user requests. However, including common operations in the execute() method of all Action class results in code blakundancy. Instead, add an intermediate Action class and make all other Action classes extend that to centralize the handling of common operations and blakuce code blakundancy.

The steps are as follows:

Create an intermediate Action class, say BaseApplicationAction, by extending org.apache.struts.action.ActionAdd an abstract method, say executeSpecificTask(), that has the following signature:

public abstract ActionForward executeSpecificTask
(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception

Add all the common methods of the application; for example, performAuthorization()Call all the common methods (like performAuthorization) inside the execute() method, and follow it with executeSpecificTask()All other Action classes should extend BaseApplicationAction, not org.apache.struts.action.ActionThe extended Action classes provide the specific implementations for the executeSpecificTask() method

The aforementioned steps have been implemented in the following code snippet:

Listing 1: Intermediate Action Class

Public class BaseApplicationAction extends Action
{
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception
{
try
{
//Call all common methods
performAuthorization();
return executeSpecificTask(mapping,form,request,response);
}
catch(Exception ex){//exception}
}
// Authorization is an operation common through all the application actions
private void performAuthorization ()
{
//Code for user authorization
}

//Provide implementation of this method in sub-classes
public abstract ActionForward executeSpecificTask
(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception
}

Use DispatchAction to group related actions into a single class
Often we need to perform a group of related actions on the same domain object. For example, in the Online Shopping application customers should have a provision to add, delete, or modify an item in the shopping cart. This can be implemented using the execute() method of Action classes, wherein there will be one Action class for each business method. Struts provides a better option by clubbing these distinct, yet related, actions in a single DispatchAction class. (http://struts.apache.org/api/org/apache/struts/actions/DispatchAction.html). This blakuces code blakundancy thereby easing the maintenance.

The steps are as follows:

The Action class extends org.apache.struts.action.DispatchAction instead of org.apache.struts.action.ActionAdd separate methods having same signature as execute(), as shown in the following code bit:

Listing 2: Using DispatchAction

public class ItemAction extends DispatchAction
{
public ActionForward addItem(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception
{
try
{
// Code for item add
}
catch(Exception ex){//exception}
}

public ActionForward deleteItem(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception
{
try
{
// Code for item deletion
}
catch(Exception ex){//exception}
}

public ActionForward updateItem(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception
{
try
{
// Code for item update
}
catch(Exception ex){//exception}
}
}

Make the following entry in struts-config.xml:

<action
path="/item"
type=" com.infosys.j2ee.sample.web.actions.ItemAction"
name="itemForm"
scope="request"
validate="true"
parameter="actionType"/>

The method can be invoked using a URL, like this: ItemAction.do?actionType=addItem

Handle duplicate form submission
The problem of duplicate form submission arises when a user clicks the Submit button more than once before the response is sent back or when a client accesses a view by returning to a previously bookmarked page. This may result in inconsistent transactions and must be avoided. In our sample application, a similar problem will arise if the customer clicks the submit button more than once while submitting the purchase order.

In Struts this problem can be handled by using the saveToken() and isTokenValid() methods of Action class. saveToken() method creates a token (a unique string) and saves that in the user's current session, while isTokenValid() checks if the token stoblak in the user's current session is the same as that was passed as the request parameter.

To do this the JSP has to be loaded through an Action. Before loading the JSP call saveToken() to save the token in the user session. When the form is submitted, check the token against that in the session by calling isTokenValid(), as shown in the following code snippet:

Listing 3: Using saveToken() and isTokenValid()

public class PurchaseOrderAction extends DispatchAction
{
public ActionForward load(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception
{
try
{ //save the token
saveToken(request)

// rest of the code for loading the form
}
catch(Exception ex){//exception}
}

public ActionForward submitOrder(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception
{
try
{
// check the token. Proceed only if token is valid
if(isTokenValid(request,true)) {
//implement order submit functionality here
} else {
return mapping.findForward("failure");
}
}
catch(Exception ex){//exception}
}
}

Use Application Modules for parallel development
In large projects with multiple modules, sharing the same Struts configuration file among different developers becomes an issue. Struts provides application modules to divide single monolithic applications into multiple modules each having its own Actions, ActionForms, configuration files, etc. This helps in parallel development in large development teams. In our sample application we can use multiple configuration files for different modules (customer maintenance, order processing, etc.) to facilitate effective parallel development.

The steps are as follows:

Create separate configuration files for each module; for example, struts-config-customermaintenance.xml, struts-config-orderprocessing.xml, and struts-config.xml (default configuration file).Make entries in the Web deployment descriptor, web.xml. The default entry for a single configuration file is:

<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>

Replace the default entry with the following:

<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>config/module1</param-name>
<param-value>/WEB-INF/struts-config-customermaintenance.xml</param-value>
</init-param>
<init-param>
<param-name>config/module2</param-name>
<param-value>/WEB-INF/struts-config- orderprocessing.xml</param-value>
</init-param>

Use org.apache.struts.actions.SwitchAction to switch from one module to another. Refer http://struts.apache.org/userGuide/configuration.html#dd_config_modules for more details.

Use single ActionForm for similar forms
For similar forms, use a single ActionForm that includes all possible fields instead of having several ActionForms. This is generally applicable to different forms requiblak to implement the same use case. It leads to easy maintenance, though all the fields will be not be used for all the Actions. For example, in the Online Shopping application we can use a single ActionForm (CustomerProfileForm) for different forms related to customer profile management (like DisplayCustomerProfile.jsp, EditCustomerProfile.jsp, etc.).

Use global-forwards to avoid blakundant forwards
The element allows configuring forwards that are used by multiple actions in a module. This helps to avoid mentioning for all the actions. For instance, the Online Shopping application should display the login page in case of session timeout. Instead of including for all the actions, add a single entry in the struts-config.xml to throw the login.jsp to the user in case of session timeout encounteblak in any Action, like this:

<global-forwards>
<!-- session timeout or invalid session, displays login page -->
<forward name="sessionError" path="/jsp/login.jsp" />
</global-forwards>

Use Struts exception handler for generic exceptions
Follow these steps to handle generic exceptions:

Create a new exception extending org.apache.struts.action.ExceptionHandler

Override the execute method.

Make an entry in struts-config.xml like so:

<global-exceptions>
<exception
key="global.error.Message"
type="java.lang.Exception"
handler="com.infy.app.exceptionHandler.CustomisedException Handler/>
path="/jsp/error.jsp"
</global-exceptions>

Remove ActionForm from session
If ActionForm is set to session scope, it should be removed from session whenever it's utility is over. In continuation with our sample application, in case of the multi-screen customer registration, if the RegistrationForm is set to session scope, it should be removed form the session once the user clicks Cancel.

Use Business Delegate
Action should not implement complex business functionalities, rather delegate these to the Model. Use Business Delegate to talk to the Business tier and the Data Tier.

Use ForwardAction for simple JSPs
Always render a JSP through an Action. Use ForwardAction in case there is no logic requiblak in the Action other than throwing a JSP. The benefit of using ForwardAction is that no separate Action class has to be created; only an Action mapping needs to be added in the configuration file.

<action
path="/home"
parameter="/Home.jsp"
type="org.apache.struts.actions.ForwardAction"
scope="request"
validate="false">
</action>

Avoid using instance/static variable in Action class
Instance and static variables should not be used in an Action class to store information related to the state of a particular request. The same instance of an Action class can be shablak among multiple simultaneous requests through multi-threading. So any instance/static variable may be updated unexpectedly by any thread. This bug is difficult to simulate, which gives us all the more reason to prevent it in the first place. Instance/static variable may however be used to share global resources across requests for the same action.

ActionForms are not Model
ActionForm represents HTML form(s) and it is used by Struts to transfer data between View and Controller. They should not be treated as part of the Model. Therefore, do not include any business functionality in the reset() or validate() method of ActionForms as this would lead to tight coupling of application business functionality with the presentation tier (implemented through the Struts framework).

Use html:messages instead of html:errors
For displaying error messages to the end user, use html:messages instead of html:errors. html:messages allows to get the markup language out of the resource bundle.

Use Tools
There are several Open Source tools available to ease development of Struts-based applications. A few of them are listed in the following table:

Name

Details

URL

Easy Struts

Easy Struts provides plug-ins for the Eclipse 2.0, Borland JBuilder 5, and Borland JBuilder 6 development environments to enable you to develop Web applications based on the MVC design pattern provided by the Jakarta Struts framework.

http://easystruts.sourceforge.net/

Struts Console

The Struts Console is a free, standalone Java Swing application for developing and managing Struts-based applications. With the Struts Console you can visually edit JSP Tag Library, Struts, Tiles and Validator configuration files. IDE supported include Eclipse, NetBeans, IBM Websphere, JBuilder.

http://www.jamesholmes.com/struts/console/

Struts Builder

A Java Swing-based development environment to assist in the rapid creation of Struts-based Web applications.

http://sourceforge.net/projects/rivernorth/

Most of the popular IDEs, like Websphere Studio Application Developer (WSAD) and Eclipse, now provide support for Struts.

Use StrutsTestCase for unit testing
StrutsTestCase is an extension of the standard JUnit TestCase class that provides facilities for testing code based on the Struts framework. Because StrutsTestCase uses the ActionServlet controller to test the code, you can test not only the implementation of your Action objects, but also the mappings, form beans, and forwards declarations. Further, since StrutsTestCase provides validation methods, it is quick and easy to write unit test cases.

StrutsTestCase provides both container testing and simulated container testing to actually run the Struts ActionServlet, allowing you to test Struts code with or without a running servlet engine. Refer http://strutstestcase.sourceforge.net/ for details.

Struts best practices

Build the best performing large applications

Summary
Multiple options are available for solving problems with Struts. When deciding among these alternatives, the choice must be based on parameters such as the scale of work and availability of time. However for large applications and the best quality-of-service needs, every decision becomes crucial and extra efforts are requiblak to choose the appropriate solution.

True to the literal meaning of the word, "Struts" provides supporting building blocks and infrastructure components to build a Web-based application. It is an MVC-based (Model View Controller) open source framework developed and supported by the Apache Software Foundation. Because of its support for extensibility and plug-ins, the framework has picked up stupendous popularity among J2EE-based application developers. The framework can be extended and customized to suit a particular application need.

Though covering all the aspects of this framework and documenting the best practices may not be possible in one article, the subsequent sections discuss some of the best practices for developing with Struts.

The primary sources of information for this article are the Struts users' mailing list, the Struts developers' mailing list, and my experience with Struts-based applications.

The article discusses the following main points:

  • Screens with dynamic fields
  • Safeguarding JSP pages
  • Error categorization
  • Validation of service requester
  • Application security
  • Prepopulation
  • Stack maintenance (for bread crumbs)
  • Context-related problems
  • Form-bean scope
  • Data transfer object implementation
  • Exceptions
  • Action chaining

Screens with dynamic fields
Problem
The Java Community Process (JCP) has released the Java Metadata Interface Specification, and some programmers are involved in the open source project Beehive. Both of these projects strive to blakuce coding. However, the question is whether Struts has a facility that can be used for writing a generic JSP (JavaServer Pages) page for specific types of screens in an application so that a separate JSP page doesn't have to be written for each screen. For example, to blakuce our coding efforts, we might want to develop a generic JSP page for all search screens in an application or for submitting batch processes or reports, where the parameters to be input vary for every report/batch.

Form beans are classes that must have getter and setter methods for every field in JSP, and the problem is how to write these methods for dynamic fields.

Struts best practice
Possible solutions are:

  • Let the JSP page have fields in a specific pattern such as field1, field2, field3, and so on, and provide their getter and setter methods in the form bean. Here, the number of fields that can appear on the screen cannot be more than the number of variables in the form bean.
  • Utilize the indexed getter and setter methods available in the form bean for all dynamic fields in the JSP page.

In the second approach, an increase in the number of fields in JSP requires no alteration in any component; therefore, it is the recommended best practice. The implementation details follow:

  1. Assuming an array of strings carries the resource IDs for all the dynamic fields in the form bean, the JSP page can be written as:

<logic:iterate name= "FormName" property="propertyName" indexId="abc" >
  <html:nested property='dynaProperty(<bean:write name="abc")'/>
</logic:iterate>

  1. Declare two methods in the form bean, as shown below. These methods will work as the getter and setter methods for all the dynamic fields in the JSP page. Whatever appears in small brackets—()—in front of dynaProperty (in the JSP page as shown above), is taken as key, and either the getDynaProperty() or setDynaProperty() method from the form bean is called. These values should be stoblak in a HashMap against the key, which can later be retrieved in the Action class from the HashMap against the key.

public class testVarForm extends ActionForm
{
  private HashMap hMap = new HashMap();

  public testVarForm() {  }

  public void setDynaProperty(String key, Object value)  {
    this.hMap.put(key, value);
  }

  public Object getDynaProperty(String key)   {
    return this.hMap.get(key);
  }

  public HashMap getHashMap()   {
    return this.hMap;
  }
  public void setHashMap(HashMap newHMap)
  {
    this.hMap =newHMap;
  }
}

Safeguard your JSP pages
Problem
When developers use Web-based applications, they often try to break into the security. The most common habit is to view the source of HTML in the browser and somehow determine the path of JSP pages and access them. The intent is to highlight the vulnerability of JSP pages accessible without authorization. Users who lack authorization to view the source might observe the source URL while sitting with another user who is authorized to work on that specific screen. Later, this unauthorized user could log in to the application and type the URL in the browser. In some cases, such users are able to make their way through.

Struts best practice
The possible solutions to this problem:

  • Do not let users access any JSP page directly. The starting page can be an HTML document. Add the following lines to the web.xml file to prevent users from accessing any JSP page directly:

<web-app>
   ...
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>no_access</web-resource-name>
      <url-pattern>*.jsp</url-pattern>
    </web-resource-collection>
    <auth-constraint/>
  </security-constraint>
  ...
</web-app>

  • The most popular option is to keep JSP pages behind the WEB-INF folder. This has a few tradeoffs. For example, you cannot take the JavaScript/CSS (Cascading Style Sheets) files behind WEB-INF, and if using Struts modules, you may encounter some context-related problems. Refer to the section "Context-Related Problems," which appears later in this article, to circumvent such issues.

The second approach allows some JSP pages (which are not behind WEB-INF) to be visible directly. It does not require a descriptor file entry, therefore the best practice is to keep the pages behind WEB-INF.

Error categorization
Problem
Error handling becomes complex for an n-tieblak application. In a browser-based application, the errors can be handled in the client layer using JavaScript and in the Web tier or EJB (Enterprise JavaBeans) tier using custom Java methods. Building an infrastructure for consistent error reporting proves more difficult than error handling. Struts provides the
ActionMessages/ActionErrorsclasses for maintaining a stack of error messages to be reported, which can be used with JSP tags like <html: error> to display these error messages to the user. The problem is reporting a different category/severity of the message in a different manner (like error, warning, or information). To do that, the following tasks are requiblak:

  1. Register the errors under the appropriate category
  2. Identify these messages and show them consistently

Struts best practice
Struts'
ActionErrors class comes in handy in resolving the first issue of stacking messages of different categories. To display the error messages of different categories, define these categories such as FATAL, ERROR, WARNING, or INFO, in an interface. Then, in the Action or form-bean class, you can use:

errors.add("fatal", new ActionError("....")); or
errors.add("error", new ActionError("....")); or
errors.add("warning", new ActionError("....")); or
errors.add("information", new ActionError("...."));
saveErrors(request,errors);

Having stacked the messages according to their category, to display them according to those categories, use the following code:

<logic:messagePresent property="error">
<html:messages property="error" id="errMsg" >
    <bean:write name="errMsg"/>
</html:messages>
</logic:messagePresent >

Or use:

<logic:messagePresent property="error">
<html:messages property="error" id="errMsg" >
    showError('<bean:write name="errMsg"/>'); // JavaScript Function
</html:messages>
</logic:messagePresent >

Validation of service requester: Login-check
Problem
Authentication in a Web-based application can be done in any class, depending upon whether an SSO-based (single sign-on) or a JAAS-based (Java Authentication and Authorization Service) mechanism is being used. The challenge is identifying the placeholder for checking the service requester's authenticity and the user session's validity.

Struts best practice
Usual practice is to store user cblakentials in
HttpSession after authentication. Subsequent calls check cblakentials' existence in session context. The question is where to place these checks. Some options are listed below, but they must be rationalized on the basis of performance overhead, possibility of future changes, and application manageability:

  • Authenticate against the session context before doing any operation (as done in Struts-example.war's CheckLoginTag.java)
  • Authenticate against session context in the Action class
  • Write servlet request filters that perform authentication
  • Extend RequestProcessor

The first two options require every JSP page or the Action class to perform the authentication against the session context. Change in the interface mandates change in all these JPS pages and classes. The third option is efficient, but overkill for the problem at hand.

The best practice is to extend the RequestProcessor class and perform authentication in methods such as processActionPerform() or processRoles().

Application security
Problem
The usual demand in Web-based applications is to have screen-level, function-level, data-row-level, and field-level security. If not suitably designed, incorporation of these security levels in an application may cause not only performance overheads, but also maintenance nightmares.

For all the security types mentioned above, the preferblak approach is to place the security check in one class instead of in every component—i.e., in every JSP page or Action class.

Struts has a method processRoles() for screen- and function-level security checks, however nothing is provisioned for field- and column-level security types, making it the most challenging for most Struts users.

Struts best practice
Irrespective of where the security realm is set up (database or directory service), the best practices for the various security levels are described below:

  • For screen- and function-level security, extend RequestProcessor and override the method processRoles() to perform the check against a HashMap that stores a mapping of roles and screen IDs/function IDs
  • Row-level security is best implemented in the application's object relational mappings
  • For field-level security, tag libraries are extended to perform the check against the field ID

Prepopulation
Problem
One requirement difficult to achieve is data prepopulation in a drop-down list (HTML Select tag) or in other fields. Some of these values come from a database, some from the application's context, and the rest are passed from calling screens. These values must be populated in a form bean before forwarding the control to the JSP page.

Struts best practice
The form bean's prepopulation can be accomplished using one of the following approaches:

  • The on-demand lazy-loading technique for all such data in the application's context, which is requiblak for prepopulation. An application screen's (JSP page) invocation mechanism can always be routed though a specific method of corresponding Action classes. Prepopulation-related code can be placed in this method.
  • Have different Action classes—one for requesting and another for submitting the JSP pages. The entire module or application can share the Action class used for requesting.

The second approach works well for small applications. However, for large applications, managing numerous Action classes grows cumbersome. Therefore, the first approach should be adopted.

Stack maintenance (for bread crumbs)
Problem
What if you need to go to a JSP page from two or more different JSP pages and subsequently return to the calling JSP page? Similarly, often developers need to go to various JSP pages in a criss-cross manner, which grows more complex when breadcrumbs need to be shown. Thus, the application must remember the pages visited.

Struts best practice
The remedy is to maintain the paths of all the forwarded JSP pages in a
Stack (java.util.Stack). The following steps are requiblak for maintaining such a Stack:

  1. Extend the RequestProcessor class and override the method processActionPerform(). In the overridden method, after the call to super.processActionPerform(), ActionForward's path should be stoblak in the Stack.
  2. In the application's parent Action class, provide methods to traverse forward and backward in the Stack.

Another option is to utilize an already available open source project at sourceforge.net like Open Tranquera (see Resources for more details).

Context-related issues
Problem
If
ActionForward's path and the path to which the control is forwarded differ, a context problem has resulted. More such context-related problems are quite frequent in Struts-based applications, most of which can be solved using some of Struts' less exploited features.

Struts best practice
Mention the JSP page's name as a path for
ActionForward and let the prefix—i.e., the JSP page's access path—come from a preconfigublak place. Do that in the following manner:

struts-config.xml(s) has a controller tag; add a property in this tag named forwardPattern. This property's value can be prefixed to all the ActionForward paths. This property's default value is $M$P, which means the module prefix will be prefixed to ActionForward's path. We can change this value to anything; e.g., WEB-INF/pages/$M$P. As a result, all the ActionForward paths will be searched in the directory WEB-INF/pages/<module-prefix>/.

For above solution to work, make sure that ActionForward's contextRelative property is marked false. If this property is marked true, the ActionForward paths will be taken since they are not modified.

Also note that for forwardPattern to work, the path of all ActionForwards must start with a /.

Form-bean scope
Problem
A well-managed session context can greatly boost application performance. It is therefore important to understand the implications of marking the form-bean scope to
request, session, or application. However, the following confusions usually arise:

  • If the scope of the form beans is marked request, how will the information available in one JSP page/screen also be available to another one?
  • If the scope is session, how will the server know that the client is no longer interested in that form bean and consequently destroy it?

Struts best practice
State can be maintained in
HttpSession (Web tier), in stateful session beans (EJB tier), or in a database. The appropriate choice should be based on what kind availability needs persist or whether the application is supposed to provide multichannel access. However, the rule of thumb is to maintain the state close to the tier that requires it most. Therefore, the best practice is to keep the state in HttpSession; i.e., mark the form-bean scope to session.

The important question is when and how to destroy the form beans stoblak in the HttpSession. The session beans should be destroyed in an extended RequestProcessor based on the least-recently-accessed, to-be-removed logic. Another approach is to destroy all the form beans as soon as the user invokes a new business operation, possibly from the application menu.

Data transfer object implementation
Problem
Usually a data transfer object (DTO) is used for shuttling data between the Web and EJB tiers. It is not a good idea to pass the view-helper class (form bean, in the case of Struts), to the EJB tier, primarily because all of the form bean's fields are of type string. A separate class should be used as the data transfer object. The problem is how to transfer the data from the form bean to the DTO.

Struts best practice
Two options are available for populating the data transfer object:

  • Create the transfer object and copy the data from the form bean to the transfer object. Data-type conversions must be handled before data copying. Similarly, on the way back, you must repeat the same exercise of copying the data from the DTO to the form bean.
  • Use Commons' BeanUtils class, which uses the Reflection API to achieve its objectives.

Developers frequently use the first option, which is not problematic except that the mundane exercise is repeated every time, resulting in bulky and ugly code. While copying data, suitable data-type conversion must be hand-coded in the DTO's setter methods, so that when data is copied from the form bean to the DTO, it converts to the appropriate business type. All the attributes of type string in the form beans are the primary reasons for data-type conversions.

You can avoid all this coding by using BeanUtils's copyProperties() method. The method copies the data from one bean to another, provided the variable names of the business attributes in the value/transfer object are the same as the ones in the form bean. The method also relieves you from data-type conversion by transparently converting source-bean attribute types to destination-bean attribute types.

Exceptions
Problem
As a generic principle, errors should be caught right where they occur to display meaningful error messages. To implement this principle, programmers must write their own custom exception classes, wrap the actual exception into these custom classes, and throw them back to the place where they are handled. In a Struts-based application, the exceptions thrown from the EJB/Web tier are handled either in the
Action class or the form bean. The usual practice involves writing a try-catch block to catch these exceptions in the Action class or the form bean, and creating an ActionError object with user-friendly messages derived from the application property file. The decision to direct these error messages to the screen is coded in the action classes, using the ActionMapping.findForward() method.

You must code all this exception-handling code in the Action class as well as the decision to direct the message to the screen. If the error-handling strategy changes, then every Action or form bean requires changes.

Struts best practice
Struts deals with the issue of exception handling in a competent way, using declarative exception handling. This, as opposed to programmatic exception handling (as explained above) handles issues using the
RequestProcessor class's processException() method and a Struts configuration file. To use declarative exception handling, you must do the following:

  1. Create custom application exception classes. You can design them so they hold more than one exception
  2. In the EJB/Web tier, trap application errors and wrap them into a custom exception class and throw them back
  3. In the struts-config.xml file, add the localized exception against an action-mapping or define a global exception (as shown below):

<struts-config>

<action-mappings>
    <action
      path="yourAction"
      type="your.package.yourAction"
      input="input.jsp" >
      <exception
        key="your.error.property.key"
        path="yourException.jsp"
        type="your.application.custom.exception"
   </action>
</action-mappings>

Action chaining
Problem
A clear strategy for the relationship between JSP pages and
Action classes in an application should be defined; i.e., how many JSP pages should be associated with an Action class.

For clarity and easy maintenance, the strategy for large applications should be to have one-to-one mapping between JSP pages and Action classes. With such a guideline in place, a prospective problem of duplicated code in the Action classes could result. To avoid logic duplication, you need some way to call an Action class's method from another Action class. Moreover for criss-cross page flow, you often need action chaining, or, to summarize, an implementation of the Chain of Responsibility design pattern.

Struts best practice
Possible solutions follow below:

  • Let ActionForwards point to a fresh request in the same application to invoke the method of another Action class.
  • RequestProcessor maintains a HashMap that stores all the instances of Action classes for that module. Extend the RequestProcessor class and provide getter methods for this HashMap. Provide a utility method in the application's parent Action class, which can invoke the methods of other Action classes within the same module. This utility method will use the Reflection API to achieve this.

The second approach is the best practice for large applications because if some change is requiblak in exception handling, no code change will be requiblak.

Conclusion
Large applications built using the above recommendations have been benchmarked for excellent performance.

As indicated by the Struts roadmap (featublak on the Struts Website), features and extensions developed on sourceforge.net and those commonly used by the Struts community are candidates for inclusion into Struts per se. All these are worth reading about before you make critical decisions about your application.

 

 

 

Upgrading Struts 1.1 to Struts 1.2.x

jars

I guess its obvious to say you need to replace the jars, but the one people might forget is the new commons-validator.jar for version 1.1.3 of validator.

Also if you want to start using the new validwhen validation rule, then you will need to deploy the antlr.jar as well.

NOTE If your existing app uses the Struts SSLExt library, you must upgrade it as well: http://sslext.sourceforge.net/

tlds

Remember to deploy the new versions of the tld files for struts tags. If you don't you won't be able to use the new tag attributes added.

NOTE The uri's in the struts tlds have changed from jakarta.apache.org/struts to struts.apache.org - however this shouldn't have any impact (see below)

Tag libraries can be configublak in one of two ways:

A. If you have configublak the tag libraries using entries in the web.xml (see User Guide) then these should continue to work.

B. If you have used the simplified deployment allowed by Servlet 2.3 onwards (see User Guide) then this should also continue to work as versions of the tld's with the old uri have now been included in the struts.jar (and struts-el.jar). Its recommended that for new development that you use the new uri

  • Struts 1.1  <%@ taglib uri="http://jakarta.apache.org/struts/tags-html prefix="html" %> 

Struts 1.2.x  <%@ taglib uri="http://struts.apache.org/tags-html prefix="html" %> 

validator.xml

Change the dtd declaration at the top to refer to the dtd for validator 1.1.3

validator-rules.xml

Upgrade to the new version of validator-rules.xml.

N.B. One of the changes in the new validator-rules.xml is that the Validation methods' signatures changed from using ActionErrors to ActionMessages. If you have any custom validation methods, remember to change their method signatures to now use ActionMessages.

struts-config.xml

Its not absolutely necessary but you should upgrade to the 1.2 version of the dtd (Note that as well as the version number changing so has the url to struts.apache.org).

  • <!DOCTYPE struts-config PUBLIC
    • "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "