11.7 Using the Validator Outside of Struts

Although the Validator was originally designed to work with the Struts framework, it can be used to perform generic validation on any JavaBean. There are several steps that must be performed before the framework can be used outside of Struts.

Although the Validator is not dependent on the Struts framework, a considerable amount of work has been done inside of Struts to make it easier to use the Validator. This behavior will need to be replicated for your application if you plan to use the Validator without Struts.

The package dependencies are exactly the same for Struts and non-Struts applications. The ORO, Commons Logging, Commons BeanUtils, Commons Collections, and Digester packages are all required. You will also need an XML parser that conforms to the SAX 2.0 specification. You will not need to include the Struts framework, however.

Functions for loading and initializing the XML Validator resources are the first behaviors to replicate. These are the two XML files that are used to configure the rules for the Validator. When the Validator framework is used in conjunction with Struts, the org.apache.struts.Validator.ValidatorPlugIn class performs this duty. However, because the ValidatorPlugIn is dependent on Struts, you will need to create an alternate approach for initializing the appropriate Validator resources. To do this, you can create a simple Java class that performs the same behavior as the ValidatorPlugIn but doesn't have a dependency on the Struts framework. A simple example is provided in Example 11-4.

Example 11-4. Using the Validator outside of Struts
import java.util.*;
import java.io.*;
import org.apache.commons.validator.ValidatorResources;
import org.apache.commons.validator.ValidatorResourcesInitializer;
 
public class ValidatorLoader{
 
  private final static String RESOURCE_DELIM = ",";
  protected ValidatorResources resources = null;
  private String pathnames = null;
 
  public ValidatorLoader(  ) throws IOException {
    loadPathnames(  );
    initResources(  );
  }
 
  public ValidatorResources getResources(  ){
    return resources;
  }
 
  public String getPathnames(  ) {
    return pathnames;
  }
 
  public void setPathnames(String pathnames) {
    this.pathnames = pathnames;
  }
 
  protected void loadPathnames(  ){
    // Set a default just in case
    String paths = "validation-rules.xml,validation.xml";
    InputStream stream = null;
 
    try{
      // Load some properties file
      stream = this.getClass(  ).getResourceAsStream( "validator.properties" );
      if ( stream != null ){
        Properties props = new Properties(  );
        props.load( stream );
        // Get the pathnames string from the properties file
        paths = props.getProperty( "validator-pathnames" );
      }
    }catch( IOException ex ){
      ex.printStackTrace(  );
    }
    setPathnames( paths );
  }
 
  protected void initResources(  ) throws IOException {
    resources = new ValidatorResources(  );
 
    if (getPathnames() != null && getPathnames().length(  ) > 0) {
      StringTokenizer st = new StringTokenizer(getPathnames(  ), RESOURCE_DELIM);
      while (st.hasMoreTokens(  )) {
        String validatorRules = st.nextToken(  );
        validatorRules = validatorRules.trim(  );
 
        InputStream input = null;
        BufferedInputStream bis = null;
        input = getClass(  ).getResourceAsStream(validatorRules);
 
        if (input != null){
          bis = new BufferedInputStream(input);
 
          try {
            // pass in false so resources aren't processed
            // until last file is loaded
            ValidatorResourcesInitializer.initialize(resources, bis, false);
          }catch (Exception ex){
            ex.printStackTrace(  );
          }
        }
      }
      // process resources
      resources.process(  );
    }
  }
}

The work being done in the ValidatorLoader from Example 11-4 is very similar to what the ValidatorPlugIn does—it loads and initializes an instance of the ValidatorResources class. The object is an in-memory representation of the validation rules for an application. This example uses the getResourceAsStream( ) method to find and load a properties file that contains the list of Validator resource files.

Once you create and initialize an instance of the ValidatorResources class, you will need to cache it somewhere. In a Struts application, it's cached in the ServletContext. Your application can hang onto this object, or you can wrap the resource inside of a Singleton.

11.7.1 Modifying the validation-rules.xml File

In the earlier section Section 11.4, you saw how to extend the Validator framework with your own customized rules. You'll have to do this here as well, but the method signatures will be different. The method signature in Example 11-3 included parameters that are part of the Servlet and Struts APIs. You will need to use different arguments to keep from being coupled to the Servlet API or the Struts framework.

First, the methodParams attribute needs to be modified to support the alternate arguments to the validation method. The following is a fragment for a rule called currency:

<global> 
 <validator name="currency"
  classname="com.oreilly.struts.storefront.Validator"
  methodParams="java.lang.Object,org.apache.commons.validator.Field,java.util.List"
  method="isCurrency"
  msg="Value is not a valid Currency Amount."/>
</global>

Once the validation rule itself is set up, you need to use it in the application-specific validation file:

<form-validation>
 <global>
 </global>
 <formset>      
  <form name="checkoutForm">
   <field property="paymentAmount" depends="required,currency">
     <arg0 key="registrationForm.paymentamount.invalid"/>
   </field>
 </formset>
</form-validation>

Somewhere in the application, you must obtain access to the ValidatorResources object instance that was initialized in Example 11-4 and use it to validate the JavaBean:

ValidatorResources resources = // Get instance of the ValidatorResources
Validator validator = new Validator(resources, "checkoutForm");
 
validator.addResource(Validator.BEAN_KEY, bean);
validator.addResource("java.util.List", lErrors);
 
try {
  // Execute the validation rules
  validator.validate(  ); 
} catch ( ValidatorException ex ) { 
 // Log the validation exception 
 log.warn( "A validation exception occured", ex );
}

Although the Validator framework is designed for use with or without Struts, some work is required before it's ready to use outside of the Struts framework. However, with a little up-front sweat, you can save yourself plenty of work downstream in the development cycle.