17 May 2005

The XWork Validation (Restored)

I thought I lost this blog entry forever.

Restoring now...

With some words snipped from jcarreira.

The Xwork Validation Framework is designed to help apply simple validation or custom validation rule to Action before it is executed.

The Validator framework, at its core, takes just an object and a String context name for which to validate that object. This allows you to have different validations for the same class in different contexts. You can define default validations in the class-level validation file (ClassName-validation.xml), and then define validations which are added on top of these for a specific context (ClassName-contextName-validation.xml). In the case of Action validation, this context is the Action alias. The validators are applied in the order they are listed in the validation files and error messages are saved into the Object (if it implements ValidationAware). Note that ClassName-validation.xml must be at the same package of the Action class. Here is an example of ValidateAction-validation.xml that defines rules of validation:



<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd">

<validators>
<field name="name">
<field-validator type="requiredstring">
<message>You must enter a value for name</message>
</field-validator>
</field>
<field name="email">
<field-validator type="email">
<message>You must enter a value for email</message>
</field-validator>
</field>

<field name="birthday">
<field-validator type="requiredstring">
<message>You must enter a value for Birthday</message>
</field-validator>
</field>

<field name="tin">
<field-validator type="requiredstring">
<message>You must enter a value for TIN</message>
</field-validator>
</field>

<field name="url">
<field-validator type="url">
<message>You must enter a value for URL</message>
</field-validator>
</field>


<field name="duns">
<field-validator type="duns">
<message>You must enter a value for Dun and Bradstreet number</message>
</field-validator>
</field>

</validators>




To explain further, Here we can see the configuration of validators for the ValidationAction class that we will discuss later. Validators (and field-validators) must have a "type" attribute, which refers to a name of a Validator registered with the ValidatorFactory(see discussion below). Validator elements may also have <param> elements with name and value attributes to set arbitrary parameters into the Validator instance. A sample of param element can look like this:



<field name="date">
<field-validator type="date">
<param name="min">12/22/2002</param>
<param name="max">12/25/2002</param>
<message>The date must be between 12-22-2002 and 12-25-2002.</message>
</field-validator>
</field>




Note that the processForm() will not be executed before the ValidationInterceptor has not yet intercepted all necessary validators.

The ValidateAction.java



package com.ingenium.xwork_validation;

import com.opensymphony.xwork.ActionSupport;
import com.opensymphony.xwork.ValidationAware;


public class ValidateAction extends ActionSupport implements ValidationAware {

private String whom;
private String message = "";
private String name = "";
private String email = "";
private String url = "";
private String birthday = "";
private String tin = "";
private String d_and_b_number = "";
private String zip_code = "";

private String validationAction = "ShowForm.action";

public String getMessage() {
return message;
}

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

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

public void setEmail(String email){
this.email = email;
}

public String getEmail(){

return email;

}

public void setUrl(String url){

this.url = url;

}

public String getUrl(){

return url;

}

public void setBirthday(String birthday){

this.birthday = birthday;

}

public String getBirthday(){

return birthday;

}

public void setTin(String tin){

this.tin = tin;

}

public String getTin(){

return tin;

}

public void setDuns(String dunscode){

this.d_and_b_number = dunscode;

}

public String getDuns(){

return d_and_b_number;

}

public String processForm() {

if (!hasFieldErrors()){

return INPUT;
}

if (!hasErrors()){
return INPUT;
}
return ERROR;
}

public String execute() throws Exception {


if (!hasFieldErrors()){
return SUCCESS;
}
return INPUT;
}

}




Registering Validators to the ValidatorFactory

There are two ways to register Validators. This may either be done programmatically, using the registerValidator(String name, Class clazz) static method of the ValidatorFactory, or by putting a file name validators.xml in the root of the classpath with a structure like this:



<validators>
<validator name="required"
class="com.opensymphony.xwork.validator.validators.RequiredFieldValidator"/>
<validator name="requiredstring"
class="com.opensymphony.xwork.validator.validators.RequiredStringValidator"/>
<validator name="int"
class="com.opensymphony.xwork.validator.validators.IntRangeFieldValidator"/>
<validator name="date"
class="com.opensymphony.xwork.validator.validators.DateRangeFieldValidator"/>
<validator name="expression"
class="com.opensymphony.xwork.validator.validators.ExpressionValidator"/>
<validator name="email"
class="com.opensymphony.xwork.validator.validators.EmailValidator"/>
<validator name="url"
class="com.opensymphony.xwork.validator.validators.URLValidator"/>

<!--This is my custom validator-->
<validator name="duns"
class="com.ingenium.xwork_validation.validator.DUNSValidator"/>

</validators>




Notice that a custom validator has been added. But in order to use it, The ValidationInterceptor has to be turned on within the xwork.xml file like this:



<interceptors>
<!--your other validators are here-->
<interceptor name="validation" class="com.opensymphony.xwork.validator.ValidationInterceptor"/>
</interceptors>




Building a custom validator

