Chapter 11. Aspect-Oriented Programming

Domain-specific languages offer the benefits of specialized language constructs for undertaking work in a particular problem domain. We’ve looked at examples such as Jython for scripting and the rule-based language Jess for defining business logic. This chapter focuses on the use of aspect-oriented programming (AOP), a programming paradigm that offers the ability to effect rapid change across a system’s entire code base with surgical precision.

The AOP paradigm brings an extra dimension to the design activity, making it possible to produce highly maintainable and extensible systems. Moreover, AOP introduces a dynamic element to the static nature of conventional software architecture, enabling the swift evolution of applications to accommodate emerging business concerns.

In the last few years, AOP has started to make its way into mainstream development, with J2EE vendors finding AOP ideally suited to the development of enterprise software. A new concept has been born, aspect-oriented middleware, and application server designers are rushing to adopt the lightweight, dynamic model AOP brings to the middle tier. Consequently, J2EE is on the cusp of a completely new approach to developing enterprise software.

This chapter introduces the major concepts of AOP and introduces two popular open source AOP products: AspectJ and AspectWerkz. AspectJ extends the Java language to include AOP constructs, while AspectWerkz adopts a framework-based approach. This chapter examines the merits of both approaches to implementing AOP and looks at how AOP languages and frameworks can complement the services offered by the J2EE platform.

The chapter concludes with some low-risk options for adopting AOP as part of your development toolkit.

First, we cover just why the world needs yet another programming paradigm.

Why AOP?

AOP grew out of the research labs of the famous Xerox Palo Alto Research Center (PARC). The paradigm resulted from work undertaken by a number of teams on several different areas of software engineering including reflection and alternative variants of object-orient programming (OOP). A team led by Gregor Kiczales identified a key shortcoming in conventional programming paradigms, the ability of these languages to contend with crosscutting concerns, and AOP was the result of research into addressing these shortcomings.

To understand how the AOP paradigm can benefit the software development process, it is necessary understand the nature of the crosscutting concern issue that AOP addresses.

Crosscutting Concerns

Object-oriented design focuses on the clean separation of concerns within a system. A concern is a concept, objective, or functional area that is of interest to the system. For example, a core concern of a stock-control system would be tracking stock items held at the warehouse.

Object-oriented languages provide the constructs necessary to localize the different concerns of a system into discrete modules. This is a fundamental approach to good software design and was practiced long before OOP came on the scene. Procedural languages put the rudimentary building blocks in place to enable the functional decomposition of concerns into modules. OOP built on the structures offered by procedural languages for modularization, introducing concepts such as information hiding and abstraction to facilitate the separation of concerns within a software system.

The problem with concerns is that they don’t all fit neatly into little boxes. Some concerns freely cross module boundaries and intersect with other concerns. These are known as crosscutting concerns and are generally associated with system-level concerns such as logging, threading, security, transactions, and performance. Such concerns are orthogonal to the core business concerns.

Note

Chapter 4 discusses the concept of orthogonal design in software architectures.

Crosscutting concerns are a dilemma for the software engineer, as OOP languages fail to offer a convenient mechanism for protecting the code base from the unwanted complexity they introduce into even the cleanest of software designs.

Code Tangling and Scattering

Crosscutting concerns are damaging to the design of software systems. They introduce the two unwanted side effects of code tangling and code scattering into the software architecture. Code tangling and scattering adversely affect the readability and maintainability of the application:

  • Code tangling.

    Tangling occurs when different concerns coexist within the same module. For example, a module that implements a specific business concern may also contain code that relates to logging, persistence, and performance. Tangling occurs when the implementation of the business logic becomes intertwined with the code for these other requirements within the body of the module.

  • Code scattering.

    Scattering occurs when the implementation of a crosscutting concern spreads over many modules. Logging is a classic example, as logging code exists in many of the application’s classes. Changes to logging therefore require visiting numerous parts of the system.

The impacts of crosscutting concerns on enterprise software are detrimental to the objectives of producing applications that are both readable and maintainable. Software that is hard to understand is difficult to maintain; code that is difficult to maintain cannot undergo rapid change in response to the evolving requirements of the business.

Fortunately, OOP is not completely defenseless against the ravages of crosscutting concerns, and various strategies are available to keep their impact to a minimum. These strategies essentially include the use of frameworks, design patterns, domain-specific languages, and mix-in classes. We briefly cover each of these techniques before examining how AOP addresses the issue.

Traditional Approaches to Crosscutting Concerns

The next sections look at the main techniques available for managing crosscutting concerns within the confines of a single paradigm OOP language such as Java.

Frameworks

Frameworks offer an effective means of separating core and system-level concerns, and the J2EE platform is an excellent example of this.

The J2EE platform frees the software engineer of many of the major system-level concerns that, by their very nature, tend to fall into the category of crosscutting concerns; threading and security are just two examples of system-level concerns that J2EE makes transparent to the developer. Each of these concerns is imperative for a high-performance, secure system, yet J2EE technology enables the developer to focus on implementing business knowledge and delegates the task of managing threads and authenticating and authorizing users to the J2EE server.

Having the J2EE server take responsibility for some of the major crosscutting system-level concerns significantly reduces the level of code tangling and scattering throughout the code base. Thread synchronization code does not appear in any of the application’s components because threading is entirely handled by the J2EE container, although the developer must still be wary of certain design decisions, such as the use of the Singleton pattern. Likewise, security in J2EE is effectively modularized by regulating security concerns to the deployment descriptor.

Despite the inarguable effectiveness of the J2EE platform in dealing with many system-level concerns, not all crosscutting concerns are system-level concerns. The J2EE platform cannot manage application-specific business crosscutting concerns, nor can the platform easily accommodate additional ad hoc system-level concerns not catered for by the platform. We therefore have only a partial solution to the crosscutting problem.

Fortunately, J2EE and AOP are not mutually exclusive, and AOP can build on the services of the J2EE platform.

Design Patterns

With careful design, it is possible to devise solutions with OOP techniques that can modularize crosscutting concerns, separating them from the system’s core concerns. The Visitor pattern is a good example of such a design and is applicable where objects within a hierarchy perform a number of unrelated operations [Gamma, 1995].

The authors of the Visitor pattern saw a need to prevent unrelated operations from polluting the classes within the hierarchy. Pollution of classes relates directly to the crosscutting concerns we are attempting to manage.

A Visitor pulls together the different and diverse operations performed on a particular class. The main class then accepts the Visitor, requesting it to perform these unrelated, crosscutting operations on its behalf.

Visitor gathers related operations together and separates unrelated ones, thereby promoting an application architecture that sees an object model aligned along concern boundaries.

The disadvantage of the Visitor pattern is that the main classes in the object hierarchy must be aware of Visitor objects and be prepared to invoke their behavior. Arguably, this is a crosscutting concern in itself, as framework code for the implementation of the pattern now must become part of the application. Code tangling is still evident within the code, albeit at a reduced level.

Mix-in Classes

The concept of mix-in classes is more appropriate for OOP implementations that support multiple inheritance than for single-inheritance languages like Java.

With this technique, functionality resides in discrete, loosely coupled and highly cohesive classes. Each class defines a specific behavior or trait. Fully featured classes result by mixing the different classes available from the object hierarchy. This approach enables the various concerns of a system to be assembled using multiple inheritance. The mix-in approach is workable, but very careful design of the class hierarchy is required to achieve a breakdown of functionality at the correct level of granularity.

Although Java does not support multiple inheritance per se, it can simulate the technique using interfaces and composition. The mix-in class design is more cumbersome to implement using these constructs than with true multiple inheritance. However, if Java were to ever support multiple inheritance, the complexities associated with its use, such as object construction order, shared-data member instances, and the need for virtual inheritance, would all outweigh the benefits the mix-in technique offers. Moreover, even with this technique, the main class still must orchestrate the calling of the different methods.

Domain-Specific Languages

To contend with crosscutting concerns, it is possible to look to other paradigms than OOP for help—for example, using a rule-based language for implementing business logic.

Note

Chapter 10 introduces rule-based languages.

Here, a rule-based language implements business concerns, while the services of the J2EE platform handle system-level concerns. Java serves as the glue between J2EE services and the rule-based language.

This is an effective approach because rule-based languages offer an excellent vocabulary for defining business logic. However, J2EE components still need to know the point at which to fire the business rules, and again, this represents a mixing of concerns.

The ideal solution for crosscutting concerns would see core concerns implemented in ignorance of orthogonal crosscutting concerns, thereby avoiding code tangling. Moreover, a language should offer the ability to modularize crosscutting concerns in the same way as is currently possible with core concerns in OOP languages. This would prevent code scattering.

The AOP paradigm provides the language constructs necessary to achieve these aims and is examined in the next sections.

AOP Explained

The primary goal of the AOP paradigm is to provide a mechanism for modularizing crosscutting concerns. The creators of AOP wanted a programming approach that could abstract and encapsulate crosscutting concerns, thereby facilitating software reuse.

Through the modularization of crosscutting concerns, AOP makes it possible to avoid code scattering and code tangling. Moreover, AOP implementations go beyond this primary goal and bring a dynamic element to the static nature of object-oriented applications. The static model of OOP designs is sensitive to change, with a change in requirements having the potential to wreak havoc upon the conventional static model. As we shall see, the dynamic capabilities of AOP implementations are of significant interest for rapid development because they offer the flexibility to accommodate change within the system.

To understand AOP, we must understand the concepts and terminology the paradigm introduces to the software engineering discipline.

Concepts and Terminology

OOP adds numerous new terms to the software engineer’s vocabulary, such as inheritance, composition, overloading, overriding, and everyone’s favorite—polymorphism. Learning the practices of OOP requires familiarity with these alien concepts.

Like OOP, AOP also comes complete with its own nomenclature, requiring our vocabulary to expand once again to encompass the paradigm’s concepts of crosscutting concerns, join points, pointcuts, advice, aspects, and weaving.

