Skip to main content

Aspects for MDD: Aspect-Based Tracing and First Failure Data Capture in Rational Software Architect

Leveraging the power of aspects

Helen Hawkins (hawkinsh@uk.ibm.com), Software Engineer, IBM, Software Group
Dr. Helen Hawkins is a developer within the IBM aspect-oriented software development team in Hursley, England, where she works on both the AspectJ and AJDT Eclipse projects. Before joining the team, she focused on testing (particularly stress testing) large software systems.
Sian January (sjanuary@uk.ibm.com), Software Engineer, IBM, Software Group
Sian January is a software engineer in the IBM Java Technology Centre in Hursley, England. She worked on the AJDT Eclipse.org project for three years after joining IBM in 2003. She has spoken about AspectJ in various venues, including the 2005 Eclipse Day in Nantes.

Summary:  Aspect-Oriented Programming (AOP) is a powerful and fast-growing technology that enables clean modularization of crosscutting concerns, such as error handling, logging, monitoring, debugging support, validation, and many others. Aspects for model-driven development (MDD) brings AOP and MDD together for the first time in a plug-in for IBM® Rational® Software Architect. This article introduces the Aspects for MDD plug-in, and shows you how it can be used to enable tracing and First Failure Data Capture (FFDC) in MDD applications. We'll also look under the covers of the aspects and find out how they work.

Date:  11 Jul 2006
Level:  Intermediate
Activity:  473 views

Introduction

Aspects for MDD is a framework that enables modelers and developers using IBM® Rational®Software Architect (hereafter, Software Architect) to apply AspectJ code without needing any technical knowledge of aspects.

What's the difference between tracing and logging?

Logging is creating a record of events in the order that they occurred. Tracing is a specialized type of logging that creates a record of method entries and exits in the order that they occurred.

This article presents two aspects from the com.ibm.aspectj.lib library contribution to Aspects for MDD, Tracing and First Failure Data Capture. The Tracing aspect makes use of the logging facility that comes with the Java™ Developer Kit (JDK™) in Java versions 1.4 and later. Tracing is generally used for problem diagnosis, either by the original developer, or by a service engineer or an end user. A trace will normally be output either to a text file or a console window, and it will list method entries and exits in the program as it runs. By reading the trace file, it is usually possible to narrow down where in the code the problem may have occurred. Our version of tracing is configurable, and can output its trace to the console, a text file, or both.

First Failure Data Capture (FFDC) is also used in problem diagnosis. When an error or exception occurs in your application, FFDC ensures that it is dealt with in the correct way, and that any useful information about the error is preserved. Using FFDC in an application can seriously reduce the time it takes to diagnose and fix a problem. In addition, using an aspect to implement FFDC ensures that no errors or exceptions go undetected, which can easily happen when it is implemented by hand.

No AOP knowledge is required either to read this article or to get started using Aspects for MDD. However, a basic knowledge may be helpful when reading the Under the Covers sections of this article. Some experience using Software Architect will be helpful, although it is not absolutely necessary.

After reading this article, you should have a good understanding of the circumstances in which you may want to use Tracing and FFDC. You should be able to install Aspects for MDD, and apply the Tracing and FFDC aspects to your application. You should also have some understanding -- in practical terms -- of how the aspects work.


Setup

To follow along with this article, have Rational Software Architect v6.0.1 installed, and then you need to do the following:

  • Install the AspectJ Development Tools (AJDT) for Eclipse 3.0
  • Install the Aspects for MDD Framework
  • Create a sample model

Instructions for installing AJDT for Eclipse 3.0 can be found by following the download link on the AJDT homepage (see Resources). Also see Resources for a link to where to download the Aspects for MDD Framework for Rational Architect.

The sample model you're going to use is a simple HelloWorld program, which does what all HelloWorld programs do and prints "Hello World" to the screen. Since this article shows you how to apply the FFDC aspect, there's also a method included that throws a RuntimeException and then prints "Goodbye World"

