Using Commons Validator with Struts


The interoperation of Commons Validator and Struts is like a jigsaw puzzle with several pieces. It is not possible to explain one piece in entirety and move on to the next since they are all interconnected . Hence our approach is to explain part of a puzzle before moving on to the next. And then several half-baked pieces are joined together. You might have read through this section twice to get a clear picture.

The twin XML files

In Struts, the XML based validations are located in two files ‚ validation-rules.xml and validation.xml . The validation-rules.xml file contains the global set of rules that are ready to use (Henceforth referred to as global rules file). It is shipped along with the Struts distribution in the lib directory. The second file ‚ validation.xml is application specific. It associates the rules from the global rules file with individual fields of your ActionForm. Suppose there is a generic rule named required in the global rules file that checks if a field is empty. You can use this rule to check if any field is empty including the firstName field in the CustomerForm by adding the following declaration in validation.xml :

 <form name="CustomerForm">     <field property="firstName"  depends="required"  >  ..  ..     </field>     <field .. ..     ..     </field>    .. </form> 

The above xml contains a XML block with a < form > element, which stands for an ActionForm named CustomerForm . All the rules associations for the CustomerForm fields exist inside this < form > block. One such validation ‚ the validation for the firstName field is also shown in a < field > element. The < field > has an attribute named depends that lists the set of rules (comma separated) on which the field is dependent upon. In other words, the validation.xml is just an association of the actual rules with the application specific forms. The actual rules are defined in the validation-rules.xml .

validation-rules.xml ‚ The global rules file

For a while, let us go back to validation-rules.xml ‚ the global rules file where all the rules are actually defined. Listing 5.1 shows a sample file. Each < validator > element defines one validation rule. The Listing shows a required rule validator. The required rule validator uses a class called org.apache.struts.validator.FieldChecks . Where did this come from? Well, that requires some background too.

Listing 5.1: Required rule in validation-rules.xml
 <form-validation>   <global>     <validator name="required"             classname="org.apache.struts.validator.FieldChecks"             method="validateRequired"             methodParams="java.lang.Object,                org.apache.commons.validator.ValidatorAction,                org.apache.commons.validator.Field,                org.apache.struts.action.ActionErrors,                javax.servlet.http.HttpServletRequest"             msg="errors.required">      </validator>     <validator name="">                       </validator>     <!- More validators defined here -->    </global> </form-validation> 
 

The basic validator class in Commons Validator is org.apache.commons.validator.GenericValidator . It contains atomic and fine-grained validation routines such as isBlankOrNull() , isFloat() , isInRange() etc. Struts provides the FieldChecks that uses the GenericValidator but has coarse grained methods such as validateRequired() , validateDate() , validateCreditCard() etc. Each of these methods accept four arguments of type

 java.lang.Object,       org.apache.commons.validator.ValidatorAction,       org.apache.commons.validator.Field,       ActionErrors and HttpServletRequest 

in that order. Notice that the same arguments are listed under the methodParams attribute in Listing 5.1.

Note ‚  

The FieldChecks couples the ActionForm validations to the Struts framework by adding dependency on Struts specific classes in the XML, but makes it easy to use the Commons Validator with Struts.

With this background info , the required validator in Listing 5.1 translates into plain English as: ‚“The rule named ‚“ required ‚½ is defined in method validateRequired within a class named FieldChecks that accepts the above listed four arguments in that order. On error, an error message identified by the key errors.required is displayed. The errors.required is a key to the Resource Bundle ‚½. Quite a mouthful indeed!

The next step is to add the message for errors.required to the Resource Bundle. The key-value pair added is: errors.required={0} is required . By default, the rules in global rules file use the following keys for the error messages - errors.required , errors.minlength , errors.maxlength , errors.date and so on. To use different error keys, make appropriate changes in validation-rules.xml .

A rule in the global rules file can itself depend on another rule. For example, consider the minlength rule. It checks if a field is less than a specified length. However it doesn ‚ t make sense to check the length of an empty field is less than a specified length. In other words, minlength rule depends on required rule. If the required rule fails, the minlength rule is not executed. This depends relationship among rules is shown below.

 <validator name="minlength"        classname="org.apache.struts.validator.FieldChecks"        method="validateMinLength"        methodParams="java.lang.Object,          org.apache.commons.validator.ValidatorAction,          org.apache.commons.validator.Field,          org.apache.struts.action.ActionErrors,          javax.servlet.http.HttpServletRequest"  depends="required"  msg="errors.minlength">     </validator> 