Here is an explanation of the AOP terminology:

  • Join points.

    A join point represents the point at which a crosscutting concern intersects with a main concern. Join points are well-defined locations in a program’s execution path, and examples include method invocation, conditional statements, and object instantiation. Essentially, a join point can be any point in an application’s execution.

  • Pointcuts.

    If a join point is a well-defined point in an application’s execution, then a pointcut is a language construct that identifies specific join points within the program. A pointcut defines a collection of join points, with a pointcut designator picking out specific join points and values at these points. The pointcut also provides a context for the join point.

  • Advice.

    Advice is the code executed upon reaching a particular pointcut within the program. Advice is therefore an implementation of a crosscutting concern.

  • Aspects.

    Aspects encapsulate join points, pointcuts, and advice into a unit of modularity for crosscutting concerns and offer reuse mechanisms for crosscutting concerns equivalent to that of a Java class for core concerns.

  • Weaving.

    Having separated the different concerns, to complete the system, it is necessary to recombine them to form the executing program. This process of interleaving aspects with the main application is known as weaving. The AOP weaver composes the different implementation aspects into a cohesive system in accordance with specific weaving rules.

AOP is therefore a process of weaving aspects that define crosscutting concerns into an application implemented in a conventional language that defines the core concerns. The result of the weaving process is a combination of concern types that make up the final system.

Classes and aspects are independent of one another, with only the pointcut declaration serving to bind the two paradigms. Classes are therefore unaware of the presence of aspects, and this is an important AOP concept.

This relationship between aspects and classes is very well described in an excellent early paper on AOP, Aspect-Oriented Programming: A Critical Analysis of a New Programming Paradigm [Highley, 1999]. The paper’s authors illustrate the relationship between OOP classes and AOP aspects by describing a mythical world inhabited by hunchbacks and dragons.

Hunchbacks and Dragons

Taken from the paper, the hunchbacks of the mythical world all worked in houses with glass ceilings. Dragons flew around the skies, observing the behavior of the hunchbacks in the houses below. The hunchbacks couldn’t look up and so were unaware of the existence of the dragons.

The hunchbacks communicated with hunchbacks in other houses by sending each other mail. The mail they received from other hunchbacks helped direct the work they completed for the day. The dragons, being inquisitive creatures, kept a close eye on the hunchbacks, including reading the hunchbacks’ mail—however, the dragons never stole or interfered with the mail.

At a given point, the dragons would suddenly leap into action. They might, for example, paint one of the houses red. The hunchbacks would notice their house had magically changed color, but they wouldn’t do anything about it. They would continue with their everyday tasks, still oblivious to the existence of the dragons.

This allegory perfectly captures the relationship between classes and aspects. From the story, the classes relate to the hunchbacks while the flying dragons represent aspects. An OOP application is self-contained, but aspects allow the augmentation of the application’s behavior without the need to change the underlying static object model. Aspects therefore offer the ability to inject new behavior into an existing system dynamically and transparently.

The task of mixing the two worlds of OOP and AOP is achieved using a weaver.

Weaving Methods

The process of weaving is critical to AOP. As the AOP paradigm has evolved, various approaches to the process of weaving have emerged. The following lists the different methods for injecting advice into a Java application:

  • Compile-time.

    This approach produces a woven application during the stages of the compilation process. First, aspects and classes are compiled to standard Java bytecode. Weaving then takes place as a postcompilation step using bytecode manipulation to add advice at the designated join points within the program.

  • Load-time.

    Load-time weaving defers the weaving process until the application is in a running state. Weaving then occurs at the bytecode level at class-load time. This method is known as code injection.

  • Runtime.

    Here, the process is similar to that of load-time weaving, except weaving at the bytecode level occurs as join points are reached in the executing application. This approach is also known as interception or call-time weaving.

Load-time and runtime weaving methods have the advantage of being highly dynamic, enabling on-the-fly changes to a running system. On the downside, such changes can adversely affect system stability and performance. In contrast, compile-time weaving offers superior performance, but requires the rebuilding and deployment of the application in order to effect a change.

Having set the scene, it is now time to go over an AOP example to illustrate how the various AOP concepts are applied. We first look at an example of AOP using AspectJ, an AOP language implementation, and then compare it to AspectWerkz, a framework for adding aspects to Java applications.

Introducing AspectJ

AspectJ was the first implementation of the AOP paradigm to come out of the research work undertaken at Xerox PARC and is the most mature and complete AOP implementation currently available. The Xerox team, led by Gregor Kiczales, produced AspectJ both as a first cut at a language specification for AOP and an AOP implementation. The Xerox AspectJ team chose to extend the Java language to support aspect-oriented concepts in addition to developing compilation and debugging tools for their new Java variant.

AspectJ represents a language-based AOP implementation, bringing new constructs and semantics to Java with additional keywords. These additions turn Java from a single-paradigm to a multiparadigm language, able to exploit the benefits of both OOP and AOP. Historically, this approach follows the same route as taken by C++, which extended the C programming language to incorporate OOP constructs.

When AspectJ reached a level of stability, it was relocated from the research labs of Xerox PARC into the arms of the open source community. AspectJ is now maintained as an Eclipse Technology project and can be found at http://eclipse.org/aspectj.

AspectJ and Eclipse

The Eclipse platform is a generic development environment that offers a powerful collection of Java development tools (JDT), including a Java source editor, compiler, and debugger.

Note

Chapter 13 describes the Eclipse platform and the JDT in detail.