A useful enterprise web application must be able to validate user inputs at UI level. Some data requires custom algorithms before it has to be committed to the database such as credit card numbers, billing account numbers, bank account numbers etc. In this topic the sample custom validator will be validating a DUNS number which stands for Dun and Bradstreet Universal Numbering System. Our code will consist of the interface which defines the operations to perform the validation, the implementation where the actual validation is performed and the accessor class where the implementation is called.

Code for IDUNSValidator.java





package com.ingenium.xwork_validation.validator;

/**
* Description: Description: This interface defines the functionalities of a
* D-U-N-S (Dun and Bradstreet algorithm) validation.
*
* @author Jared Odulio
*
*/
public interface IDunsValidator {


public static final int MODULUS = 10;

//~ Methods
/**
* Check if the D-U-N-S entry is valide
*
* @param dunsCode the D-U-N-S code to validate.
*
* @return
*/
public boolean isValid(String dunsCode);

/**
* Disposed the intance of the implementation of this interface.
*
*/
public void dispose();

}




Code listing for the DUNSValidatorImpl.java





package com.ingenium.xwork_validation.validator.impl;

import com.ingenium.xwork_validation.validator.IDunsValidator;

/**
* Description: The implementation class of IDunsValidator interface.
*
* @author Jared Odulio
*
*/
public final class DUNSValidatorImpl implements IDunsValidator {

private static DUNSValidatorImpl dunsImpl = null;
private String dunsCode = null;

/**
* Gets the runtime reference of this class.
*
* @return the created instance.
*/
public static DUNSValidatorImpl getInstance(){

if (dunsImpl == null){
dunsImpl = new DUNSValidatorImpl();
}

return dunsImpl;
}
/* (non-Javadoc)
* @see com.ingenium.xwork_validation.validator.IDunsValidator#isValid(java.lang.String)
*/
public boolean isValid(String dunsCode) {
// TODO Auto-generated method stub
this.dunsCode = dunsCode;

boolean valid = computeDunsCode();

return valid;
}

/**
* Computes the sequence of DUNS digits if it is valid.
*
* @return true if valid, false if otherwise.
*/
private boolean computeDunsCode(){

String[] sequence = new String[9];
int[] digits = new int[9];
int totalDigits = 0;
int computedDigits = 0;

//check first if the number of digits is right.
if (dunsCode.length() != 9){
return false;
}

for (int i = 0;i < sequence.length; ++i){

if (i < sequence.length - 1){
sequence[i] = dunsCode.substring(i, i + 1);
}else{
//get the last digit without end index
sequence[i] = dunsCode.substring(i);
}

//checks if entry are all numeric
try{
digits[i] = Integer.p**censored**Int(sequence[i]);
}catch (NumberFormatException nfe){
return false;
}

//checks if position is even
switch (i){
case 1:

if (digits[i] > 9){
digits[i] = computeMod(digits[i]);
}

break;

case 3:

if (digits[i] > 9){
digits[i] = computeMod(digits[i]);
}

break;

case 5:

if (digits[i] > 9){
digits[i] = computeMod(digits[i]);
}

break;

case 7:

if (digits[i] > 9){
digits[i] = computeMod(digits[i]);
}

break;
}//end of switch

}//end of for-loop

for (int i = 0;i < digits.length - 1; ++i){
totalDigits = totalDigits + digits[i];
}

computedDigits = totalDigits / IDunsValidator.MODULUS;
computedDigits = (computedDigits * IDunsValidator.MODULUS) +
IDunsValidator.MODULUS - totalDigits;

if (computedDigits == digits[8]){

return true;

}

return false;
}

/**
* Computes the modulus from the given digit.
*
* @param digits the given digit
*
* @return the computed modulus.
*/
private int computeMod(int digits){

int mod = digits;

mod = (mod / IDunsValidator.MODULUS) +
(mod % IDunsValidator.MODULUS);

return mod;
}

/* (non-Javadoc)
* @see com.ingenium.xwork_validation.validator.IDunsValidator#dispose()
*/
public void dispose() {

if (dunsImpl != null){
dunsImpl = null;
}

}
}




Code listing for the DUNSValidator.java



package com.ingenium.xwork_validation.validator;

import com.ingenium.xwork_validation.validator.impl.DUNSValidatorImpl;
import com.opensymphony.xwork.Action;
import com.opensymphony.xwork.validator.ValidationException;
import com.opensymphony.xwork.validator.validators.FieldValidatorSupport;

/**
* Description: Validates entry for the Dun and Bradstreet Universal
* Number System (DUNS).
*
* @author Jared Odulio
*
*/
public class DUNSValidator extends FieldValidatorSupport {

private IDunsValidator dunsValidator = null;

/* (non-Javadoc)
* @see com.opensymphony.xwork.validator.Validator#validate(java.lang.Object)
*/
public void validate(Action object) throws ValidationException {

String fieldname = getFieldName();
Object value = this.getFieldValue(fieldname, object);
dunsValidator = (IDunsValidator)DUNSValidatorImpl.getInstance();

if (value == null){
return;
}

if (!(value instanceof String) &&
!dunsValidator.isValid((String) value)){
addFieldError(fieldname, object);

}



}



}

No comments: