Recipe21.1.Applying Aspect-Oriented Tracing


Recipe 21.1. Applying Aspect-Oriented Tracing

Problem

You want to apply tracing to areas of your application using AspectJ.

Solution

Create an abstract base aspect, as shown in Example 21-1, to encapsulate the generic tracing logic. Extend the generic tracing aspect using specialized subaspects to include or exclude areas of your application from the tracing.

Example 21-1. An abstract tracing aspect that defines the generic tracing logic to be specialized for your application
import org.aspectj.lang.JoinPoint; public abstract aspect TracingAspect {       public abstract pointcut pointsToBeTraced( );        public abstract pointcut pointsToBeExcluded( );        public pointcut filteredPointsToBeTraced(Object caller) :        pointsToBeTraced( ) &&        !pointsToBeExcluded( ) &&        !within(com.oreilly.aspectjcookbook.tracing.TracingAspect+) &&        this(caller);        public pointcut catchStaticCallers( ) :        pointsToBeTraced( ) &&        !pointsToBeExcluded( ) &&        !within(com.oreilly.aspectjcookbook.tracing.TracingAspect+) &&        !filteredPointsToBeTraced(Object);        before(Object caller) : filteredPointsToBeTraced(caller)    {       traceBefore(thisJoinPoint, caller);    }        before( ) : catchStaticCallers( )    {       traceStaticBefore(thisJoinPoint);    }        after(Object caller) : filteredPointsToBeTraced(caller)    {       traceAfter(thisJoinPoint, caller);    }        after( ) : catchStaticCallers( )    {       traceStaticAfter(thisJoinPoint);    }        protected void traceBefore(JoinPoint joinPoint, Object caller)    {       System.out.println(caller + " calling " +              joinPoint.getSignature( ) + " @ " +              joinPoint.getSourceLocation( ));    }        protected void traceStaticBefore(JoinPoint joinPoint)    {       System.out.println("Static code calling " +              joinPoint.getSignature( ) + " @ " +              joinPoint.getSourceLocation( ));    }        protected void traceAfter(JoinPoint joinPoint, Object caller)    {       System.out.println("Returning from call to" +              joinPoint.getSignature( ) + " @ " +              joinPoint.getSourceLocation( ));    }        protected void traceStaticAfter(JoinPoint joinPoint)    {       System.out.println("Returning from static call to " +              joinPoint.getSignature( ) + " @ " +              joinPoint.getSourceLocation( ));    }        private static aspect FormatCallDepthAspect    {       private static int callDepth;              private pointcut captureTraceBefore( ) :           call(protected void TracingAspect.trace*Before(..));              private pointcut captureTraceAfter( ) :           call(protected void TracingAspect.trace*After(..));              after( ) : captureTraceBefore( )       {          callDepth++;       }              before( ) : captureTraceAfter( )       {          callDepth--;       }              private pointcut captureMessageOutput(String message) :           call(* *.println(String)) &&           args(message) &&          within(TracingAspect) &&          !within(FormatCallDepthAspect);              Object around(String originalMessage) : captureMessageOutput                                               (originalMessage)       {          StringBuffer buffer = new StringBuffer( );          for (int x = 0; x < callDepth; x++)          {             buffer.append("  ");          }          buffer.append(originalMessage);                    return proceed(buffer.toString( ));       }    } }

Discussion

The tracingAspect has a couple of abstract pointcuts, pointsToBeTraced( ) and pointsToBeExcluded( ) , to allow specialized subaspects to specify the areas of the target application to be subjected to the tracing.

The filteredPointsToBeTraced(Object) pointcut then combines the pointsToBeTraced( ) and pointsToBeExcluded( ) pointcuts along with logic for excluding the TRacingAspect itself and exposure of the calling object that triggered the tracing. This combined pointcut captures all of the join points to be traced within the target application that have a calling object. Unfortunately, the filteredPointsToBeTraced(Object) pointcut will exclude those join points that occur in a static code block because of the use of the this(TypePattern | Identifier) pointcut.

The catchStaticCallers() pointcut solves this problem by capturing all of the join points to be included in the tracing but not caught by the filteredPointsToBeTraced(Object) pointcut.

Two sets of before( ) and after( ) advice output the tracing messages to System.out. One set performs the message output for when the calling object is available; the other set does the same thing for when the calling object is not available.

If the tracingAspect was left at that, the tracing messages would be a little hard to read. It would be useful to format the tracing messages appropriately by indenting each message according to the current call depth. This turns out to be an aspect-wide cross-cutting concern because all of the advice blocks in the aspect will need to be affected with the appropriate formatting logic.

The FormatCallDepth inner aspect meets the formatting needs for all of the tracing messages across the tracingAspect aspect. The FormatCallDepth aspect keeps an internal count on the current call depth by monitoring when the tracingAspect performs before and after tracing. When the TRacingAspect makes a tracing call to System.out, the FormatCallDepth aspect amends the tracing message according to the current call depth.

Example 21-2 shows how the TRacingAspect aspect can be applied to an example application.

Example 21-2. Applying the TracingAspect to a specific example application
public aspect ApplicationSpecificTracingAspect extends TracingAspect {    public pointcut pointsToBeTraced( ) : call(* *.*(..));        public pointcut pointsToBeExcluded( ) : call(void java.io.                                            PrintStream.*(..)); }

See Also

The call(Signature) pointcut is described in Recipe 4.1; the within(TypePattern) pointcut is described in Recipe 9.1; the this(TypePattern | Identifier) pointcut is explained in Recipe 7.1; the args([TypePatterns || Identifiers]) pointcut is covered in Recipe 7.3; the AND (&&) operator and the OR (||) operator are described in Recipes 12.2 and 12.3 respectively; the before( ) form of advice is explained in Recipe 13.3; the around( ) form of advice, including using the proceed( ) method, is discussed in Recipe 13.4; the after( ) form of advice is explained in Recipe 13.5; using inheritance to implement abstract aspects is explained in Recipe 15.2; defining and using inner aspects is explained in Recipe 15.4.



AspectJ Cookbook
Aspectj Cookbook
ISBN: 0596006543
EAN: 2147483647
Year: 2006
Pages: 203
Authors: Russ Miles

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net