AspectJ builds on the services of the JDT to provide the AspectJ Development Tool (AJDT), a fully featured Eclipse plug-in that brings the capabilities of the Eclipse platform to the AspectJ language, including content assist on keywords, aspect browsing, compilation error tracing, and the debugging of aspects.

Despite its links with Eclipse, AspectJ is not bound to the Eclipse platform. The primary focus of the project is the AspectJ compiler, which is available as a standalone executable. As a standalone release, independent of the AJDT, AspectJ supports the compilation and execution of applications. A structure browser is also available for interrogating AOP constructs within the code.

AspectJ also integrates with other popular development environments, with plug-ins available for JBuilder, NetBeans, and Emacs. Refer to the AspectJ site for information on where to obtain these and other plug-ins.

The AspectJ Compiler

AspectJ supports compile-time weaving, with version 1.1.2 offering limited support for load-time weaving.

The AspectJ compiler builds on the capabilities of Eclipse’s Java compiler, thereby firmly tying the language to the open source community and cutting its initial ties with javac. The Eclipse compiler is highly sophisticated and offers capabilities such as incremental compilation. By using the Eclipse compiler as its base, AspectJ leverages these capabilities for its own builds. Classes produced by the AspectJ compiler run on any Java-compatible platform.

AspectJ Example

To understand how some of the fundamental concepts of AOP are applied, let’s look at an example built using AspectJ. The example covers the main concepts of AOP and introduces the new language constructs AspectJ adds to the Java language to support AOP.

The code for the example adds aspects to an imaginary stock-control system. Stock items are contained within a central warehouse, and the stock-control system is responsible for managing all stock going into the warehouse. A single class encapsulates warehouse functionality. Listing 11-1 shows the implementation of the Warehouse class.

Example 11-1. The Warehouse Class

package stock;

import java.util.ArrayList;

/**
 * Warehouse class for storing stock items.
 */
public class Warehouse {

  private ArrayList stockItems;

  public Warehouse() {
    stockItems = new ArrayList();
  }
  /**
   * Add a new stock item
   */
  public void add(String stockItem) {
    stockItems.add(stockItem);
  }

  /**
   * Return the number of items in stock
   */
  public int itemsInStock() {
    return stockItems.size();
  }
}

The warehouse is nothing more than a wrapper around an ArrayList. However, the intention of the code is to demonstrate the concepts of AOP, not to build a fully featured stock-control system.

Our rudimentary stock-control system adds a number of stock items to the warehouse. Listing 11-2 shows the code for the stock-control example.

Example 11-2. The Main StockControl Class

package stock;

/**
 * Adds stock items to the warehouse
 */
public class StockControl {

  public void processStockItems() {

    //  Create the warehouse
    //
    Warehouse warehouse = new Warehouse();

    // Add some stock
    //
    warehouse.add("Washing Machine");
    warehouse.add("Microwave Oven");
    warehouse.add("Television");
  }

  public static void main(String[] args) {
    StockControl stockCtrl = new StockControl();
    stockCtrl.processStockItems();
  }
}

The example application is very simple, but it is easy to imagine a production version on a much grander scale. The concept of encapsulating the warehouse functionality into a component accessed via a common interface from all parts of the system is a design in keeping with object-oriented architecture.

To illustrate how AOP weaves in functionality, we introduce an auditing (or logging) concern into the system. The following use case defines the new auditing requirements:

  1. All stock items must have an audit-log entry before going into the warehouse.

  2. After adding a stock item to the warehouse, the number of items in the warehouse must be written to the audit log.

To incorporate the new requirements into the system using AOP, the first task is to specify the join points in the program where the auditing concern crosscuts the main concern. Achieving this task requires the declaration of a pointcut designator.

A pointcut designator is a special AOP language construct that specifies join point collections and precisely defines where a crosscutting concern intersects the main concern. AspectJ supports the declaration of pointcuts at a number of different locations in a program’s execution:

  • Method and constructor call

  • Method and constructor reception

  • Method and constructor execution

  • Field access

  • Exception handler execution

  • Class and object initialization

Complying with the auditing requirements requires the declaration of a pointcut occurring at the point of the call to the add() method on the Warehouse class. We need to weave in the auditing advice ahead of the add() method’s invocation and upon returning from the call.

Listing 11-3 shows the code for the aspect that specifies the pointcut declaration and the advice for weaving into the system.

Example 11-3. Auditing Aspect AuditingAspect.java

package stock;

import org.aspectj.lang.reflect.SourceLocation;

/**
 * Aspect to add auditing to the stock control system.
 */
public aspect AuditingAspect {

  // Pointcut declaration
  //
  pointcut auditStockItem() : call(* Warehouse.add(..));

  // Advice to execute before call
  //
  before() : auditStockItem() {
    System.out.println("<--Audit log entry start-->");

    // Log the name of the calling class
    //
    SourceLocation sl = thisJoinPoint.getSourceLocation();
    Class myClass = (Class)sl.getWithinType();
    System.out.println("	Caller: " + myClass.toString());

    // Log the stock item description
    //
    Object[] args = thisJoinPoint.getArgs();
    for(int i=0; i < args.length; ++i) {
      System.out.println("	Adding item: " + args[i]);
    }
  }

  // Advice to execute after call
  //
  after() : auditStockItem() {
    Warehouse warehouse;
    warehouse = (Warehouse) thisJoinPoint.getTarget();
    System.out.println("	Items in stock: " +
                        warehouse.itemsInStock());
    System.out.println("<--Audit log entry end-->");
  }
}

