Wednesday, May 26, 2010

Form level validation with JSF and RichFaces

Validating input data is a common task for any web application. Java Server Faces (JSF) comes with a standard type conversion and validation framework that can be used for implementing validation logic at view layer. In other words, JSF validation is not focused on form level validation (which is good for validating relationships between fields like From and To date). To overcome this limitation, developers often bundle validation logic directly into the domain model, where business logic is executed, and cluttering domain classes with validation code which in most cases requires a lot more coding than the actual business logic processing.

Hibernate Validator (JSR 303) helps to remove this cluttering by defining a metadata model and API for domain model validation. This works well for implementing business validation but Hibernate Validator suffers from the fact that input data validation is purely a view concern where condition for executing validation logic is embedded in the view. Moreover, the validation model employed by Hibernate Validator framework can easily be misused and completely diminish separation between business model and view (MVC pattern violation) and also code becomes more difficult to maintain and minimises reuse.

I added this Form Validation framework to overcome some of the pitfalls mentioned above by adhering to the following objectives:

• Simplify the wiring of validation rules through configuration rather than coding.
• Bring back the focus of validation rules on performing validation logic to achieve greater reuse and ease unit testing.
• Support for validation levels to modularise validation logic.

Getting started



This following example will show you how to start with the Form Validation framework by configuring and implementing a simple validation rule to check for email address syntax.

Applying rule



Validation rule is configured in the view (.xhtml) by applying the rule to the appropriate component. The input text field email has a field-level validation rule specified against it (more about validation levels in the next chapter). The name attribute is used to specify the validation rule instance EmailAddressRule on the server side.

<h:form id="form">
<h:outputLabel for=”email” value=”Email Address” />
<h:inputtext id="email" value="#{bean.email}">
<xyz:validateField name="EmailAddressRule" />
</h:inputtext>
<h:message for=”email” />
</h:form>


Validating rule



To perform the email address validation we use a FieldRule instance called EmailAddressRule which is the same as the name attribute of the rule applied in the view. This class overrides the validate method of FieldRule to perform validation logic on the email address syntax. If an invalid email address is entered on the form, it will add an error with an appropriate message to be displayed on the view.

public class EmailAddressRule extends FieldRule {

private static final String VALID_EMAIL =
"^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)"
+ "|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$";

@Override
public void validate(final List<ValidationMessage> messages,
final UIComponent component,
final Object value) {

if (value != null
&& (value instanceof String && !StringUtils.isEmpty((String) value))) {
final String emailAddress = (String) value;
if (!emailAddress.matches(VALID_EMAIL)) {
messages.add(new ValidationMessage(FacesMessage.SEVERITY_ERROR,
"Invalid {0}.");
}
}
}
}


Running the view and enter an invalid email address in the input text field will result in the following error message to be displayed after a form submit

Invalid Email Address.


Validation step by step



In this section we will see in more detail how to use the Form Validation framework to validate a view. We begin with a detailed explanation on how to configure validation rules followed by some notes detailing how it is best to implement your validation logics.

Defining rules



As seen in the previous section, the framework offers two levels of validation, namely field-level and page-level validation. One might have guessed that field-level validation is used to validate the input data of a single field and page-level for multiple field input data. On the contrary, validation level has nothing to do with whether you want to validate one or more input data values. The level is used to determine the order which validation rules will be executed on the server and how validation messages to be displayed on the view. Having said that, field-level validation will mostly consists of single input field validation since it will be performed prior to page-level validation.

As the example shows, EmailAddressRule is a FieldRule instance used to validate single input field value. In the next section we will see how to define single input field and multiple input field validation through the implementation of validation rules.

Validator tag



Both field-level and page-level validation can be specified using tag. This component is used purely for passing validation rule configuration to the server and thus has no renderer associated with it.

Example

<xyz:validate type=”fieldLevel” name=”EmailAddressRule” />


There are also two Facelets short-cuts for specifying field-level and page-level validation, namely and .

Rule parameters



Apart from the above attributes, validation rule also accepts parameters for multiple field values and validation message arguments. For the above example we can override the default message argument using tag

<xyz:validateField name=”EmailAddressRule”>
<f:param value=”email address syntax” />
</xyz:validateField>

To convert the error message to

Invalid email address syntax.


The following example shows how to specify a rule to validate multiple input values, where ValidateExtensionDatesRule is a FormRule instance which accepts two input dates and perform validation logic on those values.

<h:inputText id=”fromDate” value=”#{bean.fromDate}” />
<h:inputText id=”toDate” value=”#{bean.toDate}”>
<xyz:validateField name=”ValidateExtensionDatesRule”>
<f:param value=”#{rich:clientId(‘fromDate’)” />
<f:param value=”#{rich:clientId(‘toDate’)” />
</xyz:validateField>
</h:inputText>


Also notes that even ValidateExtensioinDatesRule performs validation across multiple input fields, it will be executed at field-level since it is configured with tag.

Conditional validation



When using AJAX request it would be a good idea to limit server-side processing to only those components whose values have been modified on the view. RichFaces provides the tag to mark areas on the JSF component tree to be processed on the server during the Apply Request Values, Process Validations, and Update Model Values phases. While we cannot change how the form is submitted (all input fields on the form will be submitted), we can control which components will be processed on the server. Components that are not processed on the server will not be validated and will not be pushed on to the model (during the Update Model phase).

Let’s look at the following example where we don’t want to validate fields for which the user hasn’t had a chance to enter anything. Placing each input and message tag inside a region will restrict processing to the region from which the request was sent.

<h:panelGroup>
<a4j:region id=”region1”>
<h:inputText id="name" value="#{bean.name">
<a4j:support event="onblur" />
<xyz:validateField name="MandatoryRule" />
</h:inputText>
<h:message for="name" />
</a4j:region>
</h:panelGroup>

<h:panelGroup id=”region2”>
<a4j:region>
<h:inputText id="age" value="#{bean.age}">
<a4j:support event="onblur" />
<xyz:validateField name="MandatoryRule" />
</h:inputText>
<h:message for="age" />
</a4j:region>
</h:panelGroup>


When the user places the mouse cursor into the name field then without entering anything, leave the field and place the mouse in the age field, an error message will be displayed next to the name field but no error message on the age field as expected.
A closely related feature to the region is ajaxSingle attribute. The attribute can be applied to just one component while can contain any number of components.. For single input field validation, ajaxSingle should be used to limit server-side processing to the designated component as shown in the following example

<a4j:outputPanel id=”idInputFieldPanel”>
<h:outputLabel for=”idInputField” value=”Field label” />
<h:inputText id=”idInputField” value=”#{bean.input}”>
<xyz:validateField name=”MandatoryRule” />
<a4j:support event="onchange"
reRender="idInputFieldPanel"
ajaxSingle="true"
bypassUpdates="true" />
</h:inputText>
</h:message for=”idInputField” />
</a4j:outputPanel>


Another important attribute is process. It’s available on all RichFaces components that fire an AJAX request and is used in conjunction with ajaxSingle. When ajaxSingle is set to true, we know that only this component will be processed. A situation might arise where you still need to process some specific other components on the page in addition. The process attribute points to those components. process can also point to an EL expression or container component id in which case all components inside the container will be processed.

<h:inputText>
<a4j:support event="onblur" ajaxSingle="true" process="infoPanel" />
</h:inputText>
<h:panelGrid id="infoPanel">
<h:inputText />
<h:dataTable>
...
</h:dataTable>
</h:panelGrid>


The framework also provides some additional means to restrict validation rules being triggered via attributes of tag and UICommand components. The disabled attribute of can be used to disable validation when certain conditions are met.

The for attribute of tag can also be used to restrict validation to those events generated by the specified list of id’s. The syntax is similar to the process attribute of tag.

You can also be able to skip all validations on a page when certain actions are applied to a UICommand component by setting the skipValidation attribute for the UICommand component. As shown in the following example, all validations will be skipped when user clicks the ‘Save As Draft’ button on the screen.

<a4j:commandButton id="save" value="Save As Draft" …>
<f:attribute name="skipValidation" value="true" />

</a4j:commandButton>


Validating rules



Rules are validated by corresponding java objects on the server. At the time of writing there are three classes of validation rules, namely FieldRule, FormRule, and ListRule but other sets can be added to the framework to provide specialised versions of rule classes. Each validation rule class has to provide its own implementation for the validate method which adds the appropriate ValidationMessage instances to the List when validation fails.

Validation rule class can be implemented by calling Validation Service to perform required business validation prior to INVOKE_APPLICATION phase. This will ensure that when it comes to execute your action method, user input data has passed validation and your action only needs to perform the required business logic.

Field rule



FieldRule is used for single input field validation and thus should always be attached to the designated input component. When configuring a FieldRule on the view, no parameters are required except for those to be used for error/warning message interpolation. Where no message arguments are specified, the label for the input field (if any) will be passed as the default argument.

The signature for the validate method is as follows

void validate(List messages, UIComponent component, Object value)


Form rule



FormRule is used for multiple (cross-page) field validation and would expect one or more input parameters. Even when attached to an input component, its parameter still needs to be explicitly specified. FormRule is usually configured with two sets of parameters, one to provide data input to perform validation logic, the other for error/warning message interpolation.

The signature for the validate method is as follows

int validate(List messages, Object[] values)


List rule



ListRule is a specialised version of FormRule where the only expected parameter is the AbstractListBean model instance. For that reason, when configuring a ListRule on the view, immediate flag should be set to true to trigger validation after the model has been updated.

The signature for the validate method is as follows

boolean validate(List messages, AbstractListBean listBean)


Framework design



The key to this is the following marker interface and the abstract Validator class

// Validation rules - FieldRule, FormRule, ...
public interface ValidationRule {

List accept(AbstractValidator validator);
}


// Validation levels - FieldLevelValidator, PageLevelValidator, ...
public abstract class AbstractValidator {

public List apply(final FieldRule fieldRule) {
return null;
}

public List apply(final FormRule formRule) {
return null;
}

...
}


The concrete validators are used by a phase listener which parses the component tree to build a map of configured validation rules. If a component has a validation rule applied against it, the phase listener looks up the corresponding rule object and validates the input values for that component.

Looking at the class diagram below, you can read the association between the main components of the Validation Framework. At the top of the diagram sits ValidationPhaseListener, once registered with the JSF implementation, will get notified to trigger all validation logic for the current view. The listener only listens for the following phases:

• After PROCESS_VALIDATION phase – Trigger all input validation rules with submitted values from the request.
• After UPDATE_MODEL_VALUES phase – Trigger all input validation rules where immediate flag is set to true.
• Before RENDER_RESPONSE phase – Trigger all output validation rules where validationOnRender flag is true.



The following sequence diagram shows what actually happens behind the scene in each phase the listener is listened in. First a RuleMap will be created to prepare the list of all validation rules configured for the current view. Each rule then got allocated a validator whose job is to execute validation logic and return error messages when validation fails.