|  | <html><head> | 
|  | <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> | 
|  | <title>Reusable Aspects</title><link rel="stylesheet" href="aspectj-docs.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.44"><link rel="home" href="index.html" title="The AspectJTM Programming Guide"><link rel="up" href="examples.html" title="Chapter 3. Examples"><link rel="previous" href="examples-production.html" title="Production Aspects"><link rel="next" href="idioms.html" title="Chapter 4. Idioms"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Reusable Aspects</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="examples-production.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Examples</th><td width="20%" align="right"> <a accesskey="n" href="idioms.html">Next</a></td></tr></table><hr></div><div class="sect1"><a name="examples-reusable"></a><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="examples-reusable"></a>Reusable Aspects</h2></div></div><div class="sect2"><a name="tracing-using-aspects-revisited"></a><div class="titlepage"><div><h3 class="title"><a name="tracing-using-aspects-revisited"></a>Tracing using Aspects, Revisited</h3></div></div><p> | 
|  | (The code for this example is in | 
|  | <tt><i><tt>InstallDir</tt></i>/examples/tracing</tt>.) | 
|  | </p><div class="sect3"><a name="d0e3374"></a><div class="titlepage"><div><h4 class="title"><a name="d0e3374"></a>Tracing—Version 3</h4></div></div><p> | 
|  | One advantage of not exposing the methods traceEntry and | 
|  | traceExit as public operations is that we can easily change their | 
|  | interface without any dramatic consequences in the rest of the | 
|  | code. | 
|  | </p><p> | 
|  | Consider, again, the program without AspectJ. Suppose, for | 
|  | example, that at some point later the requirements for tracing | 
|  | change, stating that the trace messages should always include the | 
|  | string representation of the object whose methods are being | 
|  | traced. This can be achieved in at least two ways. One way is | 
|  | keep the interface of the methods <tt>traceEntry</tt> | 
|  | and <tt>traceExit</tt> as it was before, | 
|  | </p><pre class="programlisting"> | 
|  | public static void traceEntry(String str); | 
|  | public static void traceExit(String str); | 
|  | </pre><p> | 
|  | In this case, the caller is responsible for ensuring that the | 
|  | string representation of the object is part of the string given | 
|  | as argument.  So, calls must look like: | 
|  | </p><pre class="programlisting"> | 
|  | Trace.traceEntry("Square.distance in " + toString()); | 
|  | </pre><p> | 
|  | Another way is to enforce the requirement with a second argument | 
|  | in the trace operations, e.g. | 
|  | </p><pre class="programlisting"> | 
|  | public static void traceEntry(String str, Object obj); | 
|  | public static void traceExit(String str, Object obj); | 
|  | </pre><p> | 
|  | In this case, the caller is still responsible for sending the | 
|  | right object, but at least there is some guarantees that some | 
|  | object will be passed. The calls will look like: | 
|  | </p><pre class="programlisting"> | 
|  | Trace.traceEntry("Square.distance", this); | 
|  | </pre><p> | 
|  | In either case, this change to the requirements of tracing will | 
|  | have dramatic consequences in the rest of the code -- every call | 
|  | to the trace operations traceEntry and traceExit must be changed! | 
|  | </p><p> | 
|  | Here's another advantage of doing tracing with an aspect. We've | 
|  | already seen that in version 2 <tt>traceEntry</tt> and | 
|  | <tt>traceExit</tt> are not publicly exposed. So | 
|  | changing their interfaces, or the way they are used, has only a | 
|  | small effect inside the <tt>Trace</tt> | 
|  | class. Here's a partial view at the implementation of | 
|  | <tt>Trace</tt>, version 3. The differences with | 
|  | respect to version 2 are stressed in the comments: | 
|  | </p><pre class="programlisting"> | 
|  | abstract aspect Trace { | 
|  |  | 
|  | public static int TRACELEVEL = 0; | 
|  | protected static PrintStream stream = null; | 
|  | protected static int callDepth = 0; | 
|  |  | 
|  | public static void initStream(PrintStream s) { | 
|  | stream = s; | 
|  | } | 
|  |  | 
|  | protected static void traceEntry(String str, Object o) { | 
|  | if (TRACELEVEL == 0) return; | 
|  | if (TRACELEVEL == 2) callDepth++; | 
|  | printEntering(str + ": " + o.toString()); | 
|  | } | 
|  |  | 
|  | protected static void traceExit(String str, Object o) { | 
|  | if (TRACELEVEL == 0) return; | 
|  | printExiting(str + ": " + o.toString()); | 
|  | if (TRACELEVEL == 2) callDepth--; | 
|  | } | 
|  |  | 
|  | private static void printEntering(String str) { | 
|  | printIndent(); | 
|  | stream.println("Entering " + str); | 
|  | } | 
|  |  | 
|  | private static void printExiting(String str) { | 
|  | printIndent(); | 
|  | stream.println("Exiting " + str); | 
|  | } | 
|  |  | 
|  | private static void printIndent() { | 
|  | for (int i = 0; i < callDepth; i++) | 
|  | stream.print("  "); | 
|  | } | 
|  |  | 
|  | abstract pointcut myClass(Object obj); | 
|  |  | 
|  | pointcut myConstructor(Object obj): myClass(obj) && execution(new(..)); | 
|  | pointcut myMethod(Object obj): myClass(obj) && | 
|  | execution(* *(..)) && !execution(String toString()); | 
|  |  | 
|  | before(Object obj): myConstructor(obj) { | 
|  | traceEntry("" + thisJoinPointStaticPart.getSignature(), obj); | 
|  | } | 
|  | after(Object obj): myConstructor(obj) { | 
|  | traceExit("" + thisJoinPointStaticPart.getSignature(), obj); | 
|  | } | 
|  |  | 
|  | before(Object obj): myMethod(obj) { | 
|  | traceEntry("" + thisJoinPointStaticPart.getSignature(), obj); | 
|  | } | 
|  | after(Object obj): myMethod(obj) { | 
|  | traceExit("" + thisJoinPointStaticPart.getSignature(), obj); | 
|  | } | 
|  | } | 
|  | </pre><p> | 
|  | As you can see, we decided to apply the first design by preserving | 
|  | the interface of the methods <tt>traceEntry</tt> and | 
|  | <tt>traceExit</tt>. But it doesn't matter—we could | 
|  | as easily have applied the second design (the code in the directory | 
|  | <tt>examples/tracing/version3</tt> has the second | 
|  | design).  The point is that the effects of this change in the | 
|  | tracing requirements are limited to the | 
|  | <tt>Trace</tt> aspect class. | 
|  | </p><p> | 
|  | One implementation change worth noticing is the specification of | 
|  | the pointcuts. They now expose the object. To maintain full | 
|  | consistency with the behavior of version 2, we should have included | 
|  | tracing for static methods, by defining another pointcut for static | 
|  | methods and advising it. We leave that as an exercise. | 
|  | </p><p> | 
|  | Moreover, we had to exclude the execution join point of the method | 
|  | <tt>toString</tt> from the <tt>methods</tt> | 
|  | pointcut. The problem here is that <tt>toString</tt> is | 
|  | being called from inside the advice.  Therefore if we trace it, we | 
|  | will end up in an infinite recursion of calls. This is a subtle | 
|  | point, and one that you must be aware when writing advice. If the | 
|  | advice calls back to the objects, there is always the possibility | 
|  | of recursion. Keep that in mind! | 
|  | </p><p> | 
|  | In fact, esimply excluding the execution join point may not be | 
|  | enough, if there are calls to other traced methods within it -- in | 
|  | which case, the restriction should be | 
|  | </p><pre class="programlisting"> | 
|  | && !cflow(execution(String toString())) | 
|  | </pre><p> | 
|  | excluding both the execution of toString methods and all join | 
|  | points under that execution. | 
|  | </p><p> | 
|  | In summary, to implement the change in the tracing requirements we | 
|  | had to make a couple of changes in the implementation of the | 
|  | <tt>Trace</tt> aspect class, including changing the | 
|  | specification of the pointcuts. That's only natural. But the | 
|  | implementation changes were limited to this aspect. Without | 
|  | aspects, we would have to change the implementation of every | 
|  | application class. | 
|  | </p><p> | 
|  | Finally, to run this version of tracing, go to the directory | 
|  | <tt>examples</tt> and type: | 
|  | </p><pre class="programlisting"> | 
|  | ajc -argfile tracing/tracev3.lst | 
|  | </pre><p> | 
|  | The file tracev3.lst lists the application classes as well as this | 
|  | version of the files <tt>Trace.java</tt> and | 
|  | <tt>TraceMyClasses.java</tt>. To run the program, type | 
|  | </p><pre class="programlisting"> | 
|  | java tracing.version3.TraceMyClasses | 
|  | </pre><p>The output should be:</p><pre class="programlisting"> | 
|  | --> tracing.TwoDShape(double, double) | 
|  | <-- tracing.TwoDShape(double, double) | 
|  | --> tracing.Circle(double, double, double) | 
|  | <-- tracing.Circle(double, double, double) | 
|  | --> tracing.TwoDShape(double, double) | 
|  | <-- tracing.TwoDShape(double, double) | 
|  | --> tracing.Circle(double, double, double) | 
|  | <-- tracing.Circle(double, double, double) | 
|  | --> tracing.Circle(double) | 
|  | <-- tracing.Circle(double) | 
|  | --> tracing.TwoDShape(double, double) | 
|  | <-- tracing.TwoDShape(double, double) | 
|  | --> tracing.Square(double, double, double) | 
|  | <-- tracing.Square(double, double, double) | 
|  | --> tracing.Square(double, double) | 
|  | <-- tracing.Square(double, double) | 
|  | --> double tracing.Circle.perimeter() | 
|  | <-- double tracing.Circle.perimeter() | 
|  | c1.perimeter() = 12.566370614359172 | 
|  | --> double tracing.Circle.area() | 
|  | <-- double tracing.Circle.area() | 
|  | c1.area() = 12.566370614359172 | 
|  | --> double tracing.Square.perimeter() | 
|  | <-- double tracing.Square.perimeter() | 
|  | s1.perimeter() = 4.0 | 
|  | --> double tracing.Square.area() | 
|  | <-- double tracing.Square.area() | 
|  | s1.area() = 1.0 | 
|  | --> double tracing.TwoDShape.distance(TwoDShape) | 
|  | --> double tracing.TwoDShape.getX() | 
|  | <-- double tracing.TwoDShape.getX() | 
|  | --> double tracing.TwoDShape.getY() | 
|  | <-- double tracing.TwoDShape.getY() | 
|  | <-- double tracing.TwoDShape.distance(TwoDShape) | 
|  | c2.distance(c1) = 4.242640687119285 | 
|  | --> double tracing.TwoDShape.distance(TwoDShape) | 
|  | --> double tracing.TwoDShape.getX() | 
|  | <-- double tracing.TwoDShape.getX() | 
|  | --> double tracing.TwoDShape.getY() | 
|  | <-- double tracing.TwoDShape.getY() | 
|  | <-- double tracing.TwoDShape.distance(TwoDShape) | 
|  | s1.distance(c1) = 2.23606797749979 | 
|  | --> String tracing.Square.toString() | 
|  | --> String tracing.TwoDShape.toString() | 
|  | <-- String tracing.TwoDShape.toString() | 
|  | <-- String tracing.Square.toString() | 
|  | s1.toString(): Square side = 1.0 @ (1.0, 2.0) | 
|  | </pre></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="examples-production.html">Prev</a> </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right"> <a accesskey="n" href="idioms.html">Next</a></td></tr><tr><td width="40%" align="left">Production Aspects </td><td width="20%" align="center"><a accesskey="u" href="examples.html">Up</a></td><td width="40%" align="right"> Chapter 4. Idioms</td></tr></table></div></body></html> |