Examining the code in Listing 11-3 reveals a number of syntactic differences from standard Java, with the AOP keywords shown in bold text. The AspectJ keyword aspect specifies that we are defining an aspect and not a Java class. AspectJ uses aspects as a unit of modularization for crosscutting concerns. Aspects are similar to classes in that they have a type and can extend classes and other aspects. The main difference between the two constructs is that aspects cannot be instantiated with the new operator. They are also not directly interchangeable with classes.

The keyword pointcut declares the pointcut designator for the auditing advice and assigns the pointcut the name of auditStockItem(). Here is the full declaration of the pointcut:

pointcut auditStockItem() : call(* Warehouse.add(..));

The syntax following the pointcut name is of greatest interest because this captures the join points for the auditing concern. It is defined as call(* Warehouse.add(..), where call specifies the join point as the point at which the method is invoked. The remainder of the pointcut designator specifies the method signature for matching the join point at runtime. From the example, a match will be found for all add() methods on instances of the Warehouse class, regardless of access, return type, or arguments. AspectJ provides a rich syntax for defining join points, enabling the definition of sophisticated matches that go well beyond the simple example shown.

Having identified the join points in the program, the next step is to provide the auditing advice AspectJ will weave into the main concern. AspectJ has three options for associating advice with a join point: before(), after(), or around() the join point.

Our auditing advice has to both precede and follow the call to the Warehouse instance. The AspectJ syntax of before() and after() details precisely where the advice is to be injected once the join point is reached. This syntax gives the following method signatures for the auditing advice:

before() : auditStockItem() {
  ...

after() : auditStockItem() {
  ...

Examining the code for the before and after advice highlights the use of the thisJoinPoint object, which provides a context for the join point and makes information relating to the join point available to the advice. The example uses this information to log the name of the calling class and the arguments to the Warehouse.add() method, and to invoke the itemsInStock() method on the Warehouse instance.

The code for the example was compiled and run on the Eclipse platform using the Eclipse AJDT plug-in. The use of an aspect-aware development environment offers significant benefits over a plain code editor and build script. In addition to syntax coloring of keywords and content-assist on AspectJ types, aspect-aware environments, such as AJDT for Eclipse, provide a visual cue to where join points occur within the application. This is an invaluable aid for determining the impact of a pointcut declaration upon the code of the core concerns.

Figure 11-1 depicts this feature of the AJDT, which shows the code from the example open as a project on the Eclipse platform.

The Eclipse platform with an AspectJ project open.

Figure 11-1. The Eclipse platform with an AspectJ project open.

The upper right pane shows the code for the StockControl class open in an aspect-aware editor. Marks on the left border of the editor denote where the join points of the AuditingAspect aspect crosscut the StockControl concerns. The content of the outline view, seen in the lower left pane, displays a hierarchical view of the location of the aspect’s injected advice. The lower right pane contains the console view, which shows the results of executing the program.

The example contains only a single class and aspect. However, in a larger system with thousands of files, the pointcut declaration is just as easily applied across all classes within the system. This ability to inject functionality directly into a large system and with a high degree of precision makes AOP an ideal candidate for a rapid development language. Moreover, the dynamic nature of the language makes it an ideal prototyping tool because new behavior is easily added or removed as system functionality is explored.

tip

AOP is potentially well suited to the development of evolutionary prototypes. Omitting concerns such as security, auditing, logging, and persistence, enables a prototype to be rapidly constructed using a conventional OOP approach. Once the prototype is accepted, aspects weave in these concerns to transform the prototype into a production-standard application.

AspectJ was the first release of an AOP language and still stands out as the most comprehensive AOP implementation available, offering unrivaled tool support in the form of the AJDT for Eclipse. Since its emergence from the research labs of Xerox PARC, a host of alternative AOP implementations has joined AspectJ. These newcomers to the AOP paradigm take a different approach to AspectJ. Instead of a new language, they provide a framework for defining aspects. The next section discusses this approach.

Language Versus Framework

The designers of AspectJ elected to enhance the Java language to support AOP. Over the years, the AspectJ variant of Java has matured into a stable and complete AOP platform, with the AJDT offering excellent tool support.

However, changing the core Java language has met with a degree of criticism from some quarters. Some of the issues include the following:

  • Learning Java becomes more difficult because the additional keywords mean developers new to Java must embrace the concepts and semantics of both the OOP and AOP paradigms.

  • Compilation of Java and AOP hybrid languages requires the adoption of a new compiler.

  • Moving to an AOP language is an issue when looking to employ AOP on an existing project, since migration of the complete code base to the new language is required.

Recent AOP implementations take the approach of defining aspects externally to the Java application using a framework in order to circumvent these issues. Frameworks enable the superimposing of AOP concepts onto existing Java applications without the need to move the entire application to a new AOP compiler. These frameworks typically use XML configuration files or J2SE 5.0-style metadata annotations to specify pointcuts and advice within the main application, ensuring AOP-specific keywords are isolated from the application. Advice is defined as standard Java classes, referenced by the framework’s configuration.

A main advantage of these frameworks is that they bring AOP to vanilla Java, thereby easing the task of adopting AOP techniques within existing systems.

AOP Framework Implementations

The number of open source AOP frameworks available is growing steadily as AOP continues to gain interest among the Java community. Table 11-1 lists a selection of the AOP frameworks available as open source.

Table 11-1. AOP Frameworks

Name

Description

Reference

AspectWerkz

A popular, easy-to-learn AOP framework for Java. Features include both bytecode and load-time weaving.

http://aspectwerkz.codehaus.org

JBoss AOP

The JBoss AOP framework forms part of the JBoss application server and offers load-time and runtime aspect weaving. The framework is available standalone.

http://www.jboss.org/products/aop

Nanning

Nanning Aspects is a simple and scalable AOP framework for Java.

http://nanning.codehaus.org

CAESAR

Offers new AOP language that is compatible with Java. The CAESAR language compiles to standard Java bytecode.

http://caesarj.org/

JAC

Java Aspect Components (JAC) is an open source project targeting the use of AOP for developing an aspect-oriented middleware layer.

http://jac.objectweb.org/

Spring

Spring is an extensive Java-based framework in its own right based on the popular inversion of control (IOC) pattern. Spring also offers an AOP framework or is configurable to work with external AOP implementations.

http://www.springframework.org

To contrast AspectJ against a framework AOP implementation, we look at the approach to defining aspects taken by AspectWerkz.

Introducing AspectWerkz

AspectWerkz is a dynamic AOP implementation for Java, jointly developed by Jonas Bonér and Alexandre Vasseur. The framework is open source and available for download from the Codehaus site at http://aspectwerkz.codehaus.org. Check the site for full details of the license.

The AspectWerkz framework is not as comprehensive as AspectJ, but has a reputation as a workable and easy to learn AOP implementation. Unlike AspectJ, AspectWerkz does not extend the Java language to support aspects but instead defines aspects using either an XML definition file or J2SE 5.0-style metadata annotations. These methods for defining aspects avoid the need for an AOP-aware Java compiler.

note

Before the release of J2SE 5.0, AOP frameworks like AspectWerkz used XDoclet-style metatags embedded within Javadoc comment blocks. With metatags now supported by J2SE 5.0 as annotations, the AspectWerkz team has stated it intends to update the AOP framework to use the new syntax for defining metadata in Java code.

Note

Chapter 6 provides an overview of metadata annotations.

To compare how the approach of the AspectWerkz framework to AOP differs from that of AspectJ, consider the code snippet in Listing 11-4, which depicts a plain Java implementation of the AuditingAspect from the AspectJ example.

Example 11-4. AspectWerkz AuditingAspect Class

package stock;

import org.codehaus.aspectwerkz.joinpoint.JoinPoint;

public class AuditingAspect {

  public void beforeAddStockItem(JoinPoint joinPoint) {
    .
    .
    .
  }

  public void afterAddStockItem(JoinPoint joinPoint) {
    .
    .
    .
  }
}

The code snippet in Listing 11-4 is devoid of any AOP language constructs, although there are a few hints such as the JoinPoint class. We look first at how an external XML definition file transforms the class into a full-fledged aspect.

XML Aspect Definition

One of the first approaches of many of the AOP frameworks was to declare pointcut designators and the location of advice methods using XML definition files. Listing 11-5 shows a sample of an AspectWerkz definition file that turns the plain AuditingAspect Java class into an aspect.

Example 11-5. XML Definition File aop.xml

<aspectwerkz>
  <system id="stockcontrol">
    <package name="stock">

      <!-- Define the class implementing the aspect -->
      <aspect class="stock.AuditingAspect"
              deployment-model="perInstance">

         <!-- Named pointcut -->
         <pointcut name="auditStockItem"
                   expression="call(* Warehouse.add(..))"/>

         <!-- Bind aspect before method to pointcut -->
         <advice name="beforeAddStockItem"
                 type="before"
                 bind-to="auditStockItem"/>

         <!-- Bind aspect after method to pointcut -->
         <advice name="afterAddStockItem"
                 type="after"
                 bind-to="auditStockItem"/>

      </aspect>
    </package>
  </system>
</aspectwerkz>

Comparing the aspect definition in the XML file against the example from AspectJ reveals many similarities. Most notable is the syntax for the pointcut declaration. For example, here is the declaration for the pointcut in AspectJ:

pointcut auditStockItem() : call(* Warehouse.add(..));

Compare this to the corresponding declaration in the AspectWerkz configuration:

<pointcut name="auditStockItem"
          expression="call(* Warehouse.add(..))"/>

note

Supporters of AspectJ emphasize that these definition files present a similar learning curve to the new language constructs of AspectJ. This is a valid argument, but the strength of AspectWerkz lies in its ability to bring AOP to an existing system without requiring a move to an AOP compiler.

Aspects as Metadata Annotations

Later versions of AspectWerkz offer an alternative mechanism for specifying aspects using metadata annotations. This method moves AspectWerkz closer to the AspectJ model by embedding AOP constructs as annotations within the language. The advantage of embedded annotations over an external XML file is that all code related to the aspect resides within a single file.

Listing 11-6 shows the AuditingAspect class but this time adorned with AspectWerkz annotations.

Example 11-6. AuditingAspect Class with Metatags

package stock;

import org.codehaus.aspectwerkz.joinpoint.JoinPoint;

/**
 * @Aspect perInstance
 */
public class AuditingAspect {

  /**
   * @Before call(* Warehouse.add(..))
   */
  public void beforeAddStockItem(JoinPoint joinPoint) {
    .
    .
    .
  }

  /**
   * @After call(* Warehouse.add(..))
   */
  public void afterAddStockItem(JoinPoint joinPoint) {
    .
    .
    .
  }
}

This new version of the AuditingAspect now bears a strong resemblance to the AspectJ version.

Here is the declaration of the before advice from the AspectJ example:

before() : auditStockItem() {...}

AspectWerkz produces a similar construct using metatags. The metadata also identifies the join points for the advice.

/**
 * @Before call(* Warehouse.add(..))
 */
public void beforeAddStockItem(JoinPoint joinPoint) {...}

Metadata annotations replace the previous XML definition file, although a smaller file is still required to alert the AspectWerkz framework to the presence of aspects within the application.

Precompilation of AOP metadata information into the application makes it available at runtime for the AspectWerkz weaver. However, moving to J2SE 5.0 removes the need for the precompilation step.

tip

The introduction of metadata annotations with J2SE 5.0 offers other interesting advantages to AOP frameworks. In addition to supporting the annotation model used by AspectWerkz, annotations make excellent join point candidates because they are unambiguous. For example, the declaration call(@annotation * *(..)) offers the AOP developer more options when determining the location of join points within the application.

AspectWerkz Weaving Options

The framework supports several weaving schemes, including bytecode and load-time weaving. AspectWerkz refers to these weaving schemas in terms of an operating mode: offline and online modes.

Offline mode is compile-time weaving and is a two-step process in AspectWerkz. The first step is the standard compilation of all source code with javac. The final step is the weaving process. Here, the AspectWerkz framework weaves the class files of the main application with the advice from the pertinent aspects. The result is a set of woven classes that run under any JVM, 1.3 or higher.

The online mode is more interesting, offering dynamic load-time weaving. In this mode, AspectWerkz hooks itself directly into the class-loading mechanism of the JVM. From this unique vantage point, AspectWerkz monitors class-loading activity and intercepts classes as they are loaded, weaving in advice at the bytecode level on the fly.

Aspect-Oriented Middleware

AOP frameworks like AspectWerkz are gaining recognition for the advantages they bring to the development of enterprise software. The binding of application servers with AOP frameworks has given rise to a new term, aspect-oriented middleware.

The J2EE platform already takes care of many major system-level crosscutting concerns for the developer, providing services for handling threading, security, persistence, transactions, and component-location transparency. Despite this long list of services, the J2EE platform employs a static model for the management of crosscutting concerns. In comparison to AOP-based frameworks, the J2EE model is rigid and inflexible, with new concerns requiring ad hoc solutions. Aspects promise a fluid and dynamic model for development, and experts in the field believe aspects will revolutionize application server design and the way we develop enterprise software.

Major J2EE server vendors are investing in AOP technology in order to take advantage of the new dimension aspects bring to the middle tier. IBM sponsors AspectJ, and formal support for AspectJ in WebSphere and WebSphere Application Developer (WSAD) is expected in the near future. Meanwhile, BEA has hired the creators of AspectWerkz to add dynamic AOP capabilities to its JRockit JVM. JBoss is currently forging ahead and have come up with its own AOP framework, JBoss AOP, which is an integral part of its application server.

Aspect-oriented middleware is at the (cross) cutting edge and may in the future represent a fundamental change in the way we develop enterprise software.

Adopting Aspects

Anyone involved in the development of business-critical systems is aware of the importance of a conservative approach when adopting new technology. Production systems must be robust, and a good architect takes all necessary steps to ensure the stability and reliability of any software that underpins an organization’s core business processes.

Although AOP has been undergoing research for over 10 years, the paradigm has yet to establish itself within the software engineering community to the same degree as OOP. Indeed, some members of the IT community claim that we have yet to establish a complete set of best practices for developing with OOP. Undoubtedly, many mistakes are likely with AOP as people attempt to realize the full potential of the paradigm. This was certainly the case with OOP.

Given the constraint that the ongoing stability of a production-level system is sacrosanct, this section offers some advice for safely introducing AOP to either a new development project or as part of an established system.

Development Aspects

One approach to adopting AOP is to constrain the use of the technology solely to the development process by targeting development aspects. Development aspects are those aspects primarily of interest only to the development team. They offer an excellent opportunity to deploy AOP in the relative safety of the development environment without impacting production software.

Examples of development aspects include the following:

  • Tracing.

    Adding trace statements to the code to follow the flow of a specific section of the application is an effective debugging method and supplements the use of a debugging tool.

  • Profiling.

    AOP enables the instrumentation of the application with code to gather performance data from the executing program. Profiling techniques identify bottlenecks within the application that prevent the system from achieving its performance objectives.

  • Testing.

    In addition to injecting advice for profiling applications, AOP can add advice as part of a white-box testing approach. Advice in this context reveals the internal state of the class under test.

Development aspects serve only as an aid in the development process and do not target production-level systems. The dynamic nature of the AOP paradigm makes it very easy to remove development aspects from a system prior to its release into a production or preproduction environment.

Note

The different types of system environments are described in Chapter 15.

Removing aspects from a system using AspectJ is simply a case of omitting aspects from the build process. For AOP frameworks that rely on load-time weaving, the production system has the AOP framework disabled.

tip

Placing aspects under their own source directory or within their own package structure makes it easy to create build scripts that omit aspects from production builds.

Using AOP for only development aspects therefore offers a low-risk, incremental approach to introducing AOP to a project. The next step is to use AOP to implement production aspects of the system.

Production Aspects

Unlike development aspects, production aspects form an integral part of the system delivered into production and actively contribute to the behavior of the system.

Taking AOP to this level carries a higher level of risk, but they are manageable by taking sensible steps in the introduction of AOP. These same steps apply when looking to introduce any new technology into a production environment.

A few common issues raised against the use of AOP in a production environment include the following:

  • System performance degradation due to runtime weaving

  • Emergent system behavior resulting from inaccurate pointcut declarations

A comprehensive testing process should address both of these issues, which is a standard approach when releasing any system into a production environment. You should also make the declaration of pointcut designators more accurate by enforcing rigorous coding standards.

Here are some ideas to consider if you are looking to deploy an AOP-based system into production:

  • Experiment with development aspects.

  • Define coding standards for working with aspects.

  • Ensure all staff are knowledgeable in the use of AOP techniques.

  • Build prototypes to validate the selected AOP framework from both a functional and performance perspective.

  • Thoroughly test the system and the configuration of the AOP framework before deploying into production.

By following a methodical and incremental approach to the adoption of AOP, you should be able to successfully make AOP-based applications a part of your enterprise environment.

AOP and Other Paradigms

AOP is not limited to just the OOP paradigm but is equally applicable to other programming types. Research is underway to investigate the suitability of AOP with procedural and rule-based languages. One area of interest is in the twinning of AOP and Model-Driven Architecture (MDA).

Note

MDA is covered in Chapter 8.

AOP is complementary to working with the MDA paradigm, and the combination of the two technologies may point to an exciting direction for the future of application development. Code resulting from an MDA process is particularly well suited for defining pointcuts, due to the ability of MDA tools to generate standard method signatures and adhere to coding standards. An MDA-generated application therefore forms an ideal candidate for evolving into a final system by weaving in advice.

Taking this scenario further, the MDA tool could generate an application built purely from system-level concerns. Business concerns would be implemented as aspects that could then be woven into the framework created by the MDA tool. Theoretically, this approach would result in a completely platform-neutral application, as the only handwritten code would be the business logic in the aspects.

Switching platforms—for example, moving to the new EJB 3.0 model—would simply involve plugging in a new MDA cartridge and redefining some of the pointcuts for the final weave. Indeed, the MDA cartridge could potentially generate the new pointcut declarations, leaving the developer with even less work to do.

The benefits of MDA with AOP are still just idle speculation, and more research is required to ascertain if the approach is workable. However, potentially the two paradigms have the ability to work well together, meaning the future of developing business software could lie in the skills of modeling and weaving.

Summary

AOP is an emerging programming paradigm that augments the benefits of existing paradigms by providing language constructs that support the modularization of crosscutting concerns.

Interest in AOP is growing steadily within the developer community, and AOP is starting to penetrate the mainstream with major application server vendors moving to integrate the technology within their products.

Following are some of the main reasons to consider adopting AOP:

  • Improved designs and more easily maintainable applications due to the modularization of crosscutting concerns

  • Systems offering greater flexibility in the face of changing requirements

  • The ability to effect widespread change to an application’s code base rapidly and dynamically

  • Complementary to the development of solutions for the J2EE platform

Despite the benefits, AOP has yet to be universally accepted by the Java community, with some high-profile software engineers urging a cautious approach to what still is an emerging technology. However, moving to AOP does not require an all-or-nothing approach, and a low-risk incremental adoption of the paradigm is possible.

Perhaps the core strength of AOP lies in the new dimension it brings to existing programming paradigms. We briefly discussed the possibilities surrounding the twining of AOP with MDA.

Another interesting combination would be AOP with rule-based languages. This scenario sees business analysts using business-domain languages to describe business processes, while software engineers weave in aspects to turn business descriptions into software solutions. With this future vision of software development, business analysts become the hunchbacks, while the software engineers are the dragons. Personally, I’d rather be a dragon than a hunchback.

Additional Information

AOP is an extensive subject, and it has been necessary to be very selective in order to cover the topic within the confines of a single chapter. Further information on AOP is available from the aspect-oriented software development Web site at http://aosd.net.

Ramnivas Laddad’s “I Want My AOP Series,” a three-part article on AOP based on AspectJ, can be found on the JavaWorld site. See http://www.javaworld.com/javaworld/jw-01-2002/jw-0118-aspect.html.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.158.230