Validating End-User Data


Validating End- User Data

One of the problems that developers have is validating data. The problem is not that it is a difficult task, but that it is tedious . Typically, data will arrive from some source and the program that needs to process the data will have to validate it. The validation might be according to a simple rule like not being null, or it could involve a more complex rule of referencing an actual client. The validation could even be a password or security validation. In any case, validation is a step that is undertaken by the process before the actual business processing.

The validator package in the Commons Bridge is a package used to perform validation. The validation is not performed in the context of a program running, but in the context of a configuration file. Essentially what happens is that the programmer is presented with a Java bean that references some data. The Java bean is sent to the validator package and is associated with a specific form. The form is defined within a configuration file and references the individual fields and what their values have to be. At the end of the entire validation process, a result set, which can then be sent to the end user for verification, is created.

Technical Details for the validator Package

Tables 9.5 and 9.6 contain the abbreviated details necessary to use the validator package.

Table 9.5: Repository details for the validator package.

Item

Details

CVS repository

jakarta-commons

Directory within repository

validator

Main packages used

org.apache.commons.validator

Table 9.6: Package and class details (legend: [validator] = org.apache.commons.validator).

Interface

Details

[validator].ValidatorResources

A class that represents an individual or multiple configuration file(s) used to perform validation.

[validator].Validator

The main class used to perform an individual validation based on validator form.

[validator].ValidatorResults

A class that represents a collection of validation results after having executed a validation.

[validator].ValidatorResult

A class that represents the validation results of various validation processes for a single property.

[validator].Field

A class that represents an individual field from the validator configuration file.

[validator].ValidatorAction

A class that provides the front end to a validator plug-in.

The complicated part of using the validator is getting everything to work. Most examples, including the ones from this book, require references to configuration files and classes that are necessary and in different locations. This means that the directories [validator]/ conf/share and [validator]/target/test-classes have to be added to the classpath. It is also required that you properly configure the log4j package; if it's improperly configured, simple errors such as class loading errors will not be output.

Defining a Validator

For all validation, a configuration file is required. The configuration file has two parts : validators and forms. A partial sample configuration file is shown in Listing 9.32.

Listing 9.32
start example
 <form-validation>  <global> <validator name="custom"  classname="com.devspace.jseng.algorithms.MyValidatorTest"  method="validateRequired"  methodParams="java.lang.Object,org.apache.commons.validator.Field"  msg="errors.required"/>  </global>  <formset>  </formset> </form-validation> 
end example
 

In Listing 9.32, the validators part is represented by the XML tag global, and the forms part is represented by the tag formset . Within the XML tag global is a number of validator XML tags. Each validator XML tag defines an action that is used when a field is validated . A configuration file does not have a predefined number of validators that can be contained. Of course, physical resource limits apply. Each validator has to be uniquely identified using the attribute name .

The XML tag validator has the following five attributes:

  • classname : The name of a class that is loaded and used to perform the validation.

  • method : The name of a method that is called to perform the validation.

  • methodParams : The parameters that the validation method requires. We'll discuss this further a bit later in this section.

  • msg : A reference to a message identifier that is output when there are validation errors.

  • name : A unique identifier for the file that describes the purpose of the validation. For example, "required" could mean "required field." Or, " creditcard " could mean "credit card validation."

The purpose of the validator definition is to cross-reference a Java class that performs some validation. The validator package does not define generic validators per se. Rather, it provides the infrastructure so that developers can write their own routines. The routines might not be complicated, because the validator package provides the basics, such as having a required field. Listing 9.33 shows the implemented validator that was defined in Listing 9.32.

Listing 9.33
start example
 import org.apache.commons.validator.*; public class MyValidatorTest { public static boolean validateRequired(Object bean, Field field) { return true; } } 
end example
 

In Listing 9.33, the class MyValidatorTest exposes the method validateRequired , which is called when a field is to be validated. In the current implementation, a boolean value of true is returned. This means there is no validation, just an answer that everything is OK. This implementation is done on purpose to illustrate a couple of other points.

Going back to Listing 9.31, the attribute methodParams defined two parameters, which are of the type Object and Field . Of course, the method validateRequired in Listing 9.32 has the same parameters in the same order. This is not random and does follow some logic. When the validator package processes the data, four different variables are available. These variables reference some aspect of the validator package. The variables are passed as parameters using their type as an identifier. The four variables are:

  • org.commons.apache.validator.ValidatorAction : Represents the pluggable validator defined by Listing 9.32. Using this class, you can figure out other pluggable validator dependencies and their associated characteristics.

  • org.commons.apache.validator.Validator : Represents the core class used to perform a validation. This class is needed when you're doing nested bean validations, because within the validation of one bean a delegation has to be made to validate another bean.

  • org.commons.apache.validator.Field : Represents the field that is currently being validated.

  • java.lang.Object : Represents the Java Bean that is being validated. It is assumed that the pluggable validator will cross-reference the field with the Java Bean. The Beanutils package is very useful for finding out the values of individual bean properties and methods .