validation.xml ‚ The application specific rules file

Now, let us get back to the validation.xml . A sample is shown in Listing 5.2. The xml consists of a < formset > block with multiple < form > blocks, one for each form.

Listing 5.2: Application specific validations for CustomerForm
 <form-validation>   <formset>     <form name="CustomerForm">       <field property="firstName"               depends="required,minlength ">         <arg0 key="customerform.firstname"/>         <arg1 name="len" key="1" resource="false"/>       </field>         </form>   </formset>    </form-validation> 
 

In Listing 5.2, the topmost xml block is < form-validation >. It contains a single < formset > element, which in turn can contain a collection of < form >s. Each < form > corresponds to the Struts Form. The < form > contains a set of < field >s to be validated . The firstName field depends on two rules ‚ required and minLength . The required and minLength are defined in the validation-rules.xml .

Then comes the arg0 and arg1 . The < field > element accepts up to four args ‚ arg0 , arg1 , arg2 and arg3 . These argN s are the keys for replacement values in ActionError . Sure Sounds confusing. Here is an example to make things clear. Assume that the required rule has failed. An ActionError with key errors.required needs to be created. The error message for this key is defined in the resource bundle as ‚“ {0} is required ‚½. This message needs a literal value to replace {0} . That replacement value itself is obtained by first looking up the resource bundle with key attribute of < arg0 > element. In Listing 5.2, the key attribute of < arg0 > is customer.firstname . The key is used to lookup the resource bundle and obtain the replacement value. Suppose that the resource bundle defines these messages.

 customer.firstname=First Name errors.required={0} is required 

Then, the replacement value for {0} is First Name . This value is used to replace {0} and the resulting error message is First Name is required . Notice that the Resource bundle is looked up twice ‚ once using the arg0 key and then during the rendering of the ActionError itself.

You might be wondering why arg1 is needed. The answer is when the minlength rule fails; it looks for an error message with a predefined key called errors.minlength . The errors.minlength requires two replacement values ‚ arg0 and arg1 . arg0 was also used by the errors.required key. The errors.minlength needs arg1 in addition to arg0 . I can hear you are saying ‚ ‚“All that is fine. But how will I know what predefined error keys should be added to the resource bundle ‚½. It is simple actually. Just open the validation-rules.xml and you will find all the error message keys are provided. They are:

 errors.required={0} is required.    errors.minlength={0} can not be less than {1} characters.    errors.maxlength={0} can not be greater than {1} characters.    errors.invalid={0} is invalid.    errors.byte={0} must be a byte.    errors.short={0} must be a short.    errors.integer={0} must be an integer.    errors.long={0} must be a long.    errors.float={0} must be a float.    errors.double={0} must be a double.    errors.date={0} is not a date.    errors.range={0} is not in the range {1} through {2}.    errors.creditcard={0} is an invalid credit card number.    errors.email={0} is an invalid e-mail address. 

As you can see, every error message key needs arg0 . The errors.minlength , errors.maxlength and errors.range need arg1 . In addition, the errors.range also needs arg2 .

In Listing 5.2, the arg1 has an attribute called resource and it set to false . The resource= ‚½false ‚½ implies that there is no need to lookup the message resource bundle for arg1 (as was done with arg0 key ‚ customerform.firstname ).

More validation.xml features

Let us investigate some more interesting validator features. Listing 5.3 shows the same CustomerForm validation rules with some additions and modifications. Those are highlighted in bold.

Listing 5.3: Application specific validations for CustomerForm
 <form-validation>   <  global  >   <  constant  >   <  constant-name  >  nameMask  <  /constant-name  >   <  constant-value  >  ^[A-Za-z]*$  <  /constant-value  >   <  /constant  >   <  /global  >   <formset>     <form name="CustomerForm">       <field property="firstName"               depends="required,minlength,  mask  ">         <arg0 key="customerform.firstname"/>         <arg1 name="len"  key="${var:minlen}"  resource="false"/>   <  var  >           <var-name>minlen</var-name>           <var-value>1</var-value>         </var>         <var>           <var-name>mask</var-name>           <var-value>${nameMask}</var-value>         </var>       </field>         </form>   </formset>    </form-validation> 
 

