/usr/share/doc/aspectj-doc/progguide/examples-development.html is in aspectj-doc 1.8.3-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | <html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Development Aspects</title><link rel="stylesheet" type="text/css" href="aspectj-docs.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="The AspectJTM Programming Guide"><link rel="up" href="examples.html" title="Chapter 3. Examples"><link rel="prev" href="examples-basic.html" title="Basic Techniques"><link rel="next" href="examples-production.html" title="Production Aspects"></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">Development Aspects</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="examples-basic.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Examples</th><td width="20%" align="right"> <a accesskey="n" href="examples-production.html">Next</a></td></tr></table><hr></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="examples-development"></a>Development Aspects</h2></div></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="tracing-using-aspects"></a>Tracing using aspects</h3></div></div></div><p>
(The code for this example is in
<code class="filename"><em class="replaceable"><code>InstallDir</code></em>/examples/tracing</code>.)
</p><p>
Writing a class that provides tracing functionality is easy: a
couple of functions, a boolean flag for turning tracing on and
off, a choice for an output stream, maybe some code for
formatting the output -- these are all elements that
<code class="classname">Trace</code> classes have been known to
have. <code class="classname">Trace</code> classes may be highly
sophisticated, too, if the task of tracing the execution of a
program demands it.
</p><p>
But developing the support for tracing is just one part of the
effort of inserting tracing into a program, and, most likely, not
the biggest part. The other part of the effort is calling the
tracing functions at appropriate times. In large systems, this
interaction with the tracing support can be overwhelming. Plus,
tracing is one of those things that slows the system down, so
these calls should often be pulled out of the system before the
product is shipped. For these reasons, it is not unusual for
developers to write ad-hoc scripting programs that rewrite the
source code by inserting/deleting trace calls before and after
the method bodies.
</p><p>
AspectJ can be used for some of these tracing concerns in a less
ad-hoc way. Tracing can be seen as a concern that crosscuts the
entire system and as such is amenable to encapsulation in an
aspect. In addition, it is fairly independent of what the system
is doing. Therefore tracing is one of those kind of system
aspects that can potentially be plugged in and unplugged without
any side-effects in the basic functionality of the system.
</p><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="idp69267968"></a>An Example Application</h4></div></div></div><p>
Throughout this example we will use a simple application that
contains only four classes. The application is about shapes. The
<code class="classname">TwoDShape</code> class is the root of the shape
hierarchy:
</p><pre class="programlisting">
public abstract class TwoDShape {
protected double x, y;
protected TwoDShape(double x, double y) {
this.x = x; this.y = y;
}
public double getX() { return x; }
public double getY() { return y; }
public double distance(TwoDShape s) {
double dx = Math.abs(s.getX() - x);
double dy = Math.abs(s.getY() - y);
return Math.sqrt(dx*dx + dy*dy);
}
public abstract double perimeter();
public abstract double area();
public String toString() {
return (" @ (" + String.valueOf(x) + ", " + String.valueOf(y) + ") ");
}
}
</pre><p>
<code class="classname">TwoDShape</code> has two subclasses,
<code class="classname">Circle</code> and <code class="classname">Square</code>:
</p><pre class="programlisting">
public class Circle extends TwoDShape {
protected double r;
public Circle(double x, double y, double r) {
super(x, y); this.r = r;
}
public Circle(double x, double y) { this( x, y, 1.0); }
public Circle(double r) { this(0.0, 0.0, r); }
public Circle() { this(0.0, 0.0, 1.0); }
public double perimeter() {
return 2 * Math.PI * r;
}
public double area() {
return Math.PI * r*r;
}
public String toString() {
return ("Circle radius = " + String.valueOf(r) + super.toString());
}
}
</pre><pre class="programlisting">
public class Square extends TwoDShape {
protected double s; // side
public Square(double x, double y, double s) {
super(x, y); this.s = s;
}
public Square(double x, double y) { this( x, y, 1.0); }
public Square(double s) { this(0.0, 0.0, s); }
public Square() { this(0.0, 0.0, 1.0); }
public double perimeter() {
return 4 * s;
}
public double area() {
return s*s;
}
public String toString() {
return ("Square side = " + String.valueOf(s) + super.toString());
}
}
</pre><p>
To run this application, compile the classes. You can do it with or
without ajc, the AspectJ compiler. If you've installed AspectJ, go
to the directory
<code class="filename"><em class="replaceable"><code>InstallDir</code></em>/examples</code>
and type:
</p><pre class="programlisting">
ajc -argfile tracing/notrace.lst
</pre><p>To run the program, type</p><pre class="programlisting">
java tracing.ExampleMain
</pre><p>(we don't need anything special on the classpath since this is pure
Java code). You should see the following output:</p><pre class="programlisting">
c1.perimeter() = 12.566370614359172
c1.area() = 12.566370614359172
s1.perimeter() = 4.0
s1.area() = 1.0
c2.distance(c1) = 4.242640687119285
s1.distance(c1) = 2.23606797749979
s1.toString(): Square side = 1.0 @ (1.0, 2.0)
</pre></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="idp69279248"></a>Tracing—Version 1</h4></div></div></div><p>
In a first attempt to insert tracing in this application, we will
start by writing a <code class="classname">Trace</code> class that is
exactly what we would write if we didn't have aspects. The
implementation is in <code class="filename">version1/Trace.java</code>. Its
public interface is:
</p><pre class="programlisting">
public class Trace {
public static int TRACELEVEL = 0;
public static void initStream(PrintStream s) {...}
public static void traceEntry(String str) {...}
public static void traceExit(String str) {...}
}
</pre><p>
If we didn't have AspectJ, we would have to insert calls to
<code class="literal">traceEntry</code> and <code class="literal">traceExit</code> in
all methods and constructors we wanted to trace, and to initialize
<code class="literal">TRACELEVEL</code> and the stream. If we wanted to trace
all the methods and constructors in our example, that would amount
to around 40 calls, and we would hope we had not forgotten any
method. But we can do that more consistently and reliably with the
following aspect (found in
<code class="filename">version1/TraceMyClasses.java</code>):
</p><pre class="programlisting">
aspect TraceMyClasses {
pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square);
pointcut myConstructor(): myClass() && execution(new(..));
pointcut myMethod(): myClass() && execution(* *(..));
before (): myConstructor() {
Trace.traceEntry("" + thisJoinPointStaticPart.getSignature());
}
after(): myConstructor() {
Trace.traceExit("" + thisJoinPointStaticPart.getSignature());
}
before (): myMethod() {
Trace.traceEntry("" + thisJoinPointStaticPart.getSignature());
}
after(): myMethod() {
Trace.traceExit("" + thisJoinPointStaticPart.getSignature());
}
}</pre><p>
This aspect performs the tracing calls at appropriate
times. According to this aspect, tracing is performed at the
entrance and exit of every method and constructor defined within
the shape hierarchy.
</p><p>
What is printed at before and after each of the traced join points
is the signature of the method executing. Since the signature is
static information, we can get it through
<code class="literal">thisJoinPointStaticPart</code>.
</p><p>
To run this version of tracing, go to the directory
<code class="filename"><em class="replaceable"><code>InstallDir</code></em>/examples</code>
and type:
</p><pre class="programlisting">
ajc -argfile tracing/tracev1.lst
</pre><p>
Running the main method of
<code class="classname">tracing.version1.TraceMyClasses</code> should produce
the output:
</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><p>
When <code class="filename">TraceMyClasses.java</code> is not provided to
<span class="command"><strong>ajc</strong></span>, the aspect does not have any affect on the
system and the tracing is unplugged.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="idp69101968"></a>Tracing—Version 2</h4></div></div></div><p>
Another way to accomplish the same thing would be to write a
reusable tracing aspect that can be used not only for these
application classes, but for any class. One way to do this is to
merge the tracing functionality of
<code class="literal">Trace—version1</code> with the crosscutting
support of <code class="literal">TraceMyClasses—version1</code>. We end
up with a <code class="literal">Trace</code> aspect (found in
<code class="filename">version2/Trace.java</code>) with the following public
interface
</p><pre class="programlisting">
abstract aspect Trace {
public static int TRACELEVEL = 2;
public static void initStream(PrintStream s) {...}
protected static void traceEntry(String str) {...}
protected static void traceExit(String str) {...}
abstract pointcut myClass();
}
</pre><p>
In order to use it, we need to define our own subclass that knows
about our application classes, in
<code class="filename">version2/TraceMyClasses.java</code>:
</p><pre class="programlisting">
public aspect TraceMyClasses extends Trace {
pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square);
public static void main(String[] args) {
Trace.TRACELEVEL = 2;
Trace.initStream(System.err);
ExampleMain.main(args);
}
}
</pre><p>
Notice that we've simply made the pointcut
<code class="literal">classes</code>, that was an abstract pointcut in the
super-aspect, concrete. To run this version of tracing, go to the
directory <code class="filename">examples</code> and type:
</p><pre class="programlisting">
ajc -argfile tracing/tracev2.lst
</pre><p>
The file tracev2.lst lists the application classes as well as this
version of the files Trace.java and TraceMyClasses.java. Running
the main method of
<code class="classname">tracing.version2.TraceMyClasses</code> should
output exactly the same trace information as that from version 1.
</p><p>
The entire implementation of the new <code class="classname">Trace</code>
class is:
</p><pre class="programlisting">
abstract aspect Trace {
// implementation part
public static int TRACELEVEL = 2;
protected static PrintStream stream = System.err;
protected static int callDepth = 0;
public static void initStream(PrintStream s) {
stream = s;
}
protected static void traceEntry(String str) {
if (TRACELEVEL == 0) return;
if (TRACELEVEL == 2) callDepth++;
printEntering(str);
}
protected static void traceExit(String str) {
if (TRACELEVEL == 0) return;
printExiting(str);
if (TRACELEVEL == 2) callDepth--;
}
private static void printEntering(String str) {
printIndent();
stream.println("--> " + str);
}
private static void printExiting(String str) {
printIndent();
stream.println("<-- " + str);
}
private static void printIndent() {
for (int i = 0; i < callDepth; i++)
stream.print(" ");
}
// protocol part
abstract pointcut myClass();
pointcut myConstructor(): myClass() && execution(new(..));
pointcut myMethod(): myClass() && execution(* *(..));
before(): myConstructor() {
traceEntry("" + thisJoinPointStaticPart.getSignature());
}
after(): myConstructor() {
traceExit("" + thisJoinPointStaticPart.getSignature());
}
before(): myMethod() {
traceEntry("" + thisJoinPointStaticPart.getSignature());
}
after(): myMethod() {
traceExit("" + thisJoinPointStaticPart.getSignature());
}
}
</pre><p>
This version differs from version 1 in several subtle ways. The
first thing to notice is that this <code class="classname">Trace</code>
class merges the functional part of tracing with the crosscutting
of the tracing calls. That is, in version 1, there was a sharp
separation between the tracing support (the class
<code class="classname">Trace</code>) and the crosscutting usage of it (by
the class <code class="classname">TraceMyClasses</code>). In this version
those two things are merged. That's why the description of this
class explicitly says that "Trace messages are printed before and
after constructors and methods are," which is what we wanted in the
first place. That is, the placement of the calls, in this version,
is established by the aspect class itself, leaving less opportunity
for misplacing calls.</p><p>
A consequence of this is that there is no need for providing
<code class="literal">traceEntry</code> and <code class="literal">traceExit</code> as
public operations of this class. You can see that they were
classified as protected. They are supposed to be internal
implementation details of the advice.
</p><p>
The key piece of this aspect is the abstract pointcut classes that
serves as the base for the definition of the pointcuts constructors
and methods. Even though <code class="classname">classes</code> is
abstract, and therefore no concrete classes are mentioned, we can
put advice on it, as well as on the pointcuts that are based on
it. The idea is "we don't know exactly what the pointcut will be,
but when we do, here's what we want to do with it." In some ways,
abstract pointcuts are similar to abstract methods. Abstract
methods don't provide the implementation, but you know that the
concrete subclasses will, so you can invoke those methods.
</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="examples-basic.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="examples.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="examples-production.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Basic Techniques </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Production Aspects</td></tr></table></div></body></html>
|