Of all the variables defined in the previous list, only Field and Object provide any useful information. The other two classes are useful only for extremely complex validation, which is beyond the scope of this book.

Defining the Form

Once the validators have been defined, you can define individual forms that need to be validated. The form that will be validated is the Java Bean BeanToWrite , which we have used very often in this book. The class BeanToWrite exposes two properties: stringValue and integerValue . Listing 9.34 shows a full configuration file that references the individual properties.

Listing 9.34
start example
 <form-validation>  <global> <validator name="custom"  classname="com.devspace.jseng.algorithms.MyValidatorTest"  method="validateRequired"  methodParams="java.lang.Object,org.apache.commons.validator.Field"  msg="errors.required"/>  </global>  <formset> <form name="ValidateBeanToWrite">  <field property="integerValue"depends="custom">   <arg key="ValidateBeanToWrite.integerValue.displayname"/>  </field>  <fieldproperty="stringValue" depends="custom">   <arg key="ValidateBeanToWrite.stringValue.displayname"/>  </field> </form>  </formset> </form-validation> 
end example
 

In Listing 9.34, the XML tag form defines a collection of properties that will be validated. The XML tag field defines individual properties that are to be validated. The XML tag field has two attributes: name and depends . The attribute name is the identifier of the property that will be validated on the Java Bean. The attribute depends represents a comma-separated list of validators that will be executed for the property.

Since the configuration defines only one validator with the identifier custom , the attributes depends can have only that value. Had the configuration file had multiple validators, then the attribute depends could have contained all the validators. Going back to Listing 9.33, the validator cross-references the Field class instance to XML tag field in Listing 9.34. In actuality, the Digester package is used to read the configuration file defined in Listing 9.34. Therefore, if you want to figure out what attributes are possible, refresh your memory about the Digester package and then look at the class Field .

The child XML tag arg defines a cross-reference between the property and a properties file. The properties file defines a number of definitions used when messages are displayed. The properties file could be considered a user-friendly way of outputting a validation problem. Listing 9.35 shows the sample properties file used.

Listing 9.35
start example
 errors.required=The {0} field is required. ValidateBeanToWrite.integerValue.displayname=Integer Value ValidateBeanToWrite.stringValue.displayname=String Value 
end example
 

In Listing 9.35, the definitions are cross-referenced with the attributes msg and key in Listing 9.34. When a validation issue is raised, instead of dumping the property name integerValue or _integerValue , the text Integer Value is used.

Validating the Bean

With the configuration file and properties file properly configured and cross-referenced, you can perform some validation. Listing 9.36 shows a sample program that validates the class BeanToWrite .

Listing 9.36
start example
 InputStream in = null; ValidatorResources resources = null; try { URL url = new URL( "file:/src/classes"); URL[] urls = new URL[] { url }; ClassLoader classloader = new URLClassLoader( urls); in = classloader.getResourceAsStream("BeanToWriteValidator.xml"); resources = new ValidatorResources(in); } finally { if (in != null) { in.close(); } } BeanToWrite bean = new BeanToWrite(); Validator validator = new Validator(resources, "ValidateBeanToWrite"); validator.setParameter(Validator.BEAN_PARAM, bean); ValidatorResults results = validator.validate(); printResults(bean, results, resources); 
end example
 

Listing 9.36 contains three parts in three separate code blocks: loading of resources, initialization, and validation. The first part is the loading of the resources. The resources to be loaded are the configuration file and the properties file. The configuration file needs to be loaded as a stream; the easiest way of doing that would be to use the class URLClassLoader . Or, if a classpath configuration has already been established, you could use the Discovery package. Once the resource has been loaded, it is passed as a constructor parameter to the class ValidatorResources , which represent the validator resources.

The class ValidatorResources is a class that you can create once and reuse in different validation schemes. However, do realize the ValidatorResources in Listing 9.36 references only a single configuration file. To associate multiple configuration files, you should use an array of streams that represent individual configuration files. When the configuration file is loaded, the configuration file DTD is loaded as well. Therefore, it is necessary to make sure that the files are available from the classpath.

The second part in Listing 9.36 is the initialization of the validation. In this part, the validator searches the configuration file for a specific form. The specific form represents a validator that can be executed on a bean. To create a validator, the class Validator is instantiated , with the constructor parameter being the specific form to load from the validator resources. The bean is associated with the validator using the method setParameter . The method setParameter has two parameters: Validator.BEAN_PARAM and the bean instance.

The validator has to be assigned the bean instance whenever a different bean is to be validated. For example, if you know that a specific bean keeps the state of the data and is used for a long time, you don't have to constantly assign it.

The third part in Listing 9.36 is validation. The method validate returns a ValidatorResults class instance. The class ValidatorResults is a result set that contains the output of the validation. The results are then passed to the method printResults , which in a successful situation contains the text, as shown in Listing 9.37.

Listing 9.37
start example
 Validating: _iValue : [0] _strvalue : [null] integerValue[custom] (PASSED) stringValue[custom] (PASSED) FORM VALIDATION PASSED 
end example
 

In Listing 9.37, the output of the method printResults seems to be a black box that outputs some text. In the simplest analogy, that is exactly what the method printResults does. However, iterating the validation result is more than just dumping some strings to an output buffer. Each validation item result has an associated state and descriptive information that needs to be custom- processed . In simple terms, there is no notion of a simple true or false answer.

Generating the Output of a Validation

You generate the validation output by inspecting the results in the ValidatorResults class instance. To iterate the results, first iterate the property names and then retrieve an individual result about the property. Listing 9.38 shows how to iterate the validation table.

Listing 9.38
start example
 Iterator iter = results.getPropertyNames().iterator(); while( iter.hasNext()) { String propertyName = (String)iter.next(); ValidatorResult result = results.getValidatorResult(propertyName); System.out.println( "Property " + propertyName + " validated [" + result.isValid( "custom") + "]"); } 
end example
 

In Listing 9.38, the property name iterator is retrieved using the method calls getPropertyNames().iterator() . Returned is an iterator of string values that represent individual property names. Then, to retrieve an individual validation result, the method getValidatorResult is called. Returned is a ValidatorResult class instance. The class instance represents the validation results of a specific property. Going back to the configuration file defined in Listing 9.34, the attribute depends could have multiple validations being executed. Therefore, in Listing 9.38, the method isValid is used to retrieve the result of an individual validation defined in the configuration file. Returned from the method isValid is a Boolean true or false value to indicate whether or not validation was successful.

It is possible to pretty print the output of a validation routine. The class ResourceBundle in conjunction with a properties file can be used to pretty print the output. However, such a routine is not that simple; it requires many more steps, and as such is beyond the focus of this book. For those interested, a pretty printing routine is available on this book's CD-ROM.

Implementing a Functional Validator Class

There are different ways of performing a validation. The validator used in the beginning of this section was an overall validation. However, it is possible to validate generically using a Field object instance and a Java Bean, as shown in Listing 9.39.

Listing 9.39
start example
 public class MyValidatorTest { public static boolean validateRequired(Object bean, Field field) { try { String value = (String)BeanUtils.getSimpleProperty( bean, field.getProperty()); return !GenericValidator.isBlankOrNull(value); } catch( Exception ex) { ; } return false; } } 
end example
 

In Listing 9.39, the class method BeanUtils.getSimpleProperty is used to retrieve the value of a property from a Java Bean. The value retrieved is stored in the variable value, which is then a parameter for the class method GenericValidator.isBlankOrNull . The method isBlankOrNull is a test used to check if the input object instance is a blank buffer or a null object instance. The return value is inverted, because if the method isBlankOrNull then a true is returned for an empty buffer and the validateRequired should return a false .

One item to note in Listing 9.39 is that the Beanutils package is used instead of just the validator package. The Beanutils package, introduced in Chapter 7, allows a developer to use reflection on an object and read the object instance class data dynamically. The method getSimpleProperty could have been replaced with a reference to the class method ValidatorUtil.getValueAsString . However, that method was not used because the Bean- utils package has been explained and the class ValidatorUtil uses the Beanutils package itself.

The class GenericValidator exposes various verification routines. Note that if the verification routines fail, a false is returned. For example, if isShort is called and the value is a long , then the verification will fail. In addition, in all cases, the routines manipulate a string value.

  • isBlankOrNull : Verifies if the value is a blank or null value.

  • isByte : Verifies if the value is a byte.

  • isCreditCard : Verifies if the value is a valid credit card. The credit cards that can be tested are American Express, Visa, MasterCard, and Discover. For more details about the various date formats, look at the Java Docs for the class org.apache.commons. validation.CreditCardValidator .

  • isDate : Verifies if the value is a date. For more details about the various date formats, look at the Java Docs for the class org.apache.commons.validation.DateValidator .

  • isDouble : Verifies if the value is double.

  • isEmail : Verifies if the value is a valid e-mail address.

  • isFloat : Verifies if the value is a float.

  • isInRange : Verifies if the value, which must be some type of number and not a string, is within a specific range.

  • isInt : Verifies if the value is an integer.

  • isLong : Verifies if the value is a long.

  • isShort : Verifies if the value is a short.

  • isUrl : Verifies if the value is a valid URL.

  • matchRegexp : Verifies if the expression matches a Perl 5 regular expression. Using this module requires that the Jakarta ORO jar file be installed, which is a regular expression library.

The Beanutils package is very useful for extracting specific values from a bean instance. However, the lang package and its utility classes (defined earlier in this chapter) are very useful for manipulating strings. Using the string classes in the lang package, you can properly trim the value for consistent validation.




Applied Software Engineering Using Apache Jakarta Commons
Applied Software Engineering Using Apache Jakarta Commons (Charles River Media Computer Engineering)
ISBN: 1584502460
EAN: 2147483647
Year: 2002
Pages: 109

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