Using exception for server-side validation in JSP

[difficulty: expert]

Summary

In this article I will introduce a simple and convenient strategy to manage the server-side validation of data inserted by the user in a web application through the mechanism of exceptions offered by the Java language and JSP standard. (3338 words; 2 June 2002)

 

by Luigi R. Viggiano

Introduction

JSP (Java Server Pages) technology is a widely used standard for the development of enterprise web applications. JSP integrates technologies like JDBC and EJB so that it offers the developer a complete framework upon which to build complex internet applications based on Java.

 

Most web applications, if not all, require the user to enter data which eventually finds its way to a database. This implies that the data should be validated so as to prevent insertion of data which is inconsistent or wrong. Although it is possible to perform the validation on the client side using a browser with simple JavaScript routines, there is such a extreme variation in browsers that this approach is risky because it does not guarantee the correct execution of the client side scripts. Therefore, it is considered good practice to validate the data on the server side.

 

Server-side validation

Recognizing that server side validation is very useful and the existence of a multitude of diverse web applications which perform this task in different ways, JSP does not enforce any particular approach to deal with this recurring aspect of web applications.

 

Figure 1 – validation with error page

Figure 2 – validation with errors reported in the form

 

In the examples shown above in Figure 1 and Figure 2 implement the Model View Controller (MVC) Pattern. Notice how I have implemented the general preference to separate the business logic called “Controller” (validate.jsp) from the presentation pages called “View” (error.jsp, form.jsp and target.jsp). The Model classes which would represent the internal state of the application are not shown. These Model classes are generally kept by JavaBeans valid for the whole http session.

 

