Sun Java Solaris Communities My SDN Account Join SDN
 
Tutorials & Code Camps

NO TITLE

 
[Top] [Prev] [Next] [Bottom]

Handling Exceptions

What was happening the last time you used a JSP application and you entered something incorrectly? If the application was well written, it probably threw an exception and displayed an error page. Exceptions that occur while a JSP application is running are called runtime exceptions and are described in this tutorial.

Just as in a Java application, an exception is an object that is an instance of java.lang.Throwable or one of its subclasses. Throwable has two standard subclasses-java.lang.Exception, which describes exceptions, and java.lang.Error, which describes errors.

Errors are different from exceptions. Errors usually indicate linkage or virtual machine problems that your Web application probably won't recover from, such as running out of memory. Exceptions, however, are conditions that can be caught and recovered from. These exceptions might be, for example, a NullPointerException or a ClassCastException, which tell you that a null value or a value of the wrong data type has been passed to your application while it is running.

Runtime exceptions are easy to handle in a JSP application, because they are stored one at a time in the implicit object named exception. You can use the exception object in a special type of JSP page called an error page, where you display the exception's name and class, its stack trace, and an informative message for your user.

A runtime exception is thrown by the compiled JSP file, the Java class file that contains the translated version of your JSP page. This means that your application has already been compiled and translated correctly. (Exceptions that occur while a file is being compiled or translated are not stored in the exception object and have their messages displayed in the command window, rather than in error pages. These are not the type of exception described in this tutorial.)

This tutorial describes how to create a simple JSP application with several display pages, a JavaBeans component, and one error page that gives informative error messages to the user. In this example, the Bean tracks which JSP page the user was working in when the exception was thrown, which gives you, the developer, valuable information so that you can display an informative message. This is a simple error tracking mechanism; we will describe more complex ones later in this book.

How To Add Error Pages

Even though we call them error pages, the specialized JSP pages we describe here actually display information about exceptions. To add error pages that display exception information to a Web application, follow these steps:

  • Write your Bean (or enterprise bean, servlet, or other component) so that it throws certain exceptions under certain conditions.
  • Use a simple tracking mechanism in your component to help you gather information about what your user was doing when the exception was thrown. (If you move into developing J2EE applications, your application will be able to save state, which is a better way of providing information. This is described later in this book.)
  • In the JSP file, use a page directive with errorPage set to the name of a JSP file that will display a message to the user when an exception occurs.
  • Write an error page file, using a page directive with isErrorPage="true".
  • In the error page file, use the exception object to get information about the exception.
  • Use informative messages, either in your error page file or included from other files, to give your user an informative message relevant to what he or she was doing when the exception was thrown.

An Email Address Finder Example

This example, named email, stores names and email addresses in a map file based on the java.util.TreeMap class defined in the JDK 1.2. The TreeMap class creates a data structure called a red-black tree. In the tree, data is stored with a key and a value. In this example, the name is the key and the email address is the value.

When you add an entry to the map file, you enter both a name (the key) and an email address (the value). You can look up or delete an email address by entering just a name. The name cannot be null because it is a key. If a user tries to enter a null name, the application throws an exception and displays an error page.

So What's a Red-Black Tree?

For those of you who are curious about algorithms, a red-black tree is an extended binary tree that looks something like this (conceptually, at least):

If you are viewing this document online, you will see that some nodes are red and some are black. If you are viewing this document in print, the red nodes look a shade or two lighter than the black.

The red-black tree has nodes that are either leaf nodes or branch nodes. Leaf nodes are the small nodes at the end of a line, while branch nodes are the larger nodes that connect two or more lines. Data is stored in a balanced structure in the tree, using the following conditions:

  • Every node has two children or is a leaf.
  • Every node is colored red or black.
  • Every leaf node is colored black.
  • If a node is red, then both of its children are black.
  • Every path from the root to a leaf contains the same number of black nodes.

If you want more detail on how a tree map works, you can find it in Introduction to Algorithms by Corman, Leiserson, and Rivest. The advantage of a tree map for you, the Web developer, is that you can create a map file that stores data in ascending order (sorted by keys) and that has fast search times.

How the Example Is Structured

The email example has three pages with HTML forms, two response files, one error page, and one JavaBeans component. You can visualize the file structure as something like this:

  • Map.java is a JavaBeans component that creates the map file.
  • email.jsp is a JSP page that displays a form where the user enters a name and email address.
  • lookup.jsp is a JSP page that lets a user search for an email address that matches a name.
  • lookupresponse.jsp is included in lookup.jsp and displays the entry the user wants to look up.
  • delete.jsp is a JSP page that lets the user delete an email address that matches a name.
  • deleteresponse.jsp is included in delete.jsp and displays the entry that was deleted from the map file.
  • error.jsp is an error page that displays information about handling exceptions that occur while adding, looking up, or deleting entries in the map file.

