By Jeff Chilton
" Opportunities multiply as they are seized."
-- Sun Tzu (ancient Chinese military leader, circa 500BC)
In our last installment, we created a factory to produce our OptionListSource components to insulate the application from the configuration issues. Although we made a few shortcuts for demonstration purposes, we did manage to create enough of a framework to utilize the process for our intended purpose. In this installment, we're going to take a look at using our little framework for a new, unintended purpose.
One of the great things about producing reusable components is that, after creating your component framework, you often find that there are other uses for your components beyond that which you had originally envisioned. In the case our OptionListSource components, we originally constructed them for the purpose of populating HTML select statements. But now that we have them available to us, we could very easily use these exact same components to perform field validation. After all, the option lists generated by our OptionListSource objects contain the list of the valid options for their associated fields. Why not use this list to validate the input?
The Struts Validator framework
Struts 1.1 already comes complete with a great framework for field validation, including a number of predefined Struts validators. There is no validator, however, to compare an input field value to a finite set of valid values. Since we have just created a source for such a finite set of valid values, it won't be much of a stretch to put that source to work in the Struts validator framework.
A complete discussion of the Struts 1.1 validator framework is beyond the scope of this piece, but we should at least take a quick look at the elements that we'll need to produce in order to take advantage of the capability. Basically, you need a validator class that contains the validation code, an entry in the Struts validator-rules.xml file defining your validator class, and for every field that you want validated using your validator class, you will need a field entry in the Struts validation.xml file.
Our ValidValuesValidator class
The listing below contains our new ValidValuesValidator class.
package step.five;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
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.ValidatorUtil;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.util.LabelValueBean;
import org.apache.struts.validator.Resources;
/**
* Struts validator to check for valid values. This validator
* uses an OptionListSourceFactory to obtain an OptionListSource
* for the purpose of validating that the input value is one of
* the values in the OptionList.
*/
public class ValidValuesValidator implements Serializable {
/**
* Validates the input field against the list of valid
* values obtained from the OptionListSource.
*
* @param filter an implementation-defined filter parameter
* further identifying or limiting the available options
* @return true if the input value matches one of the values
* on the list of valid values
*/
public static boolean validateValidValues(
Object bean,
ValidatorAction va,
Field field,
ActionErrors errors,
HttpServletRequest request) {
String value = null;
if (isString(bean)) {
value = (String) bean;
} else {
value = ValidatorUtil.getValueAsString(bean, field.getProperty());
}
String factoryName = field.getVarValue("factoryClass");
String optionListName = field.getVarValue("optionListName");
if (!GenericValidator.isBlankOrNull(value)) {
try {
OptionListSourceFactory factory =
(OptionListSourceFactory) Class
.forName(factoryName)
.newInstance();
OptionListSource source =
factory.getOptionListSource(optionListName);
ArrayList items = source.getOptions();
boolean valueFound = false;
Iterator i = items.iterator();
while (i.hasNext()) {
LabelValueBean item = (LabelValueBean) i.next();
if (value.equals(item.getValue())) {
valueFound = true;
}
}
if (!valueFound) {
errors.add(
field.getKey(),
Resources.getActionError(request, va, field));
return false;
}
} catch (Throwable t) {
\// here is where you would invoke your own event management or logging
System.out.println("data validation error: " + t.toString());
errors.add(
field.getKey(),
Resources.getActionError(request, va, field));
return false;
}
}
return true;
}
/**
* Determines if the object passed is a String.
*
* @param o an object
* @return true if the object passed is a String or null
*/
private static boolean isString(Object o) {
if (o == null) {
return true;
}
return String.class.isInstance(o);
}
}