The Model 2 architecture (see references) anticipates that controllers, that are the non-visual parts, may be implemented by servlets, However, here I am using JSP only since in the context of this article there are not remarkable differences. Moreover, this presentation is intended to simplify the regeneration of the environment and allow for a faster deployment. For further informations about the server-side design patterns and about relative methodologies please refer to the documentation on architectures like Jakarta Struts framework ( http://jakarta.apache.org/struts/index.html ).

 

Form.jsp shows the HTML form inside the browser. When the user presses the submit button, the inserted data is sent to the validate.jsp page. This page validate.jsp acts as a controller so it does not produce any output, on the contrary it encapsulates the business logic. It performs the data validation and consequent entry of the data into the database. Finally it redirects the validate.jsp to the target.jsp which shows the user a notification message about the successful completion of the transaction.

If the user has entered invalid data, validate.jsp handles a validation failure by redirecting the page to “error.jsp” which will subsequently show the error to the user (see Figure 1). At this point the user will return to the form.jsp through a hyperlink so the data can be re-entered correctly.

 

An alternative is shown in the example illustrated in Figure 2. In this approach the user does not have to look for his mistakes but instead the errors are highlighted when the user is redirected to the form which is now updated with the appropriate error messages, preserving approved data. Even though this is an improvement from the usability aspect, mostly when there are many fields in the form and you don’t want that the user wastes time trying to understand where he is doing wrong, it implies an increase of complexity from the developer perspective. For example, the form.jsp must now to deal with the display of contents and the positioning of the error messages.

 

The following is an illustration of the last case in detail.

 

Functionality

You may notice that in the example shown in figure 2, the user first enters the data, then after pressing the submit button he is redirected back to the form.jsp until all the inserted data is acceptable, and finally the flow of the program proceeds.

The classic approach to implement this mechanism is using JSP forwarding to bounce back the user to the form when data is wrong, displaying the error messages near to the rejected fields. To do that, the programmer often falls in the trap of using cryptic error codes, often ambiguous, which compromises the maintenance of the application. Also sometimes, performing the error handling in different locations is commonly implemented using vectors of codes or other complicated tricks which are not always very clean and could lead to the introduction of bugs.

In summary, this a sort of “do-it-yourself” error management used in old procedural languages. And the state of the error is maintained through numerical codes and the management is done with “if-then-else” statements which are frequently cascaded. This is obviously not suitable for object oriented code.

 

The solution that I am presenting in this article is to employ exception handling functionality which is offered by the Java language. Because JSP technology is based upon Java this exception handling ability can be used to develop clear code that is easier to maintain.

 

The goal one wants to achieve is to manage error as follows:

 

  1. Instantiate an exception with a generic message

Example: “Error validating submission”

  1. Add to this exception the detailed messages of errors, which identify the invalid fields and eventually indicate the necessary information to correct them.

Example: “Erong date: MM-dd-yyyy”

  1. If there have been validation errors, raise the instance of the exception to a higher level, since the program automatically sends the information to the view.

 

All this is done in the validate.jsp code shown in Figure 3. Notice that the code in the panel of validate.jsp is just a sample. In the reality the code would be slightly more complex, but the effect and process would be the same, as we will see later.

 

Figure 3 – flow of the exception

Form.jsp collects the data, then, on submit, validate.jsp is executed and raises an exception in case of unacceptable data. At this point the exception is caught and managed by form.jsp that now contains validation errors and precompiled fields when they are accepted by the checks.

 

Inside the code contained in validate.jsp, on the first line an instance of ValidationException class is created and then, in subsequent checks, we add error messages related to invalid fields invoking method addMessage(). After having checked all fields, it is necessary to raise the exception using the keyword throw in case of at least one of inserted data is invalid; otherwise (all fields are valid) a forward to the confirmation page is made.

 

When an exception thrown by the web application reaches the servlet container, this is forwarded to the exception-page that will manage the mechanism just illustrated. Generally, in JSP based application, the exception-page is only used to print the stack trace of un-handled exceptions, that is when the exception is not caught is automatically sent to the exception page (if defined), that generally the stack of method invocations that produced the error, inside the HTML given to the browser.

The following will illustrate how the exception page can do something much more useful.

 

Implementation

First of all we have to write the code of a “presentation exception” that distinguishes itself from the errors that could occur for unexpected conditions (RuntimeExceptions). This exception will be named ValidationException and will extend from ServletException.

As usual it will be present the error message, but this exception needs to be able to contain also several error messages related to fields that missed validation checks. This is done by the member instance “messages” that is a Map (interface of Hashtable and HashMap).

The exception will also contain an instance variable called “errorPage”, a String, that indicates to which URL the error messages shall be sent to be shown in the browser. Finally we define the method raise(), with the responsibility to throw the exception, if and only if there are some error messages to be shown. If there are no messages, it means that all the validation checks had success, then the exception must not be thrown and the program flow can continue forward (for example, recording data in the database).

 

Listing 1 – ValidationException.java (partial)

public class ValidationException extends ServletException {

    private String errorPage;

    private Map messages;

 

    public ValidationException(String msg, String errorPage) {

        super(msg);

        setErrorPage(errorPage);

    }

 

    public java.util.Map getMessages() {

        if (null == messages)

            messages = new HashMap();

        return messages;

    }

 

    public void addMessage(String message, String position) {

        getMessages().put(position, message);

    }

 

    public void raise() throws ValidationException {

        if (null != messages && ! messages.isEmpty())

            throw this;

    }

}

 

After this, we obtain an exception-page able to catch only ValidationException, executing the forward (line 9) to the page entrusted to show the errors contained in the exception:

 

Listing 2 – ValidationErrorPage.jsp

<%@ page language="java"

         contentType="text/html"

         import="net.jx.servlet.ValidationException"

         isErrorPage="true"

%><%

    ValidationException valEx = (ValidationException)exception;

    String errorPage = valEx.getErrorPage();

    if (null != errorPage)

        pageContext.forward(errorPage);

    else

        throw new ServletException("ErrorPage not set", valEx);

%>

 

Obviously our servlet container have to be set up to send to this error-page only the validation exceptions. We can do that modifying opportunely the descriptor web.xml as shown in listing 3.

Web.xml is a configuration file that allows us to specify several parameters that will be valid in the context of our web application. This file needs to be saved in the directory WEB-INF created in the root of the web tree. Beyond to exception pages, it is also possible to specify the welcome-files (generally index.html, index.jsp, default.html etc…), the mapping between URL and servlets, the tag-libraries, MIME-TYPES and other security information. Once created the application tree with the configuration file WEB-INF/web.xml, we can pack it in a file with extension “.war” and distribute it for the deploy in any web container implementing the spec.

 

Listing 3 – web.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE web-app PUBLIC

       "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"

       "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd" >

<web-app>   

  <error-page>

    <exception-type>net.jx.servlet.ValidationException</exception-type>

    <location>/error/ValidationErrorPage.jsp</location>

  </error-page>

</web-app>

 

So, we have now indicated to the servlet container to send any exception of type net.jx.servlet.ValidationException to the URL /error/ValidationErrorPage.jsp. All the other exceptions will be sent to the default error-page which will simply print the stack trace. When an exception of type ValidationException will be caught from the servlet container, it will be sent to ValidationErrorPage.jsp that works as a dispatcher.

In this case, if  Validate.jsp finds that the data are not acceptable, it will throw an exception of type ValidationException containing ”Form.jsp” as error-page that will show error messages.

 

Listing 4 – validate.jsp

<%@ page language="java" %>

<%@ page import="java.text.*" %>

<%@ page import="java.util.Date" %>

<%@ page import="net.jx.sample.SampleBean" %>

<%@ page import="net.jx.servlet.ValidationException" %>

<%

    // Clear any old bean and create a new one in session keeping data from

    // parameters in the request.

    session.removeAttribute("sampleBean");

    SampleBean sampleBean = new SampleBean();

    session.setAttribute("sampleBean", sampleBean);

 

    // Get submitted fields

    String textField = request.getParameter("mandatoryTextField");

    String dateField = request.getParameter("dateField");

    String currencyField = request.getParameter("currencyField");

 

    // Instantiate the exception with the default message

    ValidationException validationEx =

        new ValidationException("Error validating submission", "/Form.jsp");

 

    // Mandatory text field validation.

    if (null == textField || textField.length() == 0)

        validationEx.addMessage("Mandatory field", "msgMandatoryField");

    else

        sampleBean.setMandatoryTextField(textField);

 

    // Date field validation.

    if (dateField != null && dateField.length() > 0) {

        String pattern = "MM-dd-yyyy";

        DateFormat dateFormatter = new SimpleDateFormat(pattern);

        try {

            Date date = dateFormatter.parse(dateField);

            sampleBean.setDateField(date);

        } catch (ParseException parseEx) {

            validationEx.addMessage("Wrong date: " + pattern, "msgDateField");

        }

    }

 

    // Floating point numeric field validation

    if (currencyField != null && currencyField.length() > 0) {

        try {

            double value = Double.parseDouble(currencyField);

            sampleBean.setCurrencyField(new Double(value));

        } catch (NumberFormatException nfEx) {

            validationEx.addMessage("Wrong numeric format", "msgCurrencyField");

        }

    }

 

    // if any submitted data has been rejected, bounce back...

    validationEx.raise();

 

    //make the bean persistent

    sampleBean.store();

 

    // the sampleBean is now persistent, we do not need it in session.

    session.removeAttribute("sampleBean");

    // go in the "success" page.

    response.sendRedirect(request.getContextPath() + "/Target.jsp");

%>

 

Validate.jsp does not contain HTML code because, as already mentioned, it is a controller and it just contains application logic. It first extracts the data sent by the user from the request and then it performs the validation checks, field by field. Inside the constructor of the exception it is indicated the page that must show the error messages:

Listing 5 – Creation of ValidationException

    ValidationException validationEx =

        new ValidationException("Error validating submission", "/Form.jsp");

 

Next the field controls take over, adding messages through the method addMessage:

Listing 6 – Data validation

    if (null == textField || textField.length() == 0)

        validationEx.addMessage("Mandatory field", "msgMandatoryField");

    else

        sampleBean.setMandatoryTextField(textField);

 

In this case the textField (that is a mandatory field) has not been filled, so the message “Mandatory field” is added to the exception, and it will be shown at position indicated by the label “msgMandatoryField” inside Form.jsp.

After all checks, we can call the method validationEx.raise() that throws the exception if at least one of the fields is not valid. Otherwise Validate.jsp continue the execution making the data contained by the object, persistent in the database and forwarding the program flow to the page Target.jsp, that notifies the user that everything went according to plan.

 

By this time we now see that form.jsp can show the error messages (if present), to allow the user to reinsert the wrong data. First of all, we must include the attribute isErrorPage=”true” in the page directive, so the validation exception can be visible from inside the JSP page. Then we have to check if exceptions have occurred, if yes we can get the messages to show up in the form near the fields to which they are related.

Listing 7 – Getting error messages from the exception

    if (null != exception) {

        // fill messages

        ValidationException validationEx = (ValidationException) exception;

        msgException = validationEx.getMessage();

        msgMandatoryField = validationEx.getMessage("msgMandatoryField");

        msgDateField = validationEx.getMessage("msgDateField");

        msgCurrencyField = validationEx.getMessage("msgCurrencyField");

    }

 

Consequently, to show the exception near a field you just need to insert the scriptlet in the JSP as shown in listing 8.

Listing 8 – Placing error messages in the HTML

          <td align="left">

            <font face="Verdana,Arial,Helvetica,sans-serif" size="2" color="red">

              <strong><%= msgMandatoryField %>   </strong>

            </font>

          </td>

 

One of the advantages of the exposed architecture (possably important) is that lets you to reach a more reusable and general purpose code: it becomes very easy to develop utility classes to handle checks on fields. Moreover it happens often that the checks  to apply to different fields are the same: let’s think about mandatory field, numeric fields, dates etc…We can write a class with has responsibilities about data validation, and we can use it inside our web controllers on which we can delegate data evaluation jobs.

 

Listing 9 –Validator.java (partial)

public class Validator {

    private String errorPage;

    private ValidationException validationEx;

 

    public Validator(String errorPage) {

        this.errorPage = errorPage;

    }

 

    private ValidationException getValidationException() {

        if (null == validationEx)

            validationEx = new ValidationException(

                "Error validating submission", errorPage);

        return validationEx;

    }

 

    //check for null/empty string

    public Object mandatory(String field, String name) {

        if (null == field || field.length() == 0)

            getValidationException()

                .addMessage("Mandatory field", name);

        return field;

    }

 

    public Date validateDate(String field, String name) {

        if (field == null || field.length() == 0) return null;

        String pattern = "MM-dd-yyyy";

        SimpleDateFormat dateFormatter =

            new SimpleDateFormat(pattern);

        try {

            return dateFormatter.parse(field);

        } catch (ParseException parseEx) {

            getValidationException()

                .addMessage("Wrong date: " + pattern, name);

            return null;

        }

    }

 

    public void validate() throws ValidationException {

        if (validationEx != null)

            validationEx.raise();

    }

}

 

In this case we instantiate the Validator class inside the controller JSP and then pass the constructor for the Validator class to the error handler page.

Then we create methods validateXXX(String field, String name) passing as parameter fields the content of the field as come from the request and as parameter name the label related to the field, identifying also where the error-message needs to be shown inside the errorPage. Finally we invoke the method validate(), that throws the exception in case of one or more checked fields are not conforming, and activating the redirection mechanism as described before.

Notice that the return-type of methods validateXXX() change in relation of the type of the validation, as the conversion job of the string fields come from the request will be done during the validation.

Listing 10 shows how the validation code previously listed (in listing 4) could become using the Validator class.

 

Listing 10 – Validating code using Validator class

    String textField = request.getParameter("mandatoryTextField");

    String currencyField = request.getParameter("currencyField");

    String dateField = request.getParameter("dateField");

 

    Validator validator = new Validator("/Form.jsp");

 

    sampleBean.setMandatoryTextField(

        (String)validator.mandatory(textField, "msgMandatoryField"));

 

    sampleBean.setDateField(

        validator.validateDate(dateField, "msgDateField"));

 

    sampleBean.setCurrencyField(

        validator.validateCurrency(currencyField, "msgCurrencyField"));

 

    validator.validate();

 

A similar example can be found in the book “Core J2EE Patterns” (Chapter 3, pag.45 “Validation Based on Abstract Types”, example 3.5)

 

Considerations / Limitations

Someone could make the argument that is not agreeable to have a “view” (Form.jsp) declared with the page attribute isErrorPage=”true”, as it ‘s not really an ErrorPage.  But we need to get the error messages from the exception, and errors are  quite inevitable. Also… how can we make this page to become a servlet, if we cannot declare it with isErrorPage=”true” ? In reality, it is possible to get a reference to the exception even if we are not inside an ErrorPage, defining explicitly the exception object choosing between one of following lines of code (Listing 11).

 

Listing 11 – Getting the exception explicitly

Throwable exception = (Throwable) request.getAttribute("javax.servlet.error.exception");

// ...or...

Throwable exception = (Throwable) request.getAttribute("javax.servlet.jsp.jspException");

 

Using request you can obtain the reference to the exception getting the attribute "javax.servlet.error.exception".  But this attribute has been defined since the Servlet Specification 2.3  (SRV.9.9.1 Request Attributes),  this implies that servlet engines 2.2 compliant, like Tomcat 3.x, not supporting this functionality will return null. Instead, Tomcat 4, that is the Servlet 2.3 reference implementation will work perfectly (and this is the recommended way).

 

But if you use Tomcat 3.x or another servlet engine implementing servlet spec 2.2, you must use the second line of code shown, but as you can see it’s a JSP-specific functionality.

Just to be more precise, if you are using Tomcat, it’s also possible to obtain the reference to the exception in the same way using ”tomcat.servlet.error.throwable”,  but that is strongly tied to Tomcat, and clearly it isn’t recommendable at all.

 

Conclusions

In this article we discussed a method to manage server-side validation of an HTML form.

This mechanism can easily be extended and modified to cover specific needs of your web applications.

Server side validation can be used as unique solution in an intranet application. For internet applications, where the response speed is low, it could actually be better to combine server side validation with some client script to relieve the network traffic. Anyway it’s always good to address validation logic on the server.

 

Source code

Source code presented in the article is available for download. Inside the zip file you can find project files following the JBuilder 5 format. Just click on “play” to run the demo.

In the zip you can find also the war (Web Archive) file that can be used with Tomcat or any other compatible servlet engine.

 

Author biography

Luigi Rocco Viggiano.  Sun Certified Web Component Developer on J2EE platform, provides consulting, training and distributed software development on Java/J2EE technologies.

 

e-mail: lviggiano@tiscalinet.it

 

I want to thank Cindy Nelson, helping me to translate this document from Italian, Alex Garbagnati, Nicola Vota, Mauro Antonaci, Francesco Meschia, for their valuable suggestions, opinions and technical reviewing.

References

Here you can find more information about argument treated in this article:

 

·         The JavaServer Pages Home Page

http://java.sun.com/products/jsp/

·         The JavaServer Pages Syntax Reference

A brief summary of basics JSP tags

http://java.sun.com/products/jsp/tags/11/tags11.html

·         Sun's J2EE Blueprints section about the web tier

http://java.sun.com/j2ee/blueprints/web_tier/qanda/index.html#directive

·         The Jakarta Struts Framework

for building MVC architectures with JSPs

http://jakarta.apache.org/struts/index.html

·         Strut Your Stuff with JSP Tags

by Thor Kristmundsson

http://www.javaworld.com/javaworld/jw-12-2000/jw-1201-struts.html

·         Core J2EE Patterns: Best Practices and Design Strategies

by Deepak Alur, John Crupi, and Dan Malks

(Prentice Hall PTR, 2001; ISBN: 0130648841)

http://www.amazon.com/exec/obidos/ASIN/0130648841

·         Understanding JavaServer Pages Model 2 Architecture

by Govind Seshadri

 http://www.javaworld.com/javaworld/jw-12-1999/jw-12-ssj-jspmvc.html

·         The JavaBean Home Page:

http://java.sun.com/produtcs/javabeans