| By Dan Stieglitz | Article Rating: |
|
| August 10, 2005 11:00 AM EDT | Reads: |
19,870 |
Aspect-Oriented Programming (AOP) is a new, thought-provoking architecture paradigm still in its youth. One of AOP's primary goals is to improve the development of object-oriented systems by refactoring related lines of code that are typically found spread among classes (and are therefore difficult to maintain).
These blocks of related code represent functional "aspects" of the system, which now can be written in a single place and then "woven" into the target application. Logging the start and end of all method calls, securing method calls, and handling thrown exceptions are all commonly found aspects. While AOP provides an interesting and effective methodology for refactoring aspects out of code, how to implement these aspects is still left up to the developer. This article discusses a strategy for building a more easily maintainable, compartmentalized exception handing subsystem using a declarative chain of responsibility pattern and some concepts from aspect-oriented development. Many of the concepts discussed here have been implemented in an open source project called "Prob-lo-Matic" (http://problomatic.sourceforge.net).
As a consultant working on a wide spectrum of projects for various companies, I've found that subsystems specifically designed for exception handling (an aspect found in every project) can be strangely rare in the business world. There are few if any vendor products available that are "generic, full-featured exception handling suites." When exception-handling frameworks are home grown, as they often are, they usually contain a lot of difficult logic (causing more problems than they fix). There seems to be a wide variety of monitoring software that act as excellent exception detection and alerting tools but, in practice, few frameworks that provide application developers with structured, robust error-correction tools for use within their software packages.
For simple error handling, such as checking some variables or attempting to access an I/O device, the Java try/catch/finally system works fine. When an error occurs, there is usually no alternative but to handle the low-level exception inline and return some status to the calling stack frame. However, in modern distributed systems, there are more intricate requirements for error handling. Robust applications are required to retry failed steps, notify components of failures, and produce logging statements. First-rate application design demands a generic, pluggable exception-handling framework for our distributed systems. A declarative chain of responsibility pattern can act as the foundation for building such a system, and AOP can give us a powerful non-invasive way to integrate such a system with our code.
Chain of Responsibility (a.k.a. Chain of Command)
The chain of responsibility pattern's intent is to "avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request" (Gamma, et al. Design Patterns). Essentially, a message object is passed through a chain of objects implementing a common interface. The interface includes methods to chain the handler together, i.e., get- and setSuccessor methods:
public interface Handler {
public void handle(Object message);
public void setSuccessor(Handler successor);
public Handler getSuccessor();
}
Implementations of this interface use the successor property to pass the message through the chain, as in:
public class HandlerImplementation {
public void handle(Object message) {
// local handling code here
if (getSuccessor()!=null) {
successor.handle(message);
}
}
}
Handlers are acquired by the application in some fashion (more on that later), and execution is branched to the handle's handle() method. In the case of an exception-handling framework, we wish to construct an object that encapsulates all of the information about the state of our application when an error occurred, as well as information about what to do for specific errors. For example, if we have implemented a handler to retry database calls it's necessary to provide information as to where the secondary database instances are. To do so, it's useful to create an object tree based on a message interface that's understandable by all handlers.
The Problem Interface
An important part of using the chain of responsibility pattern is standardizing the interface of the message passed down the links. If a wrapper around the underlying exception, error or application-generated warning is applied, information can be shared among nodes. An example interface could be:
public interface Problem {
public void setAttribute(String name, Object obj);
public Object getAttribute[(String name);
public boolean hasAttribute(String name);
}
Implementations of Problem could be created for specific recurring situations, such as:
public class DatabaseAccessProblem implements Problem { ... }
public class ProblemInRequestProcessor implements Problem { ... }
public class SecurityProblem implements Problem { ... }
Each specific implementation can store information that allows for some logic to occur. Coupled with a decla-rative handler chain (see below), a framework evolves that allows for robust, extensible generic exception processing subsystems to be designed and quickly adapted to any project.
Declarative Programming and Prob-lo-Matic
Declarative programming refers to the practice of refactoring application logic out of the code and into a reference file. An excellent example of a declarative framework is the Spring Framework (www.springframework.org/), which allows developers to move dependencies out of code and into XML files (the pattern on which the framework is based is called "dependency injection" or "inversion of control"). A declarative approach facilitates quick system maintenance and the ability to "hot swap" features of a deployed application.
Using the inversion of control pattern makes code very flexible and is the method used by Prob-lo-Matic to configure the problem handler chains. Any number of formats could be used to store this information; for example, here is a Prob-lo-Matic configuration file, which is XML (see Listing 1).
Published August 10, 2005 Reads 19,870
Copyright © 2005 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
About Dan Stieglitz
Dan is an independent software consultant in New York. He specializes in designing and developing distributed applications in Java and J2EE.
- Performance of Java Compilers: An Empirical Study
- Java Kicks Ruby on Rails in the Butt
- Ulitzer’s Amazing First 30 Days in Public Beta
- 1st Annual Government IT Expo: Call for Papers Deadline July 15
- REA Is Where RIA Becomes the Norm
- Why an Application Grid?
- Will Ulitzer Dominate News Content on The Web? -Gartner
- Profiling Netbeans within Amazon EC2
- Clear Toolkit 4: The Road Map
- Java Persistence on the Grid: Approaches to Integration
- Performance of Java Compilers: An Empirical Study
- Java Kicks Ruby on Rails in the Butt
- Developing Rich Client Applications Using Swing - II
- The Right Time for Real Time Java
- Xpress Suite Adds Automatic Java to iPhone Conversion
- Building Better Phone Applications with SOA and Eclipse
- Initial Thoughts on IBM Acquisition of Sun Microsystems
- Ulitzer’s Amazing First 30 Days in Public Beta
- 1st Annual Government IT Expo: Call for Papers Deadline July 15
- Maximizing Java Performance with Bespoke Programming
- A Cup of AJAX? Nay, Just Regular Java Please
- Java Developer's Journal Exclusive: 2006 "JDJ Editors' Choice" Awards
- The i-Technology Right Stuff
- JavaServer Faces (JSF) vs Struts
- Rich Internet Applications with Adobe Flex 2 and Java
- Java vs C++ "Shootout" Revisited
- Bean-Managed Persistence Using a Proxy List
- Reporting Made Easy with JasperReports and Hibernate
- What's New in Eclipse?
- Creating a Pet Store Application with JavaServer Faces, Spring, and Hibernate






