The sample code for email is shown in CODE EXAMPLE 0-1 through CODE EXAMPLE 0-7, along with miniature versions of its screens. You may want to install and run the example while you look at the sample code. The instructions are in "How To Run the Example" at the end of this tutorial.

Adding a Name and Email Address (email.jsp)

<%@ include file="copyright.html" %>

<%@ page isThreadSafe="false" import="java.util.*, email.Map"
	errorPage="error.jsp" %>

<jsp:useBean id="mymap" scope="session" class="email.Map" />
<jsp:setProperty name="mymap" property="name" param="name" />
<jsp:setProperty name="mymap" property="email" param="email" />

<% mymap.setAction( "add" );  %>

<html>

<head><title>Email Finder</title></head>
<body bgcolor="#ffffff" background="background.gif" link="#000099">

<!-- the form table -->

<form method="get">
<table border="0" cellspacing="0" cellpadding="5">

<tr>
<td width="120"> &nbsp; </td>
<td align="right"> <h1>Email Finder</h1> </td>
</tr>

<tr>
<td width="120" align="right"><b>Name</b></td>
<td align="left"><input type="text" name="name" size="35"></td>
</tr>

<tr>
<td width="120" align="right"><b>Email Address</b></td>
<td align="left"><input type="text" name="email" size="35"></td>
</tr>

<tr>
<td width="120"> &nbsp; </td>
<td align="right">
Please enter a name and an email address.
</td>
</tr>

<tr>
<td width="120"> &nbsp; </td>
<td align="right">
<input type="submit" value="Add">
</td>
</tr>

<!-- here we call the put method to add the 
          name and email address to the map file -->

<%
	String rname = request.getParameter( "name" );
	String remail = request.getParameter( "email" );
	if ( rname != null) {
		mymap.put( rname, remail );
	} 
%>

<tr>
<td width="120"> &nbsp; </td>
<td align="right">
The map file has <font color="blue"><%= mymap.size() %>
</font> entries.
</font>
</td>
</tr>

<tr>
<td width="120"> &nbsp; </td>
<td align="right">
<a href="lookup.jsp">Lookup</a>&nbsp; | &nbsp;
	<a href="delete.jsp">Delete</a>
</td>
</tr>

</table>
</form>

</body>
</html>
 


Looking Up a Name in the Map File (lookup.jsp)

<%@ include file="copyright.html" %> <%@ page isThreadSafe="false" import="java.util.*, email.Map" errorPage="error.jsp" %> <jsp:useBean id="mymap" scope="session" class="email.Map" /> <jsp:setProperty name="mymap" property="name" param="name" /> <% mymap.setAction( "lookup" ); %> <html> <head><title> Email Finder </title></head> <body bgcolor="#ffffff" background="background.gif" link="#000099"> <form method="get"> <table border="0" cellspacing="0" cellpadding="5"> <tr> <td width="120"> &nbsp; </td> <td align="right"> <h1>Email Finder</h1> </td> </tr> <tr> <td width="120" align="right"><b>Name</b></td> <td align="left"><input type="text" name="name" size="35"></td> </tr> <tr> <td width="120"> &nbsp; </td> <td align="right"> Please enter a name for which <br> you'd like an email address. </td> </tr> <tr> <td width="120"> &nbsp; </td> <td align="right"> The map file has <font color="blue"> <%= mymap.size() %></font> entries. </td> </tr> <tr> <td width="120"> &nbsp; </td> <td align="right"> <input type="submit" value="Lookup"> </td> </tr> <% if ( request.getParameter( "name" ) != null ) { %> <%@ include file="lookupresponse.jsp" %> <% } %> <tr> <td width="120"> &nbsp; </td> <td align="right"> <a href="email.jsp">Add</a> &nbsp; | &nbsp; <a href="delete.jsp">Delete</a> </td> </tr> </table> </body> </html>

Displaying the Lookup Response (lookupresponse.jsp)

<%@ page import="java.util.*, email.Map" %> <tr> <td width="120"> &nbsp; </td> <td align="right"> <b> Success! </b> </td> </tr> <tr> <td width="120"> &nbsp; </td> <td align="right"> <jsp:getProperty name="mymap" property="name" /> <br> <jsp:getProperty name="mymap" property="email" /> </td> </tr>

Deleting an Email Address (delete.jsp)