The first addition is the < global > block to < form-validation >. The < global > can hold as many < constant >s. A < constant > is much like a Java constant. Declare it once and use wherever needed. In this case, a constant called nameMask is declared and a regular expression ^[A-Za-z]*$ is assigned to it. This regular expression is interpreted as: ‚“The field can have any number of characters as long as each of them is between A-Z and a-z ‚½. This constant is used to define the mask rule for CustomerForm in two steps as follows :

  1. First, a variable < var > called mask is created and the value of nameMask is assigned to it. This is done by setting the < var-value > to be ${nameMask} . [Any variable within the ${ and } blocks is evaluated. You will find the same convention in JSTL too.] The < var > scope is limited to the < field > where it is declared.

  2. Next, a rule called mask is added to the CustomerForm ‚ s depends attribute. The mask rule is defined in the validation-rules.xml . It checks if the current field value confirms to the regular expression in a predefined variable called mask (This is the reason why we created a variable called mask in the firstName < field > and assigned it the nameMask value. Doing so, lets us reuse the nameMask expression for all the forms in validation.xml if necessary and at the same time satisfy the constraint imposed by the mask rule that the regular expression is always available in a < var > called mask .

The second new feature in Listing 5.3 is the use of variable for arg1 . arg1 as you know, represents the minimum length of the first name. In Listing 5.2, the arg1 key was hard coded. A bit of flexibility is added this time round by declaring it as a field scoped variable and then accessing it through the shell syntax ${..} .

Using the ValidationForm

There is one last piece pending in the puzzle. How does the validation failure become ActionError and get displayed to the user ? We will answer it right away. Struts has a class called ValidatorForm in org.apache.struts.validator package. This is a subclass of ActionForm and implements the validate() method. The validate() method invokes the Commons Validator, executes the rules using the two xml files and generates ActionErrors using the Message Resources defined in the struts-config.xml . All you have to do is extend your form from ValidatorForm and write your rules in XML. The framework does the rest. More details on the validator are covered later in this chapter. For now, let us see how the Validator is configured.

Configuring the Validator

Starting from 1.1, Struts provides a facility to integrate third party utilities seamlessly through what is called as a PlugIn . A PlugIn is simply a configuration wrapper for a module-specific resource or service that needs to be notified about application startup and application shutdown events (through the methods init and destroy ). A PlugIn is a class that implements org.apache.struts.action.PlugIn interface. This interface defines two methods:

 public void init(ActionServlet servlet, ModuleConfig config)  public void destroy() 

You can respectively implement logic to initialize and destroy custom objects in these methods. PlugIns are configured in the struts-config.xml file, without the need to subclass ActionServlet simply to perform application lifecycle activities. For instance the following XML snippet (from the struts-config.xml ) configures the 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> 

The ValidatorPlugIn is a class that implements the PlugIn interface. It has an attribute called pathnames . The two input rule XML file names are specified using this attribute. As you know already, Struts reads the struts-config.xml file during initialization ‚ during which it also reads the Validator plugin and accordingly initializes it. Consequently the rules are loaded and available to the ValidatorForm class when the time comes to execute the validate() method.

Steps to use Commons Validator in Struts

Now, let us summarize the steps involved in using Commons Validator with Struts. They are:

  1. Create the application specific ActionForm by extending the ValidatorForm

  2. Add the corresponding <form> element with <field> sub-element for every form field that needs validation.

  3. List the rules to execute in the <field> ‚ s depends attribute.

  4. For every rule, add the error message with predefined name to the message bundle.

  5. For every rule, supply the argNs either as inline keys or keys to the resource bundle.

  6. If the rules in validation-rules.xml do not meet your needs, add new rules and follow the steps above for the new rules. Be sure to have the classes executing the rules are available in the appropriate class path .




Struts Survival Guide. Basics to Best Practices
Struts Survival Guide: Basics to Best Practices (J2ee Survival Series)
ISBN: 0974848808
EAN: 2147483647
Year: 2004
Pages: 96

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net