Recipe8.7.Validating Field Equality with a Custom Validator


Recipe 8.7. Validating Field Equality with a Custom Validator

Problem

You want to create a reusable validator in Struts 1.1 that can validate that the value of one field is equal to the value of another.

Solution

Use Matt Raible's TwoFields custom validator. Start by creating a class with a static method that implements the rule, as shown in Example 8-9.

Example 8-9. TwoFields validation rule class
package com.oreilly.strutsckbk.ch08; import javax.servlet.http.HttpServletRequest; import org.apache.commons.validator.Field; import org.apache.commons.validator.GenericValidator; import org.apache.commons.validator.ValidatorAction; import org.apache.commons.validator.util.ValidatorUtils; import org.apache.struts.action.ActionErrors; import org.apache.struts.validator.Resources; public class CustomValidatorRules {          public static boolean validateTwoFields( Object bean,                                               ValidatorAction va,                                              Field field,                                              ActionErrors errors,                                              HttpServletRequest                                               request ) {         String value = ValidatorUtils.getValueAsString(bean, field.                        getProperty( ));         String sProperty2 = field.getVarValue("secondProperty");         String value2 = ValidatorUtils.getValueAsString(bean,                          sProperty2);                  if (!GenericValidator.isBlankOrNull(value)) {             try {                 if (!value.equals(value2)) {                     errors.add(                             field.getKey( ),                             Resources.getActionError(request, va, field));                     return false;                 }             } catch (Exception e) {                 errors.add(                         field.getKey( ),                         Resources.getActionError(request, va, field));                 return false;             }         }         return true;     }  }

Next, add the following validator element, shown in Example 8-10, as a sub-element of the global element in the validator-rules.xml file.

Example 8-10. TwoFields validator rule
<validator name="twofields"        classname="com.oreilly.strutsckbk.ch08.CustomValidatorRules"           method="validateTwoFields"     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.twofields">     <javascript><![CDATA[     function validateTwoFields(form) {         var bValid = true;         var focusField = null;         var i = 0;         var fields = new Array( );         oTwoFields = new twofields( );         for (x in oTwoFields) {             var field = form[oTwoFields[x][0]];             var secondField = form[oTwoFields[x][2]("secondProperty")];                       if (field.type == 'text' ||                 field.type == 'textarea' ||                 field.type == 'select-one' ||                 field.type == 'radio' ||                 field.type == 'password') {                          var value;                 var secondValue;                 // get field's value                 if (field.type == "select-one") {                     var si = field.selectedIndex;                     value = field.options[si].value;                     secondValue = secondField.options[si].value;                 } else {                     value = field.value;                     secondValue = secondField.value;                 }                              if (value != secondValue) {                                      if (i == 0) {                         focusField = field;                     }                     fields[i++] = oTwoFields[x][1];                     bValid = false;                 }             }         }                    if (fields.length > 0) {             focusField.focus( );             alert(fields.join('\n'));         }                      return bValid;     }]]></javascript> </validator>

Next, add an error message with the key of errors.twofields to your applications MessageResources properties file:

errors.twofields={0} must be equal to {1}.

To use the TwoFields validator, in your validation.xml file change the field element for one of the related fields to be dependent on the twofields rule. In Example 8-11, the password2 field must be equal to the password field for the validation of password2 to succeed.

Example 8-11. Applying the TwoFields rule
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE form-validation PUBLIC           "-//Apache Software Foundation//DTD Commons Validator Rules            Configuration            "http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd"> <form-validation>     <formset>         <form name="RegistrationForm">             <field property="emailAddress"                     depends="required,email">                 <arg0 key="prompt.emailAddress"/>             </field>             <field property="password"                     depends="required">                 <arg0 key="prompt.password"/>             </field>             <field property="password2"                     depends="required,twofields">                                  <arg0 key="prompt.password2"/>                 <arg1 key="prompt.password"/>                 <var>                     <var-name>secondProperty</var-name>                     <var-value>password</var-value>                 </var>             </field>         </form>     </formset> </form-validation>

Discussion

This recipe provides a solution for checking field equality and shows you how to create a custom validator. It's easier than you might suppose.

You implement a custom validator as a static method of a class of your choosing. By convention, the method should be named validatorRuleName. The precise method signature when developing under Struts 1.1 is the following:

public static boolean validateRuleName( Object bean,                                          ValidatorAction va,                                         Field field,                                          ActionErrors errors,                                          HttpServletRequest request)

This method returns a boolean, which indicates if the validation passes (true) or fails (false). Table 8-1 describes the method arguments and how they are used.

Table 8-2. Validator rule arguments

Name

Type

Purpose

bean

Object

The ActionForm being validated. You retrieve the input values from this object's properties.

Va

ValidatorAction

Object representation of the pluggable validator element from the validator-rules.xml file for the particular rule. Used to generate the error message for the rule.

field

Field

Object representation of the field element from the validation.xml file. Provides access to the nested variables (var) and arguments (arg).

errors

ActionErrors

An instance of ActionErrors you populate with ActionError objects. For Struts 1.2, this variable is an ActionMessages instance that you populate it ActionMessage objects.

request

HttpServletRequest

The HTTP servlet request. Used by the Resources utility class to retrieve the MessageResources for creating an ActionError.


The implementation of the TwoFields rule does the following:

  1. Gets the value for the field from the ActionForm (bean).

  2. Gets the value for the field variable named secondProperty that represents a bean property name.

  3. Using the bean property name acquired in step 2, retrieves the form value for the property from the ActionForm.

  4. Checks if the field value acquired in step 1 is blank or null. If it is either, true is returned; otherwise, processing continues.

  5. Tests if the two values are equal using the equals( ) method.

  6. If the values are unequal, adds a new ActionError to the errors and returns false.

  7. If an Exception is thrown in step 5 or 6, the rule adds a new ActionError to the errors and return false.

  8. If no Exception is thrown, the validation passes and returns true.

Once you have the Java coded for the validator, you need to link the implementation to the Validator by creating a validator element in the validator-rules.xml file. Here's the validator element used for TwoFields:

<validator name="twofields"        classname="com.oreilly.strutsckbk.ch08.CustomValidatorRules"           method="validateTwoFields"     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.twofields">

The name attribute specifies the name that you'll use to refer to the validator wherever it's applied. The classname, method, and methodParams attributes are used by the Validator to determine the class and method to call. If you are using Struts 1.2, be sure to change ActionErrors to ActionMessages.

The depends attribute specifies other rules triggered before this rule is fired. For the twofields rule, you need to validate the field if there's a value for it. You can enforce this by setting depends to required. The last attribute, msg, identifies the MessageResources key of the default error message used by this rule. This value can be overridden when the rule is applied.

The TwoFields rule shown in Example 8-10 includes JavaScript for client-side validation. For a Validator rule, you enclose the JavaScript code in a CDATA section of the javascript element nested in the validator element:

<validator name="twofields" ...   <javascript>       <![CDATA[       function validateTwoFields(form) {           var bValid = true;           // body of the JavaScript function ...           return bValid;       }]]>   </javascript> </validator>

The JavaScript function, like the Java method name, should be named using the validateRuleName convention. The function must return a boolean value that indicates if the validation rule passes (true) or fails (false).

For custom rules that don't use client-side validation, you can omit the javascript element.


The last piece of the puzzle (whew!) is to apply the rule to a specific form field:

<field property="password2"     depends="twofields">                      <arg0 key="prompt.password2"/>     <arg1 key="prompt.password"/>     <var>         <var-name>secondProperty</var-name>         <var-value>password</var-value>     </var> </field>

The arg0 and arg1 values specify the message resource keys for the labels of the two fields. These values are substituted into the error message if the validation fails. The var element specifies the name of the second field. This value doesn't necessarily have to be a field on the form (though in this case it probably would be); it can be any JavaBean property on the ActionForm.

See Also

If you are using Struts 1.2, an easier solution is discussed in Recipe 8.8.

The TwoFields validator was originally presented on Matt Raible's weblog. It can be found on his site at http://www.raibledesigns.com/page/rd/20030226. The Validator User's Guide discusses custom Validators in the section found at http://struts.apache.org/userGuide/dev_validator.html#plugs.

The Recipe 8.9 presents a custom Validator for Struts 1.2 that you may want to read up on as well.



    Jakarta Struts Cookbook
    Jakarta Struts Cookbook
    ISBN: 059600771X
    EAN: 2147483647
    Year: 2005
    Pages: 200

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