The Validator framework is now part of the Jakarta Commons project. It's included with the Struts main distribution, but you can also get the latest version from the Commons download page at http://jakarta.apache.org/commons/. Unless you need the source code or the absolute latest version, you'll find all the necessary files included with the Struts 1.1 distribution.
The Validator depends on several other packages to function properly, and the most important of these is the Jakarta ORO package. The ORO package contains functionality for regular expressions, performing substitutions, and text splitting, among other utilities. The libraries were originally developed by ORO, Inc. and donated to the Apache Software Foundation. Earlier versions of the Validator framework depended on a different regular expression package, called Regexp, which is also a Jakarta project. However, ORO was considered the more complete of the two, and the Validator that is included with Struts 1.1 now depends on the ORO package.
Other packages required by the Validator are Commons BeansUtils, Commons Logging, Commons Collections, and Digester. All of the dependent packages for the Validator are included in the Struts 1.1 download. The commons-validator.jar and jakarta-oro.jar files need to be placed into the WEB-INF/lib directory for your web application. The other dependent JAR files must also be present, but they should already be there due to Struts framework requirements.
As mentioned earlier, the Validator framework allows the validation rules for an application to be declaratively configured. This means that they are specified externally to the application source. There are two important configuration files for the Validator framework: validation-rules.xmlandvalidation.xml.
The validation-rules.xml configuration file contains a global set of validation rules that can be used out of the box by your application. This file is application-neutral and can be used by any Struts application. You should need to modify this file only if you plan to modify or extend the default set of rules.
|
The validator-rules_1_1.dtd describes the syntax of the validation-rules.xml file. The root element is the form-validation element, which requires one or more global elements:
<!ELEMENT form-validation (global+)>
<!ELEMENT global (validator+)>
Each validator element describes one unique validation rule. The following fragment from the validation-rules.xml file is the definition for the required validation rule:
<validator
name="required"
classname="org.apache.struts.util.StrutsValidator"
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>
|
The validator element supports seven attributes, as shown here:
<!ATTLIST validator name CDATA #REQUIRED
classname CDATA #REQUIRED
method CDATA #REQUIRED
methodParams CDATA #REQUIRED
msg CDATA #REQUIRED
depends CDATA #IMPLIED
jsFunctionName CDATA #IMPLIED>
The name attribute assigns a logical name to the validation rule. It is used to reference the rule from other rules within this file and from the application-specific validation file discussed in the next section. The name must be unique.
The classname and method attributes define the class and method that contain the logic for the validation rule. For example, as shown in the earlier code fragment, the validateRequired( ) method in the StrutsValidator class will be invoked for the required validation rule. The methodParams attribute is a comma-delimited list of parameters for the method defined in the method attribute.
The msg attribute is a key from the resource bundle. The Validator framework uses this value to look up a message from the Struts resource bundle when a validation error occurs. By default, the Validator framework uses the following values:
errors.required={0} is required.
errors.minlength={0} cannot be less than {1} characters.
errors.maxlength={0} cannot 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 not a valid credit card number.
errors.email={0} is an invalid email address
You should add these to your application's resource bundle, or change the key values in the validation-rules.xml file if you plan to use alternate messages.
The depends attribute is used to specify other validation rules that should be called before the rule specifying it. The depends attribute is illustrated in the minLength validation rule here:
<validator
name="minLength"
classname="org.apache.struts.util.StrutsValidator"
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>
Before the minLength validation rule is called, the required rule will be invoked. You can also set up a rule to depend on multiple rules by separating the rules in the depends attribute with a comma:
depends="required,integer"
If a rule that is specified in the depends attribute fails validation, the next rule will not be called. For example, in the minLength validation rule shown previously, the validateMinLength( ) method will not be invoked if the required validation rule fails. This should stand to reason, because there's no sense in checking the length of a value if no value is present.
The final attribute supported by the validator element is the jsFunctionName attribute. This optional attribute allows you to specify the name of the JavaScript function. By default, the Validator action name is used.
The Validator framework is fairly generic. It contains very basic, atomic rules that can be used by any application. As you'll see later in this chapter, it's this generic quality that allows it to be used with non-Struts applications as well. The org.apache.commons.Validator.GenericValidator class implements the generic rules as a set of public static methods. Table 11-1 lists the set of validation rules available in the GenericValidator class.
Because the validation rules in the GenericValidator are so fine-grained, the Struts developers added a utility class to the Struts framework called org.apache.struts.util.StrutsValidator , which defines a set of higher-level methods that are coupled to the Struts framework but make it easier to use the Validator with Struts. They are listed here without descriptions because the names are similar enough to the ones from Table 11-1 to indicate their functionality.
· validateByte
· validateCreditCard
· validateDate
· validateDouble
· validateEmail
· validateFloat
· validateInteger
· validateLong
· validateMask
· validateMinLength
· validateMaxLength
· validateRange
· validateRequired
· validateShort
The StrutsValidator class contains the concrete validation logic used by Struts. This class and the methods listed above are declaratively configured in the validation-rules.xml file. When one of these methods is invoked and the validation fails, an ActionError is automatically created and added to the ActionErrors object. These errors are stored in the request and made available to the view components.
The second configuration file that is required by the Validator framework is the validation.xml file. This file is application-specific; it describes which validation rules from the validation-rules.xml file are used by a particular ActionForm. This is what is meant by declaratively configured—you don't have to put code inside of the ActionForm class. The validation logic is associated with one or more ActionForm classes through this external file.
The validation.xml file is governed by the validation_1_1.dtd. The outermost element is the form-validation element, which can contain two child elements, global and formset. The global element can be present zero or more times, while the formset element can be present one or more times:
<!ELEMENT form-validation (global*, formset+)>
The global element allows you to configure constant elements that can be used throughout the rest of the file:
<!ELEMENT global (constant*)>
This is analogous to how you might define a constant in a Java file and then use it throughout the class. The following fragment shows a global fragment that defines two constants:
<global>
<constant>
<constant-name>phone</constant-name>
<constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$</constant-value>
</constant>
<constant>
<constant-name>zip</constant-name>
<constant-value>^\d{5}(-\d{4})?$</constant-value>
</constant>
</global>
This fragment includes two constants, phone and zip, although you can include as many as you need. These constants are available to the elements within the formset section. You can reuse them many times within the formset simply by referring to them by name.
This is best illustrated with an example. Example 11-1 shows a simple validation.xml file.
<form-validation>
<global>
<constant>
<constant-name>phone</constant-name>
<constant-value>^\(?(\d{3})\)?[-| ]?(\d{3})[-| ]?(\d{4})$</constant-value>
</constant>
</global>
<formset>
<form name="checkoutForm">
<field
property="phone"
depends="required,mask">
<arg0 key="registrationForm.firstname.displayname"/>
<var>
<var-name>mask</var-name>
<var-value>${phone}</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
In Example 11-1, the phone constant that's declared in the global section is used in the var element to help validate the phone property.
The formset element can contain two child elements, constant and form. The constant element has the same format as the one in the global section. It can be present zero or more times. The form element can be present one or more times within the formset element:
<!ELEMENT formset (constant*, form+)>
The formset element supports two attributes that deal with I18N, language and country:
<!ATTLIST formset language CDATA #IMPLIED
country CDATA #IMPLIED>
If you don't have any I18N requirements for your validation routines and want to use the default locale, you can leave out these attributes. The section Section 11.6" later in this chapter discusses this topic in more detail.
The form element defines a set of fields to be validated. The name corresponds to the identifier the application assigns to the form. In the case of the Struts framework, this is the name attribute from the form-beans section.
The form element defines a set of fields that are to be validated. It contains a single attribute name, which should match one of the name attributes from the form-beans section of the Struts configuration file.
The form element can contain one or more field elements:
<!ELEMENT form (field+)>
The field element corresponds to a specific property of a JavaBean that needs to be validated. In a Struts application, this JavaBean is an ActionForm. In Example 11-1, the sole field element for the checkoutForm corresponds to the phone property in an ActionForm called checkoutForm in the form-beans section of the Struts configuration file. The field element supports several attributes, which are listed in Table 11-2.
The field element contains several child elements:
<!ELEMENT field (msg?, arg0?, arg1?, arg2?, arg3?, var*)>
The msg child element allows you to specify an alternate message for a field element. The validation rule can use this value instead of the default message declared with the rule. The value for the msg element must be a key from the application resource bundle. For example:
<field property="phone" depends="required,mask">
<msg name="mask" key="phone.invalidformat"/>
<arg0 key="registrationForm.firstname.displayname"/>
<var>
<var-name>mask</var-name>
<var-value>${phone}</var-value>
</var>
</field>
The msg element supports three attributes:
<!ATTLIST msg name CDATA #IMPLIED
key CDATA #IMPLIED
resource CDATA #IMPLIED >
The name attribute specifies the rule with which the msg should be used. The value should be one of the rules specified in the validation-rules.xml file or in the global section.
The key attribute specifies a key from the resource bundle that should be added to the ActionError if validation fails. If you want to specify a literal message, rather than using the resource bundle, you can set the resource attribute to false. In this case, the key attribute is taken as a literal string.
The field element allows up to four additional elements to be included. These elements, named arg0, arg1, arg2, and arg3, are used to pass additional values to the message, either from the resource bundle or from the var or constant elements. The arg0 element defines the first replacement value, arg1 defines the second replacement value, and so on. Each arg element supports three attributes, name, key, and resource, which are the same as the attributes of the msg element described earlier.
Example 11-1 included elements for arg0 and arg1 like this:
<field property="phone" depends="required,mask,minLength">
<arg0 key="registrationForm.firstname.displayname"/>
<arg1 name="minlength" key="${var:minLength}" resource="false"/>
<var>
<var-name>mask</var-name>
<var-value>${phone}</var-value>
</var>
<var>
<var-name>minLength</var-name>
<var-value>5</var-value>
</var>
</field>
The last of the field child elements is the var element, as seen in Example 11-1 and in the previous fragment. The var element can set parameters that a field element may need to pass to one of its validation rules, such as the minimum and maximum values in a range validation. These parameters may also be referenced by one of the arg elements using a shell syntax: ${var:var-name}.
In Example 11-1, the substituted value for the phone constant is passed into the mask validation rule so that it can be used to check whether the property value conforms to the proper phone mask. The field element can have zero or more var elements.
Once you have the two XML resource files configured for your application, you need to place them in the WEB-INF directory. They will be referenced within the Struts configuration file, as described in the next section.
Each Struts application needs to know that the Validator framework is being employed. As discussed in Chapter 9, you can use the PlugIn mechanism to hook the Validator framework into a Struts application.
|
The following fragment illustrates how to set up the Validator as a plug-in:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validator.xml"/>
</plug-in>
|
The Struts framework will call the init( ) method in the ValidatorPlugIn class when the application starts up. During this method, the Validator resources from the XML files are loaded into memory so that they will be available to the application. Before calling the init( ) method, however, the pathnames property value is passed to the ValidatorPlugIn instance. This is how the ValidatorPlugIn finds out which Validator resources to load. For more information on how the PlugIn mechanism works, see Section 9.2.1.