|
Recipe 9.3. Using Exception Error CodesProblemYou 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. SolutionUse or extend my ErrorCodeException, shown in Example 9-6. Example 9-6. Exception that accepts a numeric error codepackage 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 ErrorCodeExceptionpackage 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> DiscussionA 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:
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.
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 AlsoBest 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. |
|