Recipe9.3.Using Exception Error Codes


Recipe 9.3. Using Exception Error Codes

Problem

You want to use an exception class that accepts a logical error code or key and optional arguments that can be used to display a localized error message.

Solution

Use or extend my ErrorCodeException, shown in Example 9-6.

Example 9-6. Exception that accepts a numeric error code
package com.oreilly.strutsckbk.ch09; public class ErrorCodeException extends Exception {          public ErrorCodeException(int code) {         this.code = code;     }     public ErrorCodeException(int code, Object[] args) {         this.code = code;         this.args = args;     }     public ErrorCodeException(int code, Object[] args, String msg) {         super(msg);         this.code = code;         this.args = args;     }     public ErrorCodeException(int code, Object[] args, String msg,                                                    Throwable cause) {         super(msg, cause);         this.code = code;         this.args = args;     }     public int getCode( ) {         return code;     }     public Object[] getArgs( ) {         return args;     }     private Object[] args;     private int code; }

Use my ErrorCodeExceptionHandler, shown in Example 9-7, to handle these exception types.

Example 9-7. Exception handler for the ErrorCodeException
package com.oreilly.strutsckbk.ch09; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.Globals; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ExceptionHandler; import org.apache.struts.config.ExceptionConfig; public class ErrorCodeExceptionHandler extends ExceptionHandler {     public ActionForward execute(             Exception ex,             ExceptionConfig ae,             ActionMapping mapping,             ActionForm formInstance,             HttpServletRequest request,             HttpServletResponse response)             throws ServletException {                  if (!(ex instanceof ErrorCodeException)) {             return super.execute(ex, ae, mapping, formInstance, request,              response);         }                  ErrorCodeException errCodeEx =(ErrorCodeException) ex;         ActionForward forward = null;         ActionMessage error = null;         String property = null;         // Build the forward from the exception mapping if it exists         // or from the form input         if (ae.getPath( ) != null) {             forward = new ActionForward(ae.getPath( ));         } else {             forward = mapping.getInputForward( );         }         ErrorCodeException ece =(ErrorCodeException) ex;         String code = Integer.toString(ece.getCode( ));         error = new ActionMessage(code, ece.getArgs( ));         property = error.getKey( );         logException(ex);         // Store the exception         request.setAttribute(Globals.EXCEPTION_KEY, ex);         storeException(request, property, error, forward, ae.getScope( ));         return forward;     } }

Finally, declare a global exception handler in your struts-config.xml for this exception:

<global-exceptions>     ...     <exception key="error.exception"                type="com.oreilly.strutsckbk.ch09.ErrorCodeException"            handler="com.oreilly.strutsckbk.ch09.ErrorCodeExceptionHandler"                path="/error_page.jsp"/> </global-exceptions>

Discussion

A lot of large software applications report problems using error codes as well as text. The Oracle database reports errors using an error code formatted as ORA-9999. You can use an Oracle utility program to retrieve the meaning of the error code. This approach allows the application to localize text messages based on the user's language and country. The ErrorCodeException shown in Example 9-6 can be used in a similar manner in your Struts application. You create this exception class using a numeric error code and an optional set of Object arguments. The error code serves as a key for retrieving a localized message from your MessageResources properties file. The arguments are used at runtime as substitution parameters in that message.

When an Action or business service creates an ErrorCodeException, it can populate the exception with an appropriate error code and an array of arguments for message substitution. The ErrorCodeExceptionHandler shown in Example 9-7 is designed to process ErrorCodeExceptions. The code in the execute( ) method was originally copied from the Struts base ExceptionHandler (org.apache.struts.action.ExceptionHandler) and modified as needed. This custom handler first checks if the error is of type ErrorCodeException; if not, it allows the Struts exception handler to process the Exception by calling super.execute( ). Otherwise, the exception is handled as follows:

  1. The path to forward to is determined from the ExceptionConfig. If no path is specified, the action's input path is used (accessed using mapping.getInputForward( )).

  2. The error code is retrieved from the ErrorCodeException and converted to a String.

  3. An ActionMessage is created using the error code String and the Object array from the ErrorCodeException.

  4. The exception is logged using the logException( ) method (implemented by the super class).

  5. The exception is added as an attribute to the HttpServletRequest.

  6. The error is stored by calling storeException( ) (implemented by the super class).

  7. The forward is returned.

Only steps 2 and 3 are specific to this handler. The other steps are identical to the handling in the base ExceptionHandler.

Though not required, you can extend the ErrorCodeException class to create exception types for specific functional areas of your application. Using this approach allows you to control exception processing based on type, yet give the benefits provided by using an error code and message arguments.

Exception Handling 101

Use only the type of the exceptionnot its propertiesto drive exception-handling logic in Java code. In other words, you don't want to have try...catch blocks such as the following:

try {     callService(  ); } catch (ErrorCodeException ece) {         // bad code!     switch (ece.getCode( )) {         case -1:             return               mapping.findForward("somewhere.jsp");         case 100:             // do something         case 110:             // do something else     }     throw ece; }

Using the properties of an exception to control the flow of your application can cause serious performance problems. When an exception occurs, the Java Virtual Machine must wait on any method called in the try block to complete before control is yielded to the catch block, essentially forcing synchronization of these methods. A better approach is to subclass the ErrorCodeException and use a catch block for each type.


If you have an existing application that relies heavily on predefined error codes, this Solution can help bridge the gap with exception handling. The error codes and corresponding error messages can be defined in your application's default MessageResources file, or they can be stored in their own properties file. Since you are coding the exception handler, you can do it how you want.

The ErrorCodeException and corresponding handler are useful if you need to localize the generated message in support of internationalization. Since the exception handler uses MessageResources, the message can be localized by creating a properties file for specific locales.

See Also

Best practices for localizing exceptions have been discussed a number of times on the struts-user mailing list. You'll find the thread at http://marc.theaimsgroup.com/?l=struts-user&m=109474569119868&w=2 to be particularly interesting.

Creating a custom exception handler is easier than you think. See Recipe 9.2 for details.



    Jakarta Struts Cookbook
    Jakarta Struts Cookbook
    ISBN: 059600771X
    EAN: 2147483647
    Year: 2005
    Pages: 200

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net