<%@ include file="copyright.html" %> <%@ page isThreadSafe="false" import="java.util.*, email.Map" errorPage="error.jsp" %> <jsp:useBean id="mymap" scope="session" class="email.Map" /> <jsp:setProperty name="mymap" property="name" param="name" /> <!-- tags the JSP page so that we can display the right exception message later --> <% mymap.setAction( "delete" ); %> <html> <head><title> Email Finder </title></head> <body bgcolor="#ffffff" background="background.gif" link="#000099"> <form method="get"> <table border="0" cellspacing="0" cellpadding="5"> <tr> <td width="120"> &nbsp; </td> <td align="right"> <h1>Email Finder</h1> </td> </tr> <tr> <td width="120" align="right"><b>Name</b></td> <td align="left"> <input type="text" name="name" size="35"> </td> </tr> <tr> <td width="120"> &nbsp; </td> <td align="right"> Please enter a name you would like to delete. </td> </tr> <tr> <td width="120"> &nbsp; </td> <td align="right"> The map file has <font color="blue"> <%= mymap.size() %></font> entries. </td> </tr> <tr> <td width="120"> &nbsp; </td> <td align="right"> <input type="submit" value="Delete"> </td> </tr> <!-- display the name and email address, then delete them from the map file --> <% if ( request.getParameter( "name" ) != null ) { %> <%@ include file="deleteresponse.jsp" %> <% mymap.remove( request.getParameter("name") ) ; } %> <tr> <td width="120"> &nbsp; </td> <td align="right"> <a href="email.jsp">Add</a> &nbsp; | &nbsp; <a href="lookup.jsp">Lookup</a> </td> </tr> </table> </body> </html>

Displaying the Delete Response (deleteresponse.jsp)

<%@ page import="java.util.*, email.Map" %> <tr> <td width="120"> &nbsp; </td> <td align="right"> <b>Success!</b> </td> </tr> <tr> <td width="120"> &nbsp; </td> <td align="right"> <jsp:getProperty name="mymap" property="name" /> <br> <jsp:getProperty name="mymap" property="email" /> <br><p> has been deleted from the map file. </td> </tr>

Displaying Exception Messages (error.jsp)

<%@ include file="copyright.html" %> <%@ page isErrorPage="true" import="java.util.*, email.Map" %> <jsp:useBean id="mymap" scope="session" class="email.Map" /> <html> <head><title>Email Finder</title></head> <body bgcolor="#ffffff" background="background.gif" link="#000099"> <table border="0" cellspacing="0" cellpadding="5"> <tr> <td width="150" align="right"> &nbsp; </td> <td align="right" valign="bottom"> <h1> Email Finder </h1> </td> </tr> <tr> <td width="150" align="right"> &nbsp; </td> <td align="right"> <b>Oops! an exception occurred.</b> </td> </tr> <tr> <td width="150" align="right"> &nbsp; </td> <td align="right">The name of the exception is <%= exception.toString() %>. </td> </tr> <tr> <td width="150" align="right"> &nbsp; </td> <td align="right"> &nbsp; </td> </tr> <% if (mymap.getAction() == "delete" ) { %> <tr> <td width=150 align=right> &nbsp; </td> <td align=right> <b>This means that ...</b> <p>The entry you were trying to <font color="blue">delete</font> is not in the map file <br> <b><i>or</i></b> <br> you did not enter a name to delete. <p> Want to try <a href="delete.jsp">again</a>? </td> </tr> <% } else if (mymap.getAction() == "lookup" ) { %> <tr> <td width="150" align="right"> &nbsp; </td> <td align="right"> <b><i>This means that ...</b></i> <p>the entry you were trying to <font color="blue">look up</font> is not in the map file, <b><i>or</i></b> <br> you did not enter a name to look up. <p> Want to try <a href="lookup.jsp">again</a>? </td> </tr> <% } else if (mymap.getAction() == "add" ) { %> <tr> <td width="150" align="right"> &nbsp; </td> <td align="right"> <b><i>This means that ...</b></i> <p>You were trying to <font color="blue">add</font> an entry with a name of null. <br> The map file doesn't allow this. <p> Want to try <a href="email.jsp">again</a>? </td> </tr> <% } %> </table>

Creating the Map File (Map.java)

package email; import java.util.*; public class Map extends TreeMap { // In this treemap, name is the key and email is the value private String name, email, action; private int count = 0; public Map() { } public void setName( String formName ) { if ( formName != "" ) { name = formName; } } public String getName() return name; } public void setEmail( String formEmail ) { if ( formEmail != "" ) { email = formEmail; System.out.println( name ); // for debugging only System.out.println( email ); // for debugging only } } public String getEmail() { email = get(name).toString(); return email; } public void setAction( String pageAction ) { action = pageAction; } public String getAction() { return action; } }


Handling Exceptions in the Bean

In this example, the code that throws exceptions is in the TreeMap class, which our email.Map Bean extends, so we won't need to write code that throws exceptions in the Bean.

The methods that we use from TreeMap are shown below, with their exceptions:

  • public Object get( Object key )throws ClassCastException, NullPointerException- retrieves an entry from the map file
  • public Object put( Object key, Object value )throws ClassCastException, NullPointerException- adds an entry to the map file
  • public Object remove( Object key )throws ClassCastException, NullPointerException- removes an entry from the map file
  • int size()- returns the number of entries in the map file

Of course, if you need more information about these methods, you can find it in the Javadoc API reference for java.util.TreeMap.

The TreeMap class throws a ClassCastException when the user tries to enter data of the wrong type in the map file, for example, an int where the map file is expecting a String. Keep in mind that the TreeMap class is also used with Java client applications. In our JSP application, this exception won't occur, because the user enters a name and an email address in an HTML form, which always passes data as strings to the Bean. Even if the user typed 6 as a name, the value is still sent as a String.

However, the get, put, and remove methods throw a NullPointerException if the user enters nothing and a null value is passed to the Bean. This is the most common exception that the email application needs to handle. This exception might occur while your user is trying to add, look up, or remove an entry from the map file. Remember that the key (in this case, the name) cannot be null.

When the User Tries to Add a Null Value

The first case, where the user attempts to add a null name or email address, is handled by some simple code in the Bean and in email.jsp. (Here null means the user has entered nothing in the form text box. It does not handle the case where the user enters one or more blank spaces, then presses Return.)

The code that handles adding null values is in the setName and setEmail methods of Map.java and in a scriptlet in email.jsp (CODE EXAMPLE 0-8):

Catching a Null Value on Add
Map.java:

public void setName( String formName ) {
	if ( formName != "" ) {
		name = formName; 	 
	}
}
public void setEmail( String formEmail ) {
	if ( formEmail != "" ) {	 
		email = formEmail;	
		System.out.println( name );	    // for debugging only
		System.out.println( email ); 	  // for debugging only 	 
	}	
}

email.jsp:

<%
	String rname = request.getParameter( "name" );
	String remail = request.getParameter( "email" );
	if ( rname != null) {
		mymap.put( rname, remail );
	}
%>

Both setName and setEmail check whether the user has entered a null value in the form before setting their respective properties. If the form value is null, the Bean does not set a property, the put method does not add a value to the map file, and no exception is thrown.

When the User Tries to Look Up a Null Value

But if you go to the Lookup or Delete page of the example and try to look up or delete an entry that isn't in the map file at all, the email application throws a NullPointerException and displays the error page. The code that handles looking up null values is shown in CODE EXAMPLE 0-9.

Catching a Null Value on Look Up
lookup.jsp:

<%  if ( request.getParameter( "name" ) != null ) {  %>
	  <%@ include file="lookupresponse.jsp" %>
<%  }  %>

lookupresponse.jsp:

<tr>
<td width="120"> &nbsp; </td>
<td align="right">
<font face="helvetica" size="-2">
<jsp:getProperty name="mymap" property="name" />
<br>
<jsp:getProperty name="mymap" property="email" />
</font>
</td>
</tr>

This example has two pieces of code that work together. The page lookup.jsp, where you enter a name you want to look up in the map file, has a scriptlet that checks whether or not the user has entered a name in the form. If the user doesn't enter a name, or enters a name that doesn't exist in the map file, the Bean throws a NullPointerException and the application displays the error page-which is the desired behavior! In this case, you can be happy that the error page is displayed.

You may have noticed that the lines from lookupresponse.jsp use the <jsp:getProperty> tag to retrieve the name and email address from the Bean. You could also try to retrieve the email address using expressions, something like this:

<%= request.getParameter( "name" ) %>
<br>
<%= mymap.get( request.getParameter( "name" ) ) %>

If you use these lines, the application would behave a little differently. Rather than throwing a NullPointerException and displaying an error page, it would display the name the user entered, with the word null below it in the JSP page. In Sun's JSP reference implementation, the <jsp:getProperty> tag intentionally handles null values differently than scriptlets or expressions. The way null values are handled will vary according to the JSP engine you use.

When the User Tries to Delete a Null Value

Handling the case of a user trying to delete a null value is very similar to handling the lookup of a null value. The code that handles null values that occur while you are trying to delete an entry is shown in CODE EXAMPLE 0-10.

Catching a Null Value on Delete
delete.jsp:

<% if ( request.getParameter( "name" ) != null ) {  %>
		  <%@ include file="deleteresponse.jsp" %>
<%
		mymap.remove( request.getParameter("name") ) ;
	} 
%>

deleteresponse.jsp:

<tr>
<td width="120"> &nbsp; </td>
<td align="right"> 
<font face="helvetica" size="-2"> 
<jsp:getProperty name="mymap" property="name" />
<br>
<jsp:getProperty name="mymap" property="email" />
<br><p>
has been deleted from the map file.
</font> 
</td>
</tr>

Calling an Error Page From Another Page

To link the display pages to the error page, each display page in the email application uses a page directive with the errorPage attribute, like this:

<%@ page isThreadSafe="false" import="java.util.*, email.Map"
	errorPage="error.jsp" %>

In the code examples, the files that use this directive are email.jsp, lookup.jsp, and delete.jsp. You can only specify one error page for each JSP page.

This means that you can design a JSP application so that each JSP page calls a different error page, or so that several JSP pages call one error page. In the email application, several JSP pages call one error page, as it simplifies the number of files you need to maintain for one application. In designing your applications, the choice is up to you.

You should always use at least one error page in a JSP application. If you don't specify an error page, the exception message and stack trace are displayed in the command window from which the JSP engine was started, while the Web browser displays a non-informative HTTP error message, for example, a 404 or 501 message. This is definitely not a graceful way to handle exceptions.

Writing an Error Page

An error page is different from an ordinary JSP page. In an error page, you must explicitly set the isErrorPage attribute of the page directive to true. You also have access to the exception object, which gives you information about the exception.

First, let's look at an example of the page directive for an error page:

<%@ page isErrorPage="true" import="java.util.*, email.Map" %>

Once you have set isErrorPage to true, you can use the exception object. exception is of type java.lang.Throwable, so you can use any of the methods defined in Throwable with exception in a scriptlet or expression, for example:

  • <%= exception.toString() %>
  • <% exception.printStackTrace(); %>

The expression exception.toString() displays the exception's class name, for example, java.lang.NullPointerException, while exception.printStackTrace() displays the exception's stack trace. The class name and stack trace are probably very helpful to you the developer, but probably not very helpful to your user. To get around this, you may want to write some type of tracking mechanism to provide information that helps you give an informative message to your user.

Writing a Simple Tracking Mechanism

The email example uses a property named action in Map.java to track which page the user was working in when the exception was thrown. That gives you valuable information to help you write an informative error message for your user. The Bean has a variable named action, a getAction method, and a setAction method. The variable and method declarations in the Bean look like this:

private String action;

public void setAction( String pageAction ) {
	action = pageAction; 	 	
}

public String getAction() {
	return action;	
}

Each of the pages email.jsp, lookup.jsp, and delete.jsp sets the value of action with a line like this one (which comes from email.jsp):

<% mymap.setAction( "add" ); %>

If an exception occurs, error.jsp checks the value of action and includes an appropriate message for each value, using lines like these:

<% if (mymap.getAction() == "delete" ) {  %>
.. text message here ..
else if (mymap.getAction() == "lookup" ) { %>
.. text message here ..
else if (mymap.getAction() == "add" ) { %>
.. text message here ..
<%  }  %>

Of course, this is a very simple way to implement tracking. If you move into developing J2EE applications with enterprise beans, you can write applications that save state. That is more advanced and is discussed later in this book.

How To Run the Example

In order to run this example, you need to have already installed the JDK 1.2 (if you haven't done so, see http://java.sun.com/products/OV_jdkProduct.html.)

The pathnames given here are for UNIX systems. If you are using Windows, use the same pathnames, with the path separators reversed.


1


Create the directory (or folder) ../jswdk-1.0/examples/jsp/tutorial/email.


2


Place the following files in the ../tutorial/email directory: background.gif, delete.jsp, deleteresponse.jsp, email.jsp, error.jsp, lookup.jsp, lookupresponse.jsp.


3


Create the directory (or folder) ../jswdk-1.0/examples/WEB-INF/jsp/beans/email.


4


Place the files Map.class and Map.java in the ../beans/email directory.


5


Start the Sun JSP reference implementation: cd ../jswdk-1.0startserver


6


Open a Web browser and go to http://yourMachineName:8080/examples/jsp/tutorial/email/email.jsp


[Top] [Prev] [Next] [Bottom]

Copyright © 1999, Sun Microsystems, Inc. All rights reserved.