ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

An Exception Handling Framework for J2EE Applications
Pages: 1, 2, 3, 4, 5, 6

Let's say you get searchDivision as the actionMethod from an HTTP request: dispatchMethod will dispatch the request to a searchDivision method in the derived Action class of BaseAppDispatchAction. Here, you can see that exception handling is done only in the base class, and the derived class just implements Action methods. It confirms to the Template Method design pattern, where the exception-handling part remains invariant while the actual implementation (the varied part) of dispatchMethod is deferred to the derived class.

The modified Struts Action method mentioned earlier will look something like this after the above changes.

 
... 
String exceptionActionForward = 
    "SearchAdjustmentPage"; 
String exceptionContext = 
    "divisionAction.searchDivision"; 
        
ExceptionDisplayDTO expDTO = 
    new ExceptionDisplayDTO(expActionForward, 
        exceptionContext); 
expDisplayDetails.set(expDTO); 
... 
DivisionDTO divisionDTO =divisionBusinessDelegate 
   .getDivisionByNum(fromDivisionNum); 
...

Wow! Now it looks clean. As exception handling is being done in one centralized place (BaseAppDispatchAction), the scope of manual errors is also minimized.

However, we need to set the exception context and the name of the ActionForward to which the requests will be forwarded if there's an exception. And we are setting this in a ThreadLocal variable, expDisplayDetails.

Hmm. Fine. But why a java.lang.ThreadLocal variable? The expDisplayDetails is a protected data member in the BaseAppDispatchActiion class, and that's why it needs to be thread-safe too. The java.lang.ThreadLocal object comes to the rescue here.

Exception Handler

We talked about an abstraction for handling exceptions in the last section. Here is the contract it should satisfy.

  • Identify the type of exception and get the corresponding error code, which could be used to display a message to the end user.
  • Log the exception. The underlying logging mechanism is hidden and could be configured based on some environmental properties.

As you might have noticed, the only exception we are catching in the presentation layer is BaseAppException. As all checked exceptions are subclasses of BaseAppException, implicitly, we are catching all of the derived classes of BaseAppException. It's fairly easy to identify the error code based on the name of the class.

//exp is an object of BaseAppException
String className = exp.getClass().getName();

Error codes can be configured in an XML file (named exceptioninfo.xml) based on the name of the exception class. Here is a sample of exception configuration.

<exception name="EmployeeConfirmationException">
    <messagecode>messagecode.laborconfirmation</messagecode>
    <confirmationind>true</confirmationind>
    <loggingtype>nologging</loggingtype>
</exception>

As you can see, we are making it fairly explicit that for this exception, the message code to be used is messagecode.employeeconfirmation. The real message can then be extracted from a ResourceBundle for internationalization purposes. We are also making it very clear that we don't need to perform logging for this type of exception, as it's just a confirmation message and not an application error.

Let's look at an example of a context-sensitive exception:

<exception name="RecordNotFoundException">
    <messagecode>messagecode.recordnotfound</messagecode>
    <confirmationind>false</confirmationind>
    <contextind>true</contextind>
    <loggingtype>error</loggingtype>
</exception>

Here, contextind is true for this exception. The context you passed in handleException method can be used to make a unique error code. For instance, if we passed order.getOrder as a context, the resultant message code will be a concatenation of the exception's message code and the context passed. Hence, we get a unique message code like messagecode.recordnotfound.order.getOrder.

Pages: 1, 2, 3, 4, 5, 6

Next Pagearrow