FTP Online
 
 

Make Your Apps Operations Friendly With AOP
Learn how aspect-oriented programming (AOP) lets you add new behaviors to your application without modifying existing code.
by Robert Swarr

Posted March 15, 2004

For This Solution: AspectJ 1.0.6, Jarkarta Tomcat 4.1.x, and Jakarta Commons Logging 1.0.x are required.

All too often, organizations overlook operations management requirements until after applications are deployed. Then it's more difficult to address concerns. As a result, organizations are burdened with hard-to-manage applications.

Imagine this scenario: After completing a new application, the development team moves onto another project. Now you must support what they built, a Web application with numerous Java classes. At first the application runs well. You have more tasks than hours in the day, so you don't examine the new application too closely. Suddenly, it stops processing requests. After a half-hour of unsuccessful diagnostics, you stop and start the server, and, thankfully, the application begins processing requests again. After reviewing the application source code, you realize its logging is poorly designed and coded. You notice that many exception handlers are defined with empty blocks like this:

try {
   // Code that throws Exception
} catch (Exception e) {
   // Ignore Exception
}

Other exception handlers are defined like this:

try {
   // Code that throws Exception
} catch (Exception e) {
  System.out.println("Exception: 
     " e.getMessage()); 
}

The latter example is better because it reports the exception. However, the output could be lost among all the other messages on the console, and it doesn't supply enough information to help diagnose the problem.

You rightfully suspect that the application failure's root cause is an unreported or unnoticed Exception. But what do you do? You don't have the resources to rewrite the application. Fortunately, aspect-oriented programming (AOP) offers an elegant solution to this all-too-common problem. AOP allows you to add crosscutting behaviors such as logging to a Java application without changing the existing code.

What is Aspect-Oriented Programming?
How does AOP let you change an application's behavior without editing source code? The short answer is that the AOP implementations combine aspects and existing code to add new behavior to an application. They include a software component that weaves aspects and application code into an executable that embodies the behaviors defined in the aspects. Either a compiler or classloader can perform this weaver function. Different implementations interlace aspects and application code in different ways, which I'll discuss in the next section.

AOP is a programming technique that modularizes concerns (areas of interest or requirements) that cut across a system and are common to many modules. These modules, called aspects, associate pointcuts and advices. Pointcuts identify joinpoints, which are well-defined points in the flow of execution such as a method call or data variable access. Advices, which are associated with specific pointcuts, specify the code to execute at a joinpoint. Put another way, a pointcut declares an event and an advice declares an action to be performed when an event fires (see Table 1).

The problem with crosscutting concerns such as logging is that they are tangled with the application's core concern and scattered over many modules, whether it's credit card processing, online insurance, or whatever. The result: applications that are harder to develop and maintain. AOP provides a mechanism to modularize these crosscutting concerns.

AOP Implementations
Two open-source AOP projects are available for download: AspectJ and JBossAOP (see Resources). These two products implement AOP differently, but they both weave crosscutting behavior into a plain old Java object (POJO).

AspectJ
Xerox Palo Alto Research Center (PARC) decided to create a general-purpose AOP language and developed AspectJ over a six-year period. In December 2002, PARC transferred control of AspectJ to the Eclipse project to encourage growth of the AspectJ technology and community.

Available at the Eclipse Web site, the AspectJ download includes the AspectJ Compiler, an aspect browser, Ant tasks, and documentation. The AspectJ Browser provides a point-and-click interface to compile the Java classes and aspects you've defined to a build configuration. It compiles Java classes and aspects using the ajc compiler, which contains a weaver that interleaves the pointcuts and advices in the aspect with the Java classes.

AspectJ generates classfiles that can run on any Java virtual machine. It also supports several Integrated Development Environments (IDEs): Eclipse, Borland JBuilder, and SunOne Studio 4/NetBeans. All code and documentation is available under the Mozilla license, and the Ant tasks are released under the Apache license. In short, you can download everything you need to equip a professional development environment.

Aspects are defined in a file that looks much like a Java class. The LogPoints aspect, for example, outputs a Jakarta Commons log entry before and after any class's init() and doGet() methods, thereby exposing the lifecycle of any running servlet. The aspect file uses an aspect rather than a class identifier, but in all other ways it resembles a Java class. It contains an import statement for the Jakarta Commons Logging classes and a block of code with the advices and pointcuts enclosed within familiar curly braces:

// LogPoints Aspect
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; 

aspect LogPoints {
      private static Log log = 
      LogFactory.getLog(EntryExitPoint.class);
      before(): call(public  *  init(..)) { 
	    log.info("Enter: " + thisJoinPoint);
      }
      after(): call(public * init(..)) {
            log.info("Exit: " + thisJoinPoint);
      }	
      before(): call(public  *  doGet(..)) { 
            log.info("Enter: " + thisJoinPoint);
      }
      after(): call(public * doGet(..)) {
            log.info("Exit: " + thisJoinPoint);
      }
}

Compiling and running this aspect in Jakarta Tomcat 4 together with the HelloWorldServlet class (see Listing 1) results in these log entries:

2004-02-28 13:46:56,574 INFO  EntryExitPoint : 
Enter: call(void HelloWorldServlet.
   init(ServletConfig))
2004-02-28 13:46:56,574 INFO  EntryExitPoint : 
Exit: call(void HelloWorldServlet.
   init(ServletConfig))
2004-02-28 13:46:56,574 INFO  EntryExitPoint : 
Enter: call(void HelloWorldServlet.doGet
   (HttpServletRequest, HttpServletResponse))
2004-02-28 13:46:56,589 INFO  EntryExitPoint : 
Exit: call(void HelloWorldServlet.doGet
   (HttpServletRequest, HttpServletResponse))

The important point is that even if there were 20 servlets executing, this aspect would output the same type of log entry for each one. This simple example shows you how it's possible to define a logging interface within a single module that cuts across an entire system.

JBossAOP
JBoss, creator of one of the most advanced J2EE servers in the industry, also developed an AOP interface for the JBoss server. JBossAOP works in a fundamentally different way from AspectJ. JBossAOP performs code weaving in the classloader rather than the compiler. Also, aspects are defined in XML files rather than Java-like files.

The JBoss server configures aspects like other software components. It uses a Java Management Extensions (JMX) MBean (see "Improve Application Management With JMX") to load aspects, which you can hot-deploy by dropping a file with the signature *-aop.xml into the server's deploy directory. You can use JBossAOP outside the JBoss server, but you must use it with the JBossAOP classloader.

In JBossAOP, advices and pointcuts are declared in an XML file placed in the JBoss server's deploy directory. Here's an example of a JBossAOP advice, called an interceptor, and a method pointcut. Note that the pointcut refers to the name of the interceptor. The interceptor logic executes whenever a get() method in MyClass is called:

<aop>
   <interceptor name="Logging" 
      class="LoggingInterceptor">
   </interceptor>

   <method-pointcut class="MyClass"
      methodName="get.*">
       <interceptors>
         <interceptor-ref name="Logging"/>
       </interceptors>
   </method-pointcut>
</aop>

The declaration in the XML file names a Java class, which implements the JBossAOP Interceptor interface. The logic, which executes when the pointcut is triggered, is placed into the invoke() method:

// LoggingInterceptor class
public class LoggingInterceptor 
   implements Interceptor {

   public String getName() { };

   public InvocationResponse invoke
     (Invocation invocation)
      throws Throwable { 
   }
}

The JBossAOP example demonstrates a different approach to AOP. But in the next section, I'll use AspectJ to develop a solution to the problem I brought up at the beginning of this article.

Add an Aspect to a Java Application
You can use AOP to define a crosscutting behavior and solve the problem of poor logging design. You can add to the application the new behavior: logging information about Exceptions. The logging statements in the aspect use the Jakarta Common logging interface:

  1. Define an exception handler pointcut.
    You can define either named or anonymous pointcuts. The previous section's LogPoints aspect used anonymous pointcuts. This example uses a named pointcut:

        pointcut exceptionHandler(Exception e): 
           handler(Exception+) && args(e);

    The pointcut's name follows the pointcut keyword. The pointcut identifier is the handler(Exception+) part of the declaration. This pointcut specifies a joinpoint of the invocation of any exception handler for Exception or any of its subclasses. This definition specifies a named joinpoint in the program that can be referenced by an advice.

  2. Define the advice for the exception handler pointcut.
    The advice references the name of the exceptionHandler pointcut. It contains a block of code that writes a log message for the exception:

        after(Exception e): exceptionHandler(e) {
           log.error("Exception: " + e.toString());
        }
  3. Create an aspect that puts together the advice and the pointcut.
    If you add the pointcut and advice to the LogPoints aspect, you have a logging interface that creates log entries for before and after the execution of init() and doGet() methods, and whenever an exception handler for Exception or any one of its subclasses is invoked (see the resulting aspect in Listing 2).
  4. Compile and run HelloWorldServlet (see Listing 1) and the LogPoints aspect.
    The external interface to the ajc compiler is the same as the javac compiler. You can execute it at a command line or within an Ant script. The AspectJ distribution includes examples and Ant scripts. You also can compile it with the AspectJ Browser. The HelloWorldServlet gets a "count" request parameter and converts it into an integer. Entering any non-numeric character will cause a NumberFormatException, and the exception handler will be invoked. If it runs and generates the exception, these log entries are written:

    2004-02-28 15:21:56,527 INFO  HelloWorldServlet : 
       Exit: call(void HelloWorldServlet.
          init(ServletConfig))
    2004-02-28 15:21:56,543 INFO  HelloWorldServlet : 
       Enter: call(void HelloWorldServlet.
          doGet(HttpServletRequest, HttpServletResponse))
    2004-02-28 15:21:56,543 ERROR HelloWorldServlet : 
       Exception: java.lang.NumberFormatException: 
          For input string: " 4"
    2004-02-28 15:21:56,574 INFO  HelloWorldServlet : 
       Exit: call(void HelloWorldServlet.
          doGet(HttpServletRequest, 
             HttpServletResponse))

    The log entries show that a NumberFormatException was thrown within the HelloWorldServlet class's doGet() method.

You can use AOP to improve the manageability of your existing applications. It allows you to add crosscutting behaviors to existing applications, making it well-suited to implementing operational concerns such as logging, security, authentication, and performance monitoring that cut across a system. These types of concerns are often overlooked during development because they are separate from an application's core concern. Using AOP, you can add these crosscutting concerns in separate modules so they aren't tangled and scattered throughout an application. With multiple production-quality, open-source implementations to choose from, AOP is worth considering as part of an application upgrade.

About the Author
Robert Swarr is an independent software consultant specializing in open-source software and Java development in New Britain, Conn. You can reach him by e-mail at robert.swarr@agoralogos.net.