Before we leave the topic of exception handling, there are several special cases that we should discuss. Each one of these is unique, and you may or may not need them in your applications.
Remote Java objects are allowed to throw instances of java.rmi.RemoteException. In fact, every EJB method that is exposed to a remote client must declare that it throws RemoteException. Dealing with RemoteExceptions is very similar to handling system exceptions except that they are not descendants of either java.lang.Error or java.lang.RuntimeException.
Often, the application will not be able to recover from a RemoteException and will have to display the system error page. If you're using EJB and you get a RemoteException, you can attempt to recover by acquiring a new remote reference, but there's probably some type of programming or environment error that will prevent the end user from continuing. Whether you're using a programmatic or a declarative approach, you'll likely want to log the exception, create and store an ActionError object, and then forward to the system error page. You can also define the exception-handling behavior to forward the user back to the previous page and give her the choice of trying again. If some type of network blip caused the remote exception, it may be possible for the user to continue to use the application.
JSP custom tags usually throw JSPException objects or one of their descendants. Prior to the JavaServer Pages 1.2 specification, the JSPException class didn't support exception chaining, and because Struts was introduced before the 1.2 specification, several places inside the Struts custom tag libraries still disregard the original exception when a JSPException is created.
However, the Struts tags do usually store the exception in the request scope under the key Action.EXCEPTION_KEY, which maps to a literal string of org.apache.struts.action.Action.EXCEPTION_KEY. If you need to get access to the root cause, you can probably use this key to retrieve the exception object.
Version 1.2 of the JSP specification modified the JSPException to support exception chaining; however, the Struts developers will probably choose to leave the current tags alone for backward compatibility and will take advantage of this new functionality only for future tags. However, in the custom tags that you create, you should use the rootCause field in the JSPException class when you rethrow exceptions as different types.
The JSP 1.2 specification also introduced a new interface called TryCatchFinally. This interface, which is referred to as a "mix-in" interface, can be implemented by a tag handler in addition to one of the other tag interfaces.
The TryCatchFinally interface provides two methods:
public void doCatch(Throwable);
public void doFinally( );
The container calls the doCatch( ) method if the tag body or one of the doStartEnd( ), doEndTag( ), doInitBody( ), or doAfterBody( ) methods throws a Throwable. The doCatch( ) method can rethrow the same or a different exception after handling the error.
The container calls the doFinally( ) method after the doEndTag( ) or after the doCatch( ) method when an exception condition occurs.
The TryCatchFinally interface allows for better exception handling in custom tags. It is very important to allow limited resources that are being used by custom tags to be released. Without this interface, there's no guarantee that the container will provide the tag with an opportunity to release the resources being used by the tags.
Chapter 12 covers internationalization in detail, but it's relevant to say a few words here about how exception handling and internationalization are connected. While throwing exceptions in Java, developers often do something like the following:
// Detect some problem and throw an exception
throw new InvalidLoginException( "An exception has occurred." );
The problem with hardcoding the string into the exception is that it's useful only for developers from the same locale. It might be difficult for developers or system administrators from different locales to use the log files where these exceptions are logged. Instead of hardcoding the messages for the exceptions, it may be better to get the message from a resource bundle. Obviously, exceptions that are thrown from third-party packages are not within your control, just as stack traces are hard to localize. Many organizations don't worry about localizing the exception messages, which is fine as long as no one from locales other than your own will ever need to use the information.