Most web applications include form elements that allow a user to enter values or choose items from a list. A web application must validate these values and choices to protect its business objects from invalid data, which is often used by malicious individuals to gain control of the system on which the web application is running.
Developers can employ different techniques for including validation code in web applications. These techniques include ways to perform validation on the server, on the client, or both. Server-side validation and client-side validation each have their advantages and drawbacks.
Performing validation on the client reduces network traffic and the load on the server, which often results in a faster response time and ultimately a more pleasant experience for the user. However, not all clients support the client-side scripts that must perform the validation. Also, different clients might support different scripting languages. Consequently, developers at the very least need to provide server-side validation whether or not they include support for client-side validation in their applications.
As opposed to client-side validation, server-side validation requires extra round-trips to the server, resulting in a slower response time on even the simplest validation checks. However, a developer doesn't need to worry about supporting a growing number of clients when they perform validation exclusively on the server.
A developer who chooses to provide both client-side and server-side
validation will be stuck maintaining two redundant pieces of code.
Developers can maximize the advantages of client-side and server-side validation while minimizing their drawbacks by generating the client-side script from the same set of rules that apply to the server-side validation code. In fact, this strategy might be required as in the situation where the client-side script needs to access some information on the server to determine the validity of the input.
Among the many powerful features of JavaServer[TM] Faces is its validation model, which makes it easy to include basic server-side validation in your application and provides a flexible programming model for implementing your own custom solution.
JavaServer Faces doesn't yet include support for client-side validation. However, the JavaServer Faces component rendering model allows you to create renderers that can generate client-side validation code targeted to various clients.
While this can be a big advantage for applications that can run on
different clients, this strategy requires the developer to maintain two
redundant pieces of code: one for server-side validation and one for
client-side validation.
One solution for applications that will be rendered only in HTML is
to use Struts Validator while still using the other features included
with JavaServer Faces technology. Struts Validator not only includes a
richer set of standard validators, but these validators perform both
server-side and client-side validation. Struts Validator also allows
you to plug in custom validators by adding them to the centralized validator-rules.xml
file, which includes the corresponding client-side JavaScript[TM] for
the
validator. The centralized rules file also makes it easier to maintain
the client-side and server-side code.
Considering all of this information, consider the following recommendations:
JavaServer Faces technology provides default components that can be rendered to HTML clients. This means that you can associate an HTML "onsubmit" attribute with a JavaServer Faces HTML form component. Keep in mind that JavaServer Faces attribute names are case sensitive and must use all lower case characters in this attribute name.
Here is an example JavaScript tag included in a JavaServer Faces page:
<script language="JavaScript">
function client_validation() {
if (document.forms[0].elements["validatorForm:color"].value =="red")
return true;
} else if (document.forms[0].elements["validatorForm:color"].value =="green") {
return true;
} else if (document.forms[0].elements["validatorForm:color"].value =="blue") {
return true;
} else {
alert("Enter a red, green, or blue for the color.");
return false;
}
}
</script>
<h:form id="validatorForm" onsubmit="return client_validation();">
...
<p>Enter a color (red,green, or blue):</p>
<h:inputText id="color" value="#{ValidatorBean.color}"/>
<p>
<h:commandButton id="submit" action="success" value="Submit" />
</p>
</h:form>
This form shows validation using JavaScript. Note that the id
's
of
the form elements checked in the JavaScript are named using [form
name]:[form element id]
. In the case of this example, you will
reference the color input element using validatorForm:color
as the name. You will not be able to access the form elements from
JavaScript using a named approach, such as with
window.document.validatorForm.validatorForm:color.value == "red"
), because there is a colon used in the id
of the form
element.
Notice that the JavaScript code is hardcoded into the page. This strategy is acceptable if the JavaScript code is only used on one page or a small set of pages, and does not require any data or processing from the server.
If the script is used on multiple pages, it makes more sense to keep
the script on a separate page (such as clientValidation.js
) and include it in the pages using a specialized version of the script
tag:
<script language="Javascript" type="text/javascript"
src="clientValidation.js"/>
However, this solution doesn't solve the problem of how the script gets information from the server if it requires it. For these and many other reasons, it's often a better idea to generate the client-side script, as described in the next section.
If a client-side script needs some data from the server to perform its function, you need to include the data in the script while generating it on the server. By generating the script, you also avoid having to manually copy the script to other pages that might need it.
Another reason to generate the script is if you want various clients (including those that don't support JavaScript) to be able to run this application. JavaServer Faces technology offers a rich component rendering model, which allows you to create custom renderers that can be used to render components in different ways and to different clients.
The component classes themselves encapsulate the functionality of
the component. For example, the standard UISelectOne
component allows a user to select one of a set of values. A renderer
can define how this component should appear on the page. A UISelectOne
component can be rendered as a set of radio buttons, a menu, a listbox,
or something else by applying the appropriate renderer to the
component. The page author chooses the component and renderer
combination by using the tag that represents it on the page. The
standard tag selectOneRadio
represents the combination of
a UISelectOne
component and a Radio
renderer, which renders a set of radio buttons.
You can also use a custom renderer to render client-side script, allowing you to generate the script on the server-side and therefore give the script access to server-side data. Add to this the fact that you can write separate renderers, each of which renders script appropriate for a particular client, and you have a much more flexible and portable way of incorporating client-side scripting in your applicaitons.
In the case of generating client-side script, it's not necessary to create a custom component in addition to a custom renderer. You can use one of the standard components instead. To create a custom renderer with a component you need to perform the following tasks:
UIOutput
.To demonstrate how to render script with a custom renderer, consider the example from the previous section. This time, instead of hardcoding the script in the page, we'll write a custom renderer that generates it.
To render a custom tag from a custom renderer, you must pair the
renderer with either a standard or a custom component. For this example
that merely renders a script
tag within a
form, the simple component, UIOutput
, will work. If you
are going to add client-side script to an individual form component,
you must either make this component a custom component for which you
can create a custom renderer, or you must require the page author to
add
the script to the corresponding component tag in the page. For example,
a page author can add an onselect
attribute that has some
JavaScript (or references the script using the JavaServer Faces EL) to
the tag representing a checkbox component.
A renderer class typically includes encoding methods that produce
the markup. The encodeEnd
method from ColorRenderer
is shown below. The JavaServer Faces implementation calls the encodeEnd
method with the component that it is trying to render, which is the UIOutput
component that we are associating with this renderer. As shown in the encodeEnd
method, this renderer writes out a script that does the same thing as
the script we hardcoded in the page in. See the section above, "Adding
Client-Side Scripting
to a JavaServer Faces Page."
public void encodeEnd(FacesContext context, UIComponent component)
throws IOException {
if ((context == null) || (component == null)) {
throw new NullPointerException();
}
UIOutput script = (UIOutput) component;
UIInput currentColor = (UIInput) component.findComponent("color");
ResponseWriter writer = context.getResponseWriter();
StringBuffer sb = null;
System.out.println("currentColor =" + currentColor);
if (currentColor == null)
return;
sb = new StringBuffer("function client_validation() {\n");
sb.append("if (document.forms[0]['");
sb.append(currentColor.getClientId(context));
sb.append("'].value=='red' ) {").append("\n");
sb.append("return true;");
sb.append("\n} else if (document.forms[0]['");
sb.append(currentColor.getClientId(context));
sb.append("'].value=='green' ) {").append("\n");
sb.append("return true;");
sb.append("\n} else if (document.forms[0]['");
sb.append(currentColor.getClientId(context));
sb.append("'].value=='blue' ) {").append("\n");
sb.append("return true;");
sb.append("\n } else {\n");
sb.append("alert('Enter red, green, or blue for the color.');");
sb.append("\nreturn false;\n");
sb.append("} \n }");
sb.append("\n");
if (writer != null) {
writer.startElement("script", script);
writer.writeAttribute("language", "JavaScript", "script");
writer.write(sb.toString());
writer.endElement("script");
}
}
After creating the renderer, you need to register it with a render kit using the application configuration file. A render kit represents a set of renderers that can output markup suitable for one particular client.
Below is the render-kit
element that registers the ColorRenderer
,
discussed in the previous section. The component-family
element is a component type that identifies a component that this
renderer can render. The renderer-type
element is a
renderer type that identifies the renderer. The renderer-class
element is the actual name of the class.
<render-kit>
<renderer>
<component-family>javax.faces.component.UIOutput</component-family>
<renderer-type>Color</renderer-type>
<renderer-class>ColorRenderer</renderer-class>
</renderer>
</render-kit>
Before we were saying that your application could use multiple renderers, each of which can render the script appropriately for a particular client. If you have created a set of renderers, be sure to add corresponding renderer element tags in the application configuration resource file.
We'll see in the next section how the tag handler class uses the component type and the renderer type to tell the JavaServer Faces implementation how to render the component.
One thing the tag handler does is to retrieve the type of the component associated with the tag. It also returns the type of the renderer (if there is one) to the JavaServer Faces implementation so that the component's encoding can be performed when the tag is processed.
Here are the methods from ScriptTag
that perform these
functions for our example:
public String getComponentType() {
return ("javax.faces.component.UIOutput");
}
public String getRendererType() {
return ("Color");
}
Notice that the component type and the renderer type elements returned by these methods must match the corresponding types configured by the render-kit element in the application configuration file. See the J2EE[TM] 1.4 Tutorial for more detail on how to create a tag handler class.
If your application uses multiple renderers, each of which can
render the script appropriately for a particular client, you need to
add something like the following to the getRendererType
method of the tag handler class:
String agent = (String) getFacesContext().getExternalContext().getRequestHeaderMap().get("User-Agent");
if ((agent != null) && (agent.contains("Mozilla")) {
.... this is a Mozilla client, so return the type of the
renderer that handles this client ...
}...
This method determines what client is running the application and returns the appropriate renderer type. As described in the preceding section, you also need to register the corresponding renderers in the application configuration resource file.
The final step is to create the TLD file that defines your custom tag. Here is a piece of the TLD file from our example:
<taglib>
...
<display-name>customTags</display-name>
<tag>
<name>script</name>
<tag-class>ScriptTag</tag-class>
<body-content>empty</body-content>
...
</tag>
</taglib>
Finally, you include the taglib directive for the TLD file and the custom tag in the page, as shown here:
<%@ taglib prefix="customTags" uri="WEB-INF/customTags.tld" %>
...
<h:form id="validatorForm" onsubmit="return client_validation();">
<p>Enter a color (red, green, or blue):</p>
<h:inputText id="color" >
...
<customTags:script/>
</h:form>
Regardless of whether or not client side validation is provided, it is good practice to validate data on the server as described previously in this document. The next section demonstrates how we added server-side validation to this example.
If one of the standard validators that come with JavaServer Faces technology satisfies your needs, then use it. In that case, all you need to provide is the corresponding client-side validation script by creating a custom renderer.
If you need to provide your own server-side validation code, you can refer to the Server-side Validation entry in the Java[TM] BluePrints Solutions Catalog, which documents many techniques for performing custom server-side validation. You can employ any of these techniques when using server-side validation alongside client-side validation code in your application.
For our example, we have a custom validator class. The page author
refers to this class using the standard validator
tag.
This solution makes the most sense in our case because the page author
does not need to configure any validation parameters, and therefore we
don't need to provide a custom tag to represent the validator on the
page.
Here is the validate
method from ColorValidator
:
public void validate(FacesContext context, UIComponent component,
Object toValidate) {
String value = null;
if ((context == null) || (component == null)) {
throw new NullPointerException();
}
if (!(component instanceof UIInput)) {
return;
}
if ( null == toValidate) {
return;
}
value = toValidate.toString();
if (value.equals("red") || value.equals("green") ||
value.equals("blue")) {
return;
} else {
System.out.println("value "+value);
FacesMessage errMsg = MessageFactory.getMessage(context,
COLOR_INVALID_MESSAGE_ID);
throw new ValidatorException(errMsg);
}
}
}
Notice that the custom validator has basically the same validation
logic as the renderer class does. Unfortunately, this means that you
must maintain two redundant pieces of code. Because you must manually
write the script into a String
in the renderer encoding
methods and produce the Java code in the validator, it would be
difficult to create the client-side and the server-side validation in
place for easier maintenance.
If it helps in your particular case, you can access your custom
validator from the encodeEnd
method of the renderer
through the component passed to the method:
public void encodeEnd(FacesContext context, UIComponent component)
throws IOException {
...
UIInput inputComponent = (UIInput) component;
Validator[] = inputComponent.getValidators();
// then get the validator you're looking for from the array
...
}
You might be able to generate the client-side script using the
validation rules from the server-side validation code after accessing
it from the encodeEnd
method of the renderer. If the
renderer can recognize the validator and can determine from the
validator what checks it performs, it can subsequently generate the
appropriate Javascript. For the renderer to access the
server-side validation rules for this purpose, these rules must be
defined by a custom validator class that the renderer recognizes rather
than by a backing bean method, because it is impossible for a renderer
to determine what validation rules the backing bean method is
performing.
Another good solution is to have an external file that defines the set of validation rules that determine the behavior of both the client-side and server-side validation code. Struts Validator provides a client-side validation solution that allows you to do this. By using the struts-faces integration library, you can utilize Struts Validator in your JavaServer Faces application.
As we have demonstrated in this document, the renderers for the standard JavaServer Faces components do not provide support for client-side validation. To incorporate client-side validation into your application, you need to either produce a custom solution, as described in the preceding sections, or use a library offering support for client-side validation that you can use with your JavaServer Faces application.
The Struts-Faces integration library is used to integrate JavaServer Faces features into existing Struts applications. You can also use it to integrate Struts features, such as the Struts Validator feature, into your JavaServer Faces applications. Struts Validator provides a set of basic validators that come with JavaScript code that is already tested on multiple clients. The table below lists these validators.
Validator | Purpose |
---|---|
required | Checks if the user entered a value |
mask | Checks if the value matches the regular expression given by the mask attribute |
range | Checks if the value is within two values |
maxLength |
Checks if the field's length is less than or equal to the value given by the max attribute |
minLength | Checks if the field's length is greater than or equal to the value given by the min attribute |
byte, short, integer, long, float, double | Checks if the value can be converted to one of these primitive types |
date | Checks if the value is a valid date and conforms to an optional pattern. |
creditCard | Checks if the value is a valid credit card number |
Checks if the value could be a valid email address |
If you've already read the Server-side Validators blueprints topic, you'll notice that Struts has a larger set of standard validators than does JavaServer Faces technology. However, because the JavaServer Faces validation model is so flexible and extensible, JavaServer Faces implementors and validator and component vendors will most likely enrich this standard set of validators in the near future.
If your JavaServer Faces application already uses a standard JavaServer Faces validator and you want to add client-side validation to go along with it, you can create a custom renderer, as explained in Generating JavaScript Using a Custom Renderer. However, even though the standard server-side validation code is provided by the reference implementation, you still have the problem of two redundant pieces of code when you add the JavaScript to your application.
You can remedy this problem while making the set of Struts validators available to your JavaServer Faces application by using Struts Validator. This allows you to take advantage of a potentially more powerful client-side validation framework and still reap all the considerable benefits of using JavaServer Faces technology in the same application.
Incorporating Struts Validator in your JavaServer Faces application involves several steps:
WEB-INF/lib
directory of
your JavaServer Faces application: struts.jar
, commons-validator.jar
,
commons-lang.jar
, and jakarta-oro.jar,
struts-faces.jar
web.xml
):<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
validator-rules.xml
file that comes with
the Struts project to the WEB-INF
directory of your
application. This file declares the server-side validator routines and
defines the corresponding client-side JavaScript code used by the
application. <%@ taglib prefix="s"
uri="http://struts.apache.org/struts/tags-faces" %>
javascript
tag of the struts-faces
integration library to the page, somewhere outside the form tag
:
<s:javascript formName="myForm" />
h:form
tag in your page with the s:form
tag from the struts-faces integration library. Make sure the form
tag has an ID and that it matches the formName
attribute
of the javascript
tag. form
tag an onsubmit
attribute that invokes the JavaScript validate
MyForm
(this)
function where MyForm matches the formName
attribute and the ID of the form: <s:form id="myForm" onsubmit="return
validateMyForm(this);">
validator.xml
that
defines how the validator routines included in validator-rules.xml
are applied in your application. For example, if you have a page with a
login form, and you want to restrict the length of the input to the username
field (similar to what the standard JavaServer Faces ValidateLength
validator can do), you can apply the Struts minlength
and
maxlength
validators. The following example
demonstrates restricting the input to at least 3 characters and no more
than 16 characters. Each of the arg0
, arg1
,
and arg2
tags refer to a message that is displayed if a
particular kind of validation fails.
<formset>
<form name="logonForm">
<field property="username"
depends="minlength,maxlength">
<arg0 key="prompt.username"/>
<arg1 key="${var:minlength}" name="minlength"
resource="false"/>
<arg2 key="${var:maxlength}" name="maxlength"
resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>16</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>3</var-value>
</var>
</field>
...
</formset>
struts-config.xml
file, which specifies a resource bundle for validation messages, the
validation configuration files, action mappings and any form beans for
forms
that contain fields
that need to be validated. Here is an example of each:<form-beans>
<form-bean name="validatorForm"
type="com.sun.j2ee.blueprints.catalog.validator.LoginForm">
</form-bean>
</form-beans>
<action-mappings>
<action path="/logon"
type="com.sun.j2ee.blueprints.catalog.validator.LoginAction"
name="validatorForm"
scope="request"
input="validator"/>
</action-mappings>
<message-resources
parameter="com.sun.j2ee.bleuprints.catalog.validator.ApplicationMessages"/>
As you can see, using one of the standard struts validators requires a lot more work than using one of the standard server-side JavaServer Faces validators. For this reason, if you are not performing client-side validation, and one of the JavaServer Faces standard validators meets your needs, then you should use it.
On the other hand, because Struts Validator gives you a larger set of standard validators, each of which come with client-side validation code built-in, you should consider using Struts Validator in these cases:
If you are performing client-side validation for non-HTML clients, you will need to use a JavaServer Faces validator because you need a custom renderer to render the script appropriately for non-HTML clients.
Struts Validator can also be used for implementing custom validators in a JavaServer Faces application. The example validation code from Adding Client-Side Scripting to a JavaServer Faces Page cannot be performed by any of the standard Struts validators. Regardless of whether you are using the JavaServer Faces validation model or Struts Validator, you still must implement a custom validator for this example. If this application runs only on HTML clients, you can use Struts, which might be a better solution because it requires less work to implement the custom validator and its centralized rules file makes it easier to maintain the validation code.
To create and use a custom validator, you need to do the following:
validation.xml
file.validator-rules.xml
file with a validator
element representing your new validator. This new element will also
define the client-side JavaScript code.Creating this custom validator is outside the scope of this entry;
instead, we leave it as an exercise for the reader. The important
thing to note is that the rules for performing the validation are
defined in
the centralized validation file, which is unique to the application.
Changing the
rules in this file will change both the server-side and client-side
validation behavior because the code for each type of validation
accesses the rules in this file.
The code that performs the validation for our example can be more generalized so that it can compare any set of String values, unlike ColorValidator or ColorRenderer, which only check if input matches the strings "red", "green", or "blue". You define which strings to compare in validation.xml. Of course, this means you have an easier time synchronizing the client-side and server-side code.
After creating your own validator, you need to declare it and define
its corresponding client-side JavaScript in the same validator-rules.xml
file that includes the declarations and definitions of the standard
Struts validators.
Using Struts Validator for creating custom validators has many benefits. By defining the validation rules separately from the behavior of the validation code, you can make the validation code easier to maintain, more pluggable, and less tightly coupled to the application code.
For more information about this topic, refer to the following:
For more details on validators with JavaServer Faces technology, see the J2EE 1.4 Tutorial.