To create this sample model:

  • Create a new AspectJ Project called aj_project (File > New > Other > AspectJ > AspectJ Project)
  • In this new project, create a new UML Model. Right-click the aj_project project and select New > UML Model.
  • Keep all the defaults but change the name to SimpleModel and click Finish.
  • Within this model, create a new HelloWorld class by right-clicking in the model and selecting Add UML > Class.
  • Within the UML class, create four operations called main, sayHello, sayGoodbye, and throwingMethod by right-clicking the HelloWorld diagram and selecting New UML > operation.
  • Modify the properties of the newly created operations in the Properties view to ensure that main is static, and that sayHello and sayGoodbye return Strings.
  • Run the UML to Java transformation by right-clicking the newly created class in your model and selecting Transform > UML to Java.

When you're done, open the HelloWorld class in the editor and modify it to contain the code shown in Listing 1.


Listing 1. HelloWorld class
           
public class HelloWorld {

    public static void main(String[] args) {
           System.out.println("Starting");
           HelloWorld main = new HelloWorld();
           System.out.println( main.sayHello() );
           System.out.println( main.sayGoodbye() );
           System.out.println( "Finishing" );
    }

    public String sayHello() {
           return "Hello World";
    }

    public String sayGoodbye() {
           try {
                  throwingMethod();
           } catch (Exception e) {
           }
           return "Goodbye World";
    }

    public void throwingMethod() {
           throw new RuntimeException();
    }

}

Before going any further, run the sample application. To do this, follow these steps:

  1. Select Run > Run
  2. In the left-hand menu, select Java Application and click New
  3. In the Main tab on the right side, select HelloWorld
  4. Select OK.

The output is sent to the console and is as shown in Listing 2.


Listing 2. The output from the HelloWorld application
        
Starting
Hello World
Goodbye World
Finishing

You're now ready to apply the Tracing and FFDC aspects.


Using the Tracing aspect

In this section, you will learn how to apply tracing to your application. You will first apply it to the sample model developed in the Setup section. The article will then discuss the different possibilities for using tracing in your own application. Finally, you'll go under the covers of the Tracing aspect and find out how it works.

Applying the Tracing aspect to the sample model

Using the simple test model described in the Setup section, you are going to apply java.util.logging to the sayHello() method. To do so, follow these steps:

  1. In the diagram, right-click sayHello().
  2. Select Aspect Lib from the resulting menu.
  3. In the Aspect Specification dialog, choose JDK14Tracing from the AspectJ Library Aspects category.
  4. Select OK.

You will notice that a <<jdk14tracing>> stereotype has appeared next to the operation (see Figure 1).


Figure 1. The jdk14tracing stereotype applied to the sayHello model element
 jdk14tracing stereotype
  1. Now, run the UML to Java transform by selecting the class in the diagram, right-clicking, and navigating to Transform > Run Transformation > UML to Java.

If you look in the Package Explorer (if this is not showing, navigate to Window > Show View > Package Explorer), you will see that a file named HelloWorldJDK14Tracing.aj has been created, as shown in Figure 2.


Figure 2. The generated HelloWorldJDK14Tracing.aj file
The generated file

You'll look at that file in more detail a little later.

In order to run the HelloWorld program, java.util.logging requires the creation of a logging.properties file (for more information about java.util.logging, see Resources). To create a logging.properties file, which serves as a configuration file for the logger, follow these steps:

  1. Select the project in the package explorer.
  2. Select File > New > File.
  3. Enter logging.properties as the name.
  4. Select Finish.
  5. Open the file and paste the contents of Listing 3, following, into the file.
  6. Save the file.

Listing 3. logging.properties
        
############################################################
#      Logging Configuration File
############################################################


# Global properties

handlers= java.util.logging.ConsoleHandler
.level= INFO


# Handler specific properties.

java.util.logging.ConsoleHandler.level = FINER
java.util.logging.ConsoleHandler.formatter = 
    java.util.logging.SimpleFormatter


As mentioned previously, it is possible to output tracing to a console, a text file, or both. The next section, How to apply tracing to your own application, will look at how you can change the logging.properties file to do just that.

First, run the sample application. To do so, follow these steps:

  1. Open the run configuration you made at the end of the Setup by selecting Run > Run
  2. Switch to the Arguments tab and, in the VM Arguments text box, type -Djava.util.logging.config.file=logging.properties.
  3. Select OK.

The output -- as shown in Listing 4 -- is sent to the console.


Listing 4. The output from the application with the Tracing aspect applied
    
Starting
? initLogger() logger=HelloWorld
? initLogger() traceEnabled=true
21-Oct-2005 16:28:57 HelloWorld sayHello
FINER: ENTRY
Hello World
Goodbye World
Finishing
21-Oct-2005 16:28:57 HelloWorld sayHello
FINER: RETURN Hello World

How to apply tracing to your own application

As mentioned in the introduction, tracing is primarily useful for problem diagnosis. When you consider this, there are several different options for what to trace. First, if the application is reasonably small, you may wish to trace everything. This has the advantage that you are more likely to find a problem if it occurs in an unexpected area of the code. However, the usefulness of a complete trace decreases as the size of an application increases, because it becomes large enough to obscure any useful information. With larger applications, you may want to trace only areas of the application that are known or expected to be problematic. Alternatively, or in addition, you may want to trace your API classes. This would mean that if a problem occurred in the course of a client's application calling yours, you should be able to ascertain in whose code the error occurred. If the error occurred in your code, it may be helpful to see which part of the API was being used at the time, and in what way.

After deciding to use tracing in your application, you may wish to configure some of the details of your trace. This is done through the logging.properties file.

The original logging.properties file is shown previously in Listing 3. To change the configuration file to output the trace to a text file as well as to the console, change handlers= java.util.logging.ConsoleHandler to handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler. To output only to a file, change it to handlers= java.util.logging.FileHandler. You will then need to add some configuration settings for the file handler:

java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

The updated logging.properties file is shown in Listing 5.


Listing 5. updated logging.properties file

############################################################
#      Logging Configuration File
############################################################


# Global properties

handlers = java.util.logging.FileHandler, 
    java.util.logging.ConsoleHandler
.level = INFO


# Handler specific properties.

java.util.logging.ConsoleHandler.level = FINER
java.util.logging.ConsoleHandler.formatter = 
    java.util.logging.SimpleFormatter
    
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = 
    java.util.logging.XMLFormatter


You may also want to configure the log levels for the console, the file, and possibly for individual classes. The log level you choose determines which events are included in the trace. The available levels are:

  • SEVERE
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST

SEVERE will give you the least amount of information, and FINEST the most. In addition, you can also specify OFF to switch tracing off or ALL to include all events. Use the following to specify the level for:

  • Overall: .level= ...
  • The console: java.util.logging.ConsoleHandler.level = ...
  • The file: java.util.logging.FileHandler.level = ...
  • An individual class (for example, HelloWorld): HelloWorld.level = ...

Note: At the time of writing, all the tracing output is logged at the FINER level.

For more information about Java logging and how to configure it, please see the Resources section.

Under the covers

AOP Terms

  • Join Point: A join point is an event that occurs when a program runs, such as executing a method or handling an exception.
  • Pointcut: A pointcut describes a set of join points.
  • Advice: Advice is associated with a pointcut. It is additional logic that runs at join points matched by the pointcut, such as tracing the execution of a method.
  • Aspect: An aspect is a programming construct that contains pointcuts and advice.

For more information on AOP, please see the Resources section.

The com.ibm.aspectj.lib aspect library contribution to Aspects for MDD includes an abstract tracing aspect, JDK14Tracing. This aspect and its parent, Tracing, contain all the tracing implementation logic, but no information about what should be traced. A sub-aspect needs to provide this information, in the form of a pointcut. If you have applied an aspect to part of your UML model, an AspectJ aspect will be created in a .aj file as part of the UML to Java conversion process. The aspect created in the example process previously is shown in Listing 6 following. It is a concrete subtype of the abstract JDK14Tracing aspect, which is shown in Listing 7.

Please note that for conciseness we have removed the import statements, package declaration, copyright statements, and some content from the longer code listings. The full code is available in the aspectjLibsrc.zip file contained in the com.ibm.aspectj.lib library contribution.


Listing 6. HelloWorldJDK14Tracing.aj

public aspect HelloWorldJDK14Tracing extends 
    org.aspectj.lib.tracing.JDK14Tracing {

    protected pointcut tracingScope () : 
        execution( * HelloWorld.sayHello() ) 
        || staticinitialization(HelloWorld);

}


Listing 7. JDK14Tracing.aj
        
public abstract aspect JDK14Tracing extends Tracing {

    /*
     * Sub-aspects implement to determine what to trace
     */
    protected abstract pointcut tracingScope ();

    /*
     * Use if() pointcut to efficiently determine 
     * when to trace
     */
    protected pointcut shouldTrace () :
        if(tracingEnabled) && tracingScope();
    
    private static boolean tracingEnabled = false;

    /*
     * Ensure logger is initialized for each class we are tracing
     */
    before(): staticinitialization(!Tracing+) && tracingScope() {
        initLogger(thisJoinPointStaticPart);
    }
    
    public final static Level ENABLED = Level.FINER;
    public final static Level DISABLED = Level.OFF;

    protected String getLoggerName (JoinPoint.StaticPart sjp) {
        return sjp.getSignature().getDeclaringTypeName();
    }

    protected void initLogger (JoinPoint.StaticPart sjp) {
        Logger logger = Logger.getLogger(getLoggerName(sjp));
        System.err.println("? initLogger() logger=" + 
                logger.getName());
        if (!tracingEnabled) {
            tracingEnabled = isTracingEnabled(logger);
        }
        System.err.println("? initLogger() traceEnabled=" + 
                tracingEnabled);
    }
    
    /*
     * From the Javadoc for Level: "By default logging calls for 
     * entering, returning, or throwing an exception are traced 
     * at this level."
     */
    private static boolean isTracingEnabled (Logger logger) {
        return logger.isLoggable(ENABLED);
    }
    
    protected void enter (JoinPoint jp) {
        Logger logger = Logger.getLogger(getLoggerName(
                jp.getStaticPart()));
        if (isTracingEnabled(logger)) {
            CodeSignature signature = 
                    (CodeSignature)jp.getSignature();
            logger.entering(signature.getDeclaringTypeName(),
                    signature.getName(),jp.getArgs());
        }
    }
    
    protected void enter (JoinPoint jp, Object obj) {
        Logger logger = Logger.getLogger(getLoggerName(
                jp.getStaticPart()));
        if (isTracingEnabled(logger)) {
            CodeSignature signature = 
                    (CodeSignature)jp.getSignature();
            logger.entering(signature.getDeclaringTypeName(),
                    signature.getName(),jp.getArgs());
        }
    }
    
    protected void exit (JoinPoint.StaticPart sjp) {
        Logger logger = Logger.getLogger(getLoggerName(sjp));
        if (isTracingEnabled(logger)) {
            CodeSignature signature = 
                    (CodeSignature)sjp.getSignature();
            logger.exiting(signature.getDeclaringTypeName(),
                    signature.getName());
        }
    }
    
    protected void exit (JoinPoint.StaticPart sjp, Object ret) {
        Logger logger = Logger.getLogger(getLoggerName(sjp));
        if (isTracingEnabled(logger)) {
            CodeSignature signature = 
                    (CodeSignature)sjp.getSignature();
            logger.exiting(signature.getDeclaringTypeName(),
                    signature.getName(),ret);
        }
    }
    
    protected void exception (JoinPoint.StaticPart sjp, 
            Exception ex) {            
        Logger logger = Logger.getLogger(getLoggerName(sjp));
        if (isTracingEnabled(logger)) {
            Signature signature = sjp.getSignature();
            logger.exiting(signature.getDeclaringTypeName(),
                    signature.getName(),ex);
        }
    }
}

JDK14Tracing itself extends another aspect, Tracing, which is shown in Listing 8.


Listing 8. Tracing.aj
    
public abstract aspect Tracing {

    /*
     * Sub-aspects implement to determine what and when to trace
     */
    protected abstract pointcut shouldTrace ();

    private pointcut staticContext () : !this(Object);
    private pointcut nonStaticContext (Object obj) : this(obj);
    private pointcut voidMethod () : execution(void *(..));
    private pointcut objectMethod () : execution(* Object.*(..));

    /* 
     * Ensure we don't trace ourselves or any other sub-aspects
     */
    private pointcut excluded () : 
        objectMethod()
        || within(Tracing+);

    private pointcut tracedMethod () :
        execution(public * *(..))
        && !excluded();

    private pointcut tracedConstructor (Object obj) :
        execution(new(..))
        && this(obj)
        && !excluded()
        ;
    
    before (Object obj) : tracedMethod() && nonStaticContext(obj) 
            && shouldTrace() {
        enter(thisJoinPoint,obj);
    }
    
    before () : tracedMethod() && staticContext() && shouldTrace() {
        enter(thisJoinPoint);
    }
    
    after() returning() : tracedMethod()&& voidMethod() 
            && shouldTrace() {
        exit(thisJoinPointStaticPart);
    }
    
    after() returning(Object ret) : tracedMethod() && !voidMethod() 
            && shouldTrace() {
        exit(thisJoinPointStaticPart,ret);
    }
    
    after() throwing(Exception ex) : tracedMethod() 
            && shouldTrace() {
        exception(thisJoinPointStaticPart,ex);
    }
    
    before () : tracedConstructor(Object) && shouldTrace() {
        enter(thisJoinPoint);
    }
    
    after (Object obj) : tracedConstructor(obj) && shouldTrace() {
        exit(thisJoinPointStaticPart,obj);
    }
    
    /*
     * Template methods implemented by infrastructure-specific 
     * sub-aspects
     * e.g. Log4j to log data 
     */
    protected abstract void enter (JoinPoint jp, Object obj);
    
    protected abstract void enter (JoinPoint jp);
    
    protected abstract void exit (JoinPoint.StaticPart sjp);
    
    protected abstract void exit (JoinPoint.StaticPart sjp, 
            Object ret);
    
    protected abstract void exception (JoinPoint.StaticPart sjp, 
            Exception ex);

...

}

The Tracing aspect in Listing 8 is a general tracing aspect, which provides the mechanism for tracing -- in the form of pointcuts and advice -- but does not contain any ties to a particular tracing or logging framework. This is extended (in Listing 7) by JDK14Tracing, which implements the enter and exit template methods provided by Tracing to use the java.util.logging framework. This means that, in the future, another tracing implementation could be contributed to the workbench (for instance, Log4j based tracing), and would be able to reuse the Tracing super-aspect.

The Tracing aspect contains an abstract pointcut on line 6, shown again in Listing 9.


Listing 9. A pointcut from Tracing.aj
        
    /*
     * Sub-aspects implement to determine what to trace
     */
    protected abstract pointcut tracingScope ();
    

This is made concrete in the HelloWorldJDK14Tracing aspect (Listing 10). The concrete implementation describes the scope of the tracing to be the execution of the method sayHello() in the HelloWorld class. The staticinitalization pointcut is an artifact of the JDK141Tracing implementation.


Listing 10. HelloWorldJDK14Tracing.aj
    
public aspect HelloWorldJDK14Tracing extends 
    org.aspectj.lib.tracing.JDK14Tracing {

    protected pointcut tracingScope () : 
        execution( * HelloWorld.sayHello() ) 
        || staticinitialization(HelloWorld);

}
    

The Tracing aspect contains before and after advice for methods and constructors, meaning that both entry and exit is traced. An example of one of these pieces of advice is shown in Listing 11. The advice delegates to one of the enter or exit template methods (or the exception template method if an exception has been thrown from the method). These methods are implemented in JDK14Tracing, as shown in Listing 12.


Listing 11. Before advice in Tracing.aj
    
    before (Object obj) : tracedMethod() && nonStaticContext(obj) 
            && shouldTrace() {
        enter(thisJoinPoint,obj);
    }
    


Listing 12. Enter method from JDK14Tracing.aj
    
    protected void enter (JoinPoint jp) {
        Logger logger = Logger.getLogger(getLoggerName(
                jp.getStaticPart()));
        if (isTracingEnabled(logger)) {
            CodeSignature signature = 
                    (CodeSignature)jp.getSignature();
            logger.entering(signature.getDeclaringTypeName(),
                    signature.getName(),jp.getArgs());
        }
    }
    

The Tracing aspect contains several concrete pointcuts in addition to the abstract one implemented by our generated aspect. These are shown again in Listing 13.


Listing 13. Pointcuts from Tracing.aj
    
    private pointcut staticContext () : !this(Object);
    private pointcut nonStaticContext (Object obj) : this(obj);
    private pointcut voidMethod () : execution(void *(..));
    private pointcut objectMethod () : execution(* Object.*(..));
    

The first pointcut is used to define a scope for static methods, and the second for non-static. The third pinpoints methods with a void return type. The fourth pinpoints the execution of methods that are inherited from java.lang.Object (for example, toString() and hashcode()), which are excluded from the trace to avoid recursion problems. These pointcuts are used in different combinations by the advice in order to ensure that all methods are traced correctly.


Using the FFDC aspect

In this section you will learn how to apply FFDC to your application. You will first apply it to your sample application to see how it works. The article will then discuss the possibilities of applying FFDC to your application, and finish by going under the covers of the aspects involved to find out how they work.

Applying the FFDC aspect to the sample application

Using the simple test model described in the Setup section, you're going to apply FFDC to the sayGoodbye() method. You'll do this in a similar way to applying logging to the sayHello() method in the Using the Tracing aspect section. To apply FFDC to the sample application, perform the following steps:

  1. In the diagram, right-click sayGoodbye()
  2. Select Aspect Lib from the resulting menu.
  3. In the Aspect Specification dialog, choose JDK14FFDC from the AspectJ Library Aspects category.
  4. Select OK.

You will notice that a <<jdk14ffdc>> stereotype has appeared next to the operation, as shown in Figure 3.


Figure 3. The jdk14ffdc stereotype applied to the sayGoodbye model element
The jdk14ffdc stereotype

Next, run the UML to Java transform by selecting the class in the diagram, right-clicking it and navigating to Transform > Run Transformation > UML to Java.

If you look in the Package Explorer, you will see that a file named HelloWorldJDK14FFDC.aj has been created, as shown in Figure 4.


Figure 4. The generated HelloWorldJDK14FFDC.aj file
The generated file

You will look at that file in more detail a little later.

To see the FFDC applied, run the application again. Note that the tracing aspect detailed in Using the Tracing aspect is still applied to the sayHello(), so you will also see the tracing output when you run the application. Since the last program to run was the HelloWorld application, you can rerun it by simply pressing the Run button on the toolbar (or navigate to Run > Run History > HelloWorld).

As before, the results are sent to the console. You will see now that there's an entry capturing the output from the FFDC aspect (see Listing 14).


Listing 14. Output from FFDC and Tracing aspects
        
Starting
? initLogger() logger=HelloWorld
? initLogger() traceEnabled=true
Hello World
Goodbye World
Finishing
21-Oct-2005 13:17:31 HelloWorld sayHello
FINER: ENTRY
21-Oct-2005 13:17:31 HelloWorld sayHello
FINER: RETURN Hello World
21-Oct-2005 13:17:31 org.aspectj.lib.logging.JDK14FFDC processNonStaticFFDC
WARNING: object=HelloWorld@400e699e, source=HelloWorld.sayGoodbye, line=25
java.lang.RuntimeException
    at HelloWorld.throwingMethod(HelloWorld.java:31)
    at HelloWorld.sayGoodbye(HelloWorld.java:24)
    at HelloWorld.main(HelloWorld.java:7)

How to apply FFDC to your own application

Unlike the Tracing aspect discussed in Using the Tracing aspect, you are generally going to want to apply FFDC to your entire application. This provides a consistent error handling policy, and also ensures that no errors are simply lost through programming mistakes. With the Aspects for MDD Framework, you are able to apply the Tracing aspect to classes in the same way as shown for methods.

Under the covers

If you have applied an aspect to part of your UML model, as already mentioned, an AspectJ aspect will be created in a .aj file as part of the UML to Java conversion process. The aspect created in the example process previously is shown in Listing 15 following.


Listing 15. HelloWorldJDK14FFDC.aj
        
public aspect HelloWorldJDK14FFDC extends 
                   org.aspectj.lib.logging.JDK14FFDC {

           protected pointcut ffdcScope () : 
                   withincode( * HelloWorld.sayGoodbye() );

}

As with the tracing aspect, the generated aspect extends another aspect, this time called JDK14FFDC. Part of that aspect is shown in Listing 16.


Listing 16. JDK14FFDC aspect
        
public abstract aspect JDK14FFDC extends FFDC {

    /** 
     * Method for consumption of raw FFDC in a 
     * static context
     */ 
    protected void processStaticFFDC(
            Throwable th, 
            JoinPoint.StaticPart tjp, 
            JoinPoint.StaticPart ejp) {
        Logger logger = Logger.getLogger(getLoggerName(ejp));
        logger.log(Level.WARNING,"source=" + getSourceId(ejp) 
                + ", line=" + getProbeId(tjp),th);
    }

    /** 
     * Method for consumption of raw FFDC in a 
     * non-static context
     */ 
    protected void processNonStaticFFDC(
            Throwable th, 
            Object obj, 
            JoinPoint.StaticPart tjp, 
            JoinPoint.StaticPart ejp) {
        Logger logger = Logger.getLogger(getLoggerName(ejp));
        logger.log(Level.WARNING,"object=" + obj 
                        + ", source=" 
                + getSourceId(ejp) + ", line=" 
                + getProbeId(tjp),th);
    }

    ...
}

The design of the FFDC aspect follows that of the Tracing aspect, and you can see that JDK14FFDC also extends another aspect, this time called FFDC. Part of this is shown in Listing 17.


Listing 17. FFDC aspect
        
public abstract aspect FFDC {
    
    /** 
     * Scope of FFDC policy e.g. packages, classes, methods 
     * is declared by sub-aspect.
     */ 
    protected abstract pointcut ffdcScope();
    
    private pointcut staticContext() : !this(Object);
    private pointcut nonStaticContext(Object obj) : this(obj);
    private pointcut caughtThrowable(Throwable th) : 
        handler(Throwable+) && args(th);

    /** 
     * Exclude FFDC aspects from exception reporting to avoid 
     * unwanted recursion
     */
    private pointcut excluded() : within(FFDC+);

    /** 
     * Advice for catch blocks in static context
     */
    before (Throwable th) : caughtThrowable(th) 
         && ffdcScope() && !excluded() && staticContext() {
       processStaticFFDC(th,
               thisJoinPointStaticPart,
               thisEnclosingJoinPointStaticPart);
    }

    /** 
     * Advice for catch blocks in non-static context. Extract 
     * the object that caught the exception
     */
    before (Throwable th, Object obj) : caughtThrowable(th) 
         && ffdcScope() && !excluded() && nonStaticContext(obj) {
       processNonStaticFFDC(th,
               obj,
               thisJoinPointStaticPart,
               thisEnclosingJoinPointStaticPart);
    }
    
    /** 
     * Method for consumption of raw FFDC in a 
     * static context
     */ 
    protected abstract void processStaticFFDC(
            Throwable th, 
            JoinPoint.StaticPart tjp, 
            JoinPoint.StaticPart ejp);

    /** 
     * Method for consumption of raw FFDC in a 
     * non-static context
     */ 
    protected abstract void processNonStaticFFDC(
            Throwable th, 
            Object obj, 
            JoinPoint.StaticPart tjp, 
            JoinPoint.StaticPart ejp);

    ...
}

Looking at the FFDC aspect, you'll see that there are two abstract methods processStaticFFDC and processNonStaticFFDC. These two methods are instantiated in the JDK14FFDC aspect shown in Listing 16, which logs the respective information.

Looking again at the FFDC aspect, notice that there is an abstract pointcut called ffdcScope, as shown in Listing 18.


Listing 18. Abstract pointcut ffdcScop()

/** 
 * Scope of FFDC policy e.g. packages, classes, methods is declared by
 * sub-aspect.
 */ 
protected abstract pointcut ffdcScope();

Now take another look at the generated HelloWorldJDKFFDC aspect shown in Listing 19.


Listing 19. Generated HelloWorldJDK14FFDC aspect

public aspect HelloWorldJDK14FFDC extends 
                   org.aspectj.lib.logging.JDK14FFDC {

           protected pointcut ffdcScope () : 
                   withincode( * HelloWorld.sayGoodbye() );

}

You can see that this provides a concrete implementation of the ffdcScope pointcut. More specifically, it says that the scope of the FFDC aspect should be within the sayGoodbye() method in the HelloWorld class, where sayGoodbye() takes no arguments (hence the "()") and has any return type.

You now know the scope that the FFDC aspect is interested in. However, you don't know what it's going to do here. This is detailed in the advice within the FFDC aspect, as seen in Listing 20.


Listing 20. Advice within the FFDC aspect

/** 
 * Advice for catch blocks in static context
 */
before (Throwable th) : caughtThrowable(th) 
      && ffdcScope() && !excluded() && staticContext() {
    processStaticFFDC(th,
           thisJoinPointStaticPart,
           thisEnclosingJoinPointStaticPart);
}

/** 
 * Advice for catch blocks in non-static context. Extract 
 * the object that caught the exception
 */
before (Throwable th, Object obj) : caughtThrowable(th) 
      && ffdcScope() && !excluded() && nonStaticContext(obj) {
    processNonStaticFFDC(th,
           obj,
           thisJoinPointStaticPart,
           thisEnclosingJoinPointStaticPart);
}

You see that the advice is before advice, which means it will be executed before the execution of the join point that meets the conditions of the pointcuts. Notice too that there is one for catch blocks in static contexts and one for non-static contexts. In the case of the static context, the pointcut expression is made up of several named pointcuts:

  • caughtThrowable
  • ffdcScope
  • excluded
  • staticContext

The only difference with the non-static case is that staticContext is replaced with nonStaticContext. These pointcuts are all defined in the FFDC aspect shown in Listing 21.


Listing 21. Pointcuts defined in the FFDC aspect

protected abstract pointcut ffdcScope();
    
private pointcut staticContext() : !this(Object);
private pointcut nonStaticContext(Object obj) : this(obj);
private pointcut caughtThrowable(Throwable th) : 
    handler(Throwable+) && args(th);

private pointcut excluded() : within(FFDC+);   

From the previous discussion, you already know what the ffdcScope pointcut does. Looking at each of the remaining four pointcuts in turn, following are their functions:

  • staticContext(): matches join points where "this" is unbound
  • nonStaticContext(Object obj): this is complementary to staticContext() and allows you to obtain a reference to the currently executing object.
  • caughtThrowable(Throwable th): this matches the handling of an exception of type Throwable. By using the args pointcut designator, you are able to expose the exception instance and use it in your reporting.
  • excluded(): this matches all join points within the FFDC aspect and any of its sub aspects. Including pointcuts like this helps to guard against recursion.

The advice shown previously in Listing 21 then composes these pointcuts depending on the context (static or non-static), and calls an implementation method that processes the information and ultimately prints it to the screen.


Conclusion

This article introduces the Aspects for MDD framework and shows how the com.ibm.aspectj.lib contribution can be used to enable Tracing and FFDC in MDD applications. As well as walking you through the required steps, the article has described in detail the contributed aspects, and discussed how these can be used within different applications.


Resources

Learn

Get products and technologies

  • The AJDT homepage: Download the latest version, find out what's new or get involved in the community.

  • The AspectJ homepage: Browse the documentation, get the latest news and downloads or join the AspectJ community.

  • Download the Aspects for MDD plug-in for Rational Software Architect. The plug-in is available from the RAS repository, under the "design_aspects" category. You can access the RAS repository directly from the Rational Software Architect tool. For more information about how to do this, visit the Pattern Solutions page, and view the text under the "Installing RAS asset" section.

Discuss

About the authors

Dr. Helen Hawkins is a developer within the IBM aspect-oriented software development team in Hursley, England, where she works on both the AspectJ and AJDT Eclipse projects. Before joining the team, she focused on testing (particularly stress testing) large software systems.

Sian January is a software engineer in the IBM Java Technology Centre in Hursley, England. She worked on the AJDT Eclipse.org project for three years after joining IBM in 2003. She has spoken about AspectJ in various venues, including the 2005 Eclipse Day in Nantes.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Rational
ArticleID=144283
ArticleTitle=Aspects for MDD: Aspect-Based Tracing and First Failure Data Capture in Rational Software Architect
publish-date=07112006
author1-email=hawkinsh@uk.ibm.com
author1-email-cc=
author2-email=sjanuary@uk.ibm.com
author2-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers