~ubuntu-branches/ubuntu/natty/aspectj/natty

« back to all changes in this revision

Viewing changes to org.aspectj/modules/tests/incremental/injarSrc/two/twoSubdir/subdir/twoexamples.xml

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2009-10-04 16:37:23 UTC
  • mfrom: (1.1.3 upstream) (3.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20091004163723-ck4y7j7fhjxskkie
Tags: 1.6.6+dfsg-1
* New upstream release.
  - Update 02_use_gjdoc.diff patch
* Update my email address

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<chapter id="examples" xreflabel="Examples">
2
 
  <title>Examples</title>
3
 
 
4
 
  <sect1><!-- About this Chapter -->
5
 
    <title>About this Chapter</title>
6
 
 
7
 
    <para>This chapter consists entirely of examples of AspectJ use.
8
 
 
9
 
<!-- ADD THIS IN AGAIN WHEN IT'S TRUE
10
 
      The
11
 
      examples have been chosen because they illustrate common AspectJ usage
12
 
      patterns or techniques. Care has been taken to ensure that they also
13
 
      exhibit good style, in addition to being merely syntactically and
14
 
      semantically correct.
15
 
-->
16
 
</para>
17
 
 
18
 
    <para>The examples can be grouped into four categories:</para>
19
 
 
20
 
    <simplelist columns="2" type="horiz">
21
 
      <member><emphasis role="bold">technique</emphasis></member>
22
 
      <member>Examples which illustrate how to use one or more features of the
23
 
        language. </member>
24
 
 
25
 
      <member><emphasis role="bold">development</emphasis></member>
26
 
      <member>Examples of using AspectJ during the development phase of a
27
 
        project. </member>
28
 
 
29
 
      <member><emphasis role="bold">production</emphasis></member>
30
 
      <member>Examples of using AspectJ to provide functionality in an
31
 
        application. </member>
32
 
 
33
 
      <member><emphasis role="bold">reusable</emphasis></member>
34
 
      <member>Examples of reuse of aspects and pointcuts.</member>
35
 
    </simplelist>
36
 
 
37
 
  </sect1>
38
 
 
39
 
 
40
 
  <sect1>
41
 
    <title>Obtaining, Compiling and Running the Examples</title>
42
 
 
43
 
    <para>The examples source code is part of AspectJ's documentation
44
 
      distribution which may be downloaded from <ulink
45
 
        url="http://aspectj.org/dl">the AspectJ download page</ulink>.</para>
46
 
 
47
 
    <para>Compiling most examples should be straightforward. Go the
48
 
      <filename><replaceable>InstallDir</replaceable>/examples</filename>
49
 
      directory, and look for a <filename>.lst</filename> file in one of the
50
 
      example subdirectories. Use the <literal>-arglist</literal> option to
51
 
      <literal>ajc</literal> to compile the example. For instance, to compile
52
 
      the telecom example with billing, type </para>
53
 
 
54
 
<programlisting>
55
 
ajc -argfile telecom/billing.lst
56
 
</programlisting>
57
 
 
58
 
    <para>To run the examples, your classpath must include the AspectJ run-time
59
 
      Java archive (<literal>aspectjrt.jar</literal>). You may either set
60
 
      the <literal>CLASSPATH</literal> environment variable or use the
61
 
      <literal>-classpath</literal> command line option to the Java
62
 
      interpreter:</para>
63
 
 
64
 
<programlisting>
65
 
(In Unix use a : in the CLASSPATH)
66
 
java -classpath ".:<replaceable>InstallDir</replaceable>/lib/aspectjrt.jar" telecom.billingSimulation
67
 
</programlisting>
68
 
 
69
 
<programlisting>
70
 
(In Windows use a ; in the CLASSPATH)
71
 
java -classpath ".;<replaceable>InstallDir</replaceable>/lib/aspectjrt.jar" telecom.billingSimulation
72
 
</programlisting>
73
 
 
74
 
  </sect1>
75
 
 
76
 
 
77
 
<!--  ============================================================ -->
78
 
<!--  ============================================================ -->
79
 
 
80
 
 
81
 
  <sect1>
82
 
    <title>Basic Techniques</title>
83
 
 
84
 
    <para>This section presents two basic techniques of using AspectJ, one each
85
 
      from the two fundamental ways of capturing crosscutting concerns: with
86
 
      dynamic join points and advice, and with static introduction. Advice
87
 
      changes an application's behavior. Introduction changes both an
88
 
      application's behavior and its structure. </para>
89
 
 
90
 
    <para>The first example, <xref endterm="sec:JoinPointsAndtjp:title"
91
 
            linkend="sec:JoinPointsAndtjp"/>, is about gathering and using
92
 
      information about the join point that has triggered some advice. The
93
 
      second example, <xref endterm="sec:RolesAndViews:title"
94
 
            linkend="sec:RolesAndViews"/>, concerns changing an existing class
95
 
      hierarchy. </para>
96
 
 
97
 
<!--  ======================================== -->
98
 
 
99
 
    <sect2 id="sec:JoinPointsAndtjp"><!-- Join Points and thisJoinPoint -->
100
 
      <title>Join Points and <literal>thisJoinPoint</literal></title>
101
 
        <titleabbrev id="sec:JoinPointsAndtjp:title">Join Points and
102
 
          <literal>thisJoinPoint</literal></titleabbrev>
103
 
 
104
 
      <para>(The code for this example is in
105
 
      <filename><replaceable>InstallDir</replaceable>/examples/tjp</filename>.)</para>
106
 
 
107
 
      <para>A join point is some point in the
108
 
        execution of a program together with a view into the execution context
109
 
        when that point occurs. Join points are picked out by pointcuts. When a
110
 
        join point is reached, before, after or around advice on that join
111
 
        point may be run. </para>
112
 
 
113
 
      <para>When dealing with pointcuts that pick out join points of specific
114
 
      method calls, field gets, or the like, the advice will know exactly what
115
 
      kind of join point it is executing under.  It might even have access to
116
 
      context given by its pointcut.  Here, for example, since the only join
117
 
      points reached will be calls of a certain method, we can get the target
118
 
      and one of the args of the method directly.
119
 
      </para>
120
 
 
121
 
<programlisting><![CDATA[
122
 
before(Point p, int x): target(p)
123
 
                     && args(x)
124
 
                     && call(void setX(int)) {
125
 
    if (!p.assertX(x)) {
126
 
        System.out.println("Illegal value for x"); return;
127
 
    }
128
 
}
129
 
]]></programlisting>
130
 
 
131
 
   <para>But sometimes the join point is not so clear.  For
132
 
        instance, suppose a complex application is being debugged, and one
133
 
        would like to know when any method in some class is being executed.
134
 
        Then, the pointcut </para>
135
 
 
136
 
<programlisting><![CDATA[
137
 
pointcut execsInProblemClass(): within(ProblemClass)
138
 
                             && execution(* *(..));
139
 
]]></programlisting>
140
 
 
141
 
      <para>will select all join points where a method defined within the class
142
 
        <classname>ProblemClass</classname> is being executed. But advice
143
 
        executes when a particular join point is matched, and so the question,
144
 
        "Which join point was matched?" naturally arises.</para>
145
 
 
146
 
      <para>Information about the join point that was matched is available to
147
 
        advice through the special variable <varname>thisJoinPoint</varname>,
148
 
        of type <ulink
149
 
        url="../api/org/aspectj/lang/JoinPoint.html"><classname>org.aspectj.lang.JoinPoint</classname></ulink>. This
150
 
        class provides methods that return</para>
151
 
 
152
 
      <itemizedlist spacing="compact">
153
 
        <listitem>the kind of join point that was matched
154
 
        </listitem>
155
 
        <listitem>the source location of the current join point
156
 
        </listitem>
157
 
        <listitem>normal, short and long string representations of the
158
 
          current join point</listitem>
159
 
        <listitem>the actual argument(s) to the method or field selected
160
 
          by the current join point </listitem>
161
 
        <listitem>the signature of the method or field selected by the
162
 
            current join point</listitem>
163
 
        <listitem>the target object</listitem>
164
 
        <listitem>the currently executing object</listitem>
165
 
        <listitem>a reference to the static portion of the object
166
 
          representing the current join point.  This is also available through
167
 
          the special variable <varname>thisJoinPointStaticPart</varname>.</listitem>
168
 
 
169
 
      </itemizedlist>
170
 
 
171
 
      <sect3>
172
 
        <title>The <classname>Demo</classname> class</title>
173
 
 
174
 
          <para>The class <classname>tjp.Demo</classname> in
175
 
          <filename>tjp/Demo.java</filename> defines two methods
176
 
            <literal>foo</literal> and <literal>bar</literal> with different
177
 
            parameter lists and return types. Both are called, with suitable
178
 
            arguments, by <classname>Demo</classname>'s <function>go</function>
179
 
            method which was invoked from within its <function>main</function>
180
 
            method. </para>
181
 
 
182
 
<programlisting><![CDATA[
183
 
public class Demo {
184
 
 
185
 
    static Demo d;
186
 
 
187
 
    public static void main(String[] args){
188
 
        new Demo().go();
189
 
    }
190
 
 
191
 
    void go(){
192
 
        d = new Demo();
193
 
        d.foo(1,d);
194
 
        System.out.println(d.bar(new Integer(3)));
195
 
    }
196
 
 
197
 
    void foo(int i, Object o){
198
 
        System.out.println("Demo.foo(" + i + ", " + o + ")\n");
199
 
    }
200
 
 
201
 
 
202
 
    String bar (Integer j){
203
 
        System.out.println("Demo.bar(" + j + ")\n");
204
 
        return "Demo.bar(" + j  + ")";
205
 
    }
206
 
 
207
 
}
208
 
]]></programlisting>
209
 
 
210
 
      </sect3>
211
 
 
212
 
      <sect3>
213
 
        <title>The Aspect <literal>GetInfo</literal></title>
214
 
 
215
 
        <para>This aspect uses around advice to intercept the execution of
216
 
          methods <literal>foo</literal> and <literal>bar</literal> in
217
 
          <classname>Demo</classname>, and prints out information garnered from
218
 
          <literal>thisJoinPoint</literal> to the console. </para>
219
 
 
220
 
        <sect4>
221
 
          <title>Defining the scope of a pointcut</title>
222
 
 
223
 
          <para>The pointcut <function>goCut</function> is defined as
224
 
            <literal><![CDATA[cflow(this(Demo)) && execution(void
225
 
              go())]]></literal> so that only executions made in the control
226
 
            flow of <literal>Demo.go</literal> are intercepted. The control
227
 
            flow from the method <literal>go</literal> includes the execution of
228
 
            <literal>go</literal> itself, so the definition of the around
229
 
            advice includes <literal>!execution(* go())</literal> to exclude it
230
 
            from the set of executions advised. </para>
231
 
        </sect4>
232
 
 
233
 
        <sect4>
234
 
          <title>Printing the class and method name</title>
235
 
 
236
 
          <para>The name of the method and that method's defining class are
237
 
            available as parts of the <ulink
238
 
              url="../api/org/aspectj/lang/Signature.html">Signature</ulink>,
239
 
            found using the method <literal>getSignature</literal> of either
240
 
            <literal>thisJoinPoint</literal> or
241
 
            <literal>thisJoinPointStaticPart</literal>. </para>
242
 
 
243
 
<programlisting><![CDATA[
244
 
aspect GetInfo {
245
 
 
246
 
   static final void println(String s){ System.out.println(s); }
247
 
 
248
 
   pointcut goCut(): cflow(this(Demo) && execution(void go()));
249
 
 
250
 
   pointcut demoExecs(): within(Demo) && execution(* *(..));
251
 
 
252
 
   Object around(): demoExecs() && !execution(* go()) && goCut() {
253
 
      println("Intercepted message: " +
254
 
          thisJoinPointStaticPart.getSignature().getName());
255
 
      println("in class: " +
256
 
          thisJoinPointStaticPart.getSignature().getDeclaringType().getName());
257
 
      printParameters(thisJoinPoint);
258
 
      println("Running original method: \n" );
259
 
      Object result = proceed();
260
 
      println("  result: " + result );
261
 
      return result;
262
 
   }
263
 
 
264
 
   static private void printParameters(JoinPoint jp) {
265
 
      println("Arguments: " );
266
 
      Object[] args = jp.getArgs();
267
 
      String[] names = ((CodeSignature)jp.getSignature()).getParameterNames();
268
 
      Class[] types = ((CodeSignature)jp.getSignature()).getParameterTypes();
269
 
      for (int i = 0; i < args.length; i++) {
270
 
         println("  "  + i + ". " + names[i] +
271
 
             " : " +            types[i].getName() +
272
 
             " = " +            args[i]);
273
 
      }
274
 
   }
275
 
}
276
 
]]></programlisting>
277
 
        </sect4>
278
 
 
279
 
        <sect4>
280
 
          <title>Printing the parameters</title>
281
 
 
282
 
          <para>
283
 
            The static portions of the parameter details, the name and
284
 
            types of the parameters, can be accessed through the <ulink
285
 
              url="../api/org/aspectj/lang/reflect/CodeSignature.html"><literal>CodeSignature</literal></ulink>
286
 
            associated with the join point. All execution join points have code
287
 
            signatures, so the cast to <literal>CodeSignature</literal>
288
 
            cannot fail. </para>
289
 
 
290
 
          <para>
291
 
            The dynamic portions of the parameter details, the actual
292
 
            values of the parameters, are accessed directly from the execution
293
 
            join point object. </para>
294
 
        </sect4>
295
 
      </sect3>
296
 
    </sect2>
297
 
 
298
 
    <sect2 id="sec:RolesAndViews">
299
 
      <title>Roles and Views Using Introduction</title>
300
 
      <titleabbrev id="sec:RolesAndViews:title">Roles and Views Using
301
 
        Introduction</titleabbrev>
302
 
 
303
 
      <para>(The code for this example is in
304
 
      <filename><replaceable>InstallDir</replaceable>/examples/introduction</filename>.)</para>
305
 
 
306
 
      <para>Like advice, pieces of introduction are members of an aspect. They
307
 
        define new members that act as if they were defined on another
308
 
        class. Unlike advice, introduction affects not only the behavior of the
309
 
        application, but also the structural relationship between an
310
 
        application's classes. </para>
311
 
 
312
 
      <para>This is crucial: Affecting the class structure of an application at
313
 
        makes these modifications available to other components of the
314
 
        application.</para>
315
 
 
316
 
      <para>Introduction modifies a class by adding or changing</para>
317
 
      <itemizedlist spacing="compact">
318
 
        <listitem>member fields</listitem>
319
 
        <listitem>member methods</listitem>
320
 
        <listitem>nested classes</listitem>
321
 
      </itemizedlist>
322
 
 
323
 
      <para>and by making the class</para>
324
 
 
325
 
      <itemizedlist spacing="compact">
326
 
        <listitem>implement interfaces</listitem>
327
 
        <listitem>extend classes</listitem>
328
 
      </itemizedlist>
329
 
 
330
 
      <para>
331
 
        This example provides three illustrations of the use of introduction to
332
 
        encapsulate roles or views of a class. The class we will be introducing
333
 
        into, <classname>Point</classname>, is a simple class with rectangular
334
 
        and polar coordinates. Our introduction will make the class
335
 
        <classname>Point</classname>, in turn, cloneable, hashable, and
336
 
        comparable. These facilities are provided by introduction forms without
337
 
        having to modify the class <classname>Point</classname>.
338
 
        </para>
339
 
 
340
 
      <sect3>
341
 
        <title>The class <classname>Point</classname></title>
342
 
 
343
 
        <para>The class <classname>Point</classname> defines geometric points
344
 
          whose interface includes polar and rectangular coordinates, plus some
345
 
          simple operations to relocate points. <classname>Point</classname>'s
346
 
          implementation has attributes for both its polar and rectangular
347
 
          coordinates, plus flags to indicate which currently reflect the
348
 
          position of the point. Some operations cause the polar coordinates to
349
 
          be updated from the rectangular, and some have the opposite effect.
350
 
          This implementation, which is in intended to give the minimum number
351
 
          of conversions between coordinate systems, has the property that not
352
 
          all the attributes stored in a <classname>Point</classname> object
353
 
          are necessary to give a canonical representation such as might be
354
 
          used for storing, comparing, cloning or making hash codes from
355
 
          points. Thus the aspects, though simple, are not totally trivial.
356
 
        </para>
357
 
 
358
 
        <para>
359
 
          The diagram below gives an overview of the aspects and their
360
 
          interaction with the class <classname>Point</classname>.</para>
361
 
 
362
 
        <para>
363
 
          <inlinemediaobject>
364
 
            <imageobject>
365
 
              <imagedata fileref="aspects.gif"/>
366
 
            </imageobject>
367
 
          </inlinemediaobject>
368
 
        </para>
369
 
        <para></para>
370
 
 
371
 
      </sect3>
372
 
 
373
 
      <sect3>
374
 
        <title>Making <classname>Point</classname>s Cloneable &mdash; The Aspect
375
 
          <classname>CloneablePoint</classname></title>
376
 
 
377
 
        <para>This first example demonstrates the introduction of a interface
378
 
          (<classname>Cloneable</classname>) and a method
379
 
          (<function>clone</function>) into the class
380
 
          <classname>Point</classname>. In Java, all objects inherit the method
381
 
          <literal>clone</literal> from the class
382
 
          <classname>Object</classname>, but an object is not cloneable unless
383
 
          its class also implements the interface
384
 
          <classname>Cloneable</classname>. In addition, classes frequently
385
 
          have requirements over and above the simple bit-for-bit copying that
386
 
          <literal>Object.clone</literal> does. In our case, we want to update
387
 
          a <classname>Point</classname>'s coordinate systems before we
388
 
          actually clone the <classname>Point</classname>. So we have to
389
 
          override <literal>Object.clone</literal> with a new method that does
390
 
          what we want. </para>
391
 
 
392
 
        <para>The <classname>CloneablePoint</classname> aspect uses the
393
 
          <literal>declare parents</literal> form to introduce the interface
394
 
          <classname>Cloneable</classname> into the class
395
 
          <classname>Point</classname>. It then defines a method,
396
 
          <literal>Point.clone</literal>, which overrides the method
397
 
          <function>clone</function> that was inherited from
398
 
          <classname>Object</classname>. <function>Point.clone</function>
399
 
          updates the <classname>Point</classname>'s coordinate systems before
400
 
          invoking its superclass' <function>clone</function> method.</para>
401
 
 
402
 
        <programlisting><![CDATA[
403
 
public aspect CloneablePoint {
404
 
 
405
 
   declare parents: Point implements Cloneable;
406
 
 
407
 
   public Object Point.clone() throws CloneNotSupportedException {
408
 
      // we choose to bring all fields up to date before cloning.
409
 
      makeRectangular();
410
 
      makePolar();
411
 
      return super.clone();
412
 
   }
413
 
 
414
 
   public static void main(String[] args){
415
 
      Point p1 = new Point();
416
 
      Point p2 = null;
417
 
 
418
 
      p1.setPolar(Math.PI, 1.0);
419
 
      try {
420
 
         p2 = (Point)p1.clone();
421
 
      } catch (CloneNotSupportedException e) {}
422
 
      System.out.println("p1 =" + p1 );
423
 
      System.out.println("p2 =" + p2 );
424
 
 
425
 
      p1.rotate(Math.PI / -2);
426
 
      System.out.println("p1 =" + p1 );
427
 
      System.out.println("p2 =" + p2 );
428
 
   }
429
 
}
430
 
]]></programlisting>
431
 
 
432
 
        <para>Note that since aspects define types just as classes define
433
 
          types, we can define a <function>main</function> method that is
434
 
          invocable from the command line to use as a test method.</para>
435
 
      </sect3>
436
 
 
437
 
      <sect3>
438
 
        <title>Making <classname>Point</classname>s Comparable &mdash; The
439
 
          Aspect <classname>ComparablePoint</classname></title>
440
 
 
441
 
        <para>This second example introduces another interface and
442
 
          method into the class <classname>Point</classname>.</para>
443
 
 
444
 
        <para>The interface <classname>Comparable</classname> defines the
445
 
          single method <literal>compareTo</literal> which can be use to define
446
 
          a natural ordering relation among the objects of a class that
447
 
          implement it. </para>
448
 
 
449
 
        <para>The aspect <classname>ComparablePoint</classname> introduces
450
 
          implements <classname>Comparable</classname> into
451
 
          <classname>Point</classname> along with a
452
 
          <literal>compareTo</literal> method that can be used to compare
453
 
          <classname>Point</classname>s. A <classname>Point</classname>
454
 
          <literal>p1</literal> is  said to be less than
455
 
          another <classname>Point</classname><literal> p2</literal> if
456
 
          <literal>p1</literal> is closer to the origin. </para>
457
 
 
458
 
        <programlisting><![CDATA[
459
 
public aspect ComparablePoint {
460
 
 
461
 
   declare parents: Point implements Comparable;
462
 
 
463
 
   public int Point.compareTo(Object o) {
464
 
      return (int) (this.getRho() - ((Point)o).getRho());
465
 
   }
466
 
 
467
 
   public static void main(String[] args){
468
 
      Point p1 = new Point();
469
 
      Point p2 = new Point();
470
 
 
471
 
      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
472
 
 
473
 
      p1.setRectangular(2,5);
474
 
      p2.setRectangular(2,5);
475
 
      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
476
 
 
477
 
      p2.setRectangular(3,6);
478
 
      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
479
 
 
480
 
      p1.setPolar(Math.PI, 4);
481
 
      p2.setPolar(Math.PI, 4);
482
 
      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
483
 
 
484
 
      p1.rotate(Math.PI / 4.0);
485
 
      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
486
 
 
487
 
      p1.offset(1,1);
488
 
      System.out.println("p1 =?= p2 :" + p1.compareTo(p2));
489
 
   }
490
 
}]]></programlisting>
491
 
      </sect3>
492
 
 
493
 
      <sect3>
494
 
        <title>Making <classname>Point</classname>s Hashable &mdash; The Aspect
495
 
          <classname>HashablePoint</classname></title>
496
 
 
497
 
        <para>The third aspect overrides two previously defined methods to
498
 
          give to <classname>Point</classname> the hashing behavior we
499
 
          want.</para>
500
 
 
501
 
        <para>The method <literal>Object.hashCode</literal> returns an unique
502
 
          integer, suitable for use as a hash table key. Different
503
 
          implementations are allowed return different integers, but must
504
 
          return distinct integers for distinct objects, and the same integer
505
 
          for objects that test equal. But since the default implementation
506
 
          of <literal>Object.equal</literal> returns <literal>true</literal>
507
 
          only when two objects are identical, we need to redefine both
508
 
          <function>equals</function> and <function>hashCode</function> to work
509
 
          correctly with objects of type <classname>Point</classname>. For
510
 
          example, we want two <classname>Point</classname> objects to test
511
 
          equal when they have the same <literal>x</literal> and
512
 
          <literal>y</literal> values, or the same <literal>rho</literal> and
513
 
          <literal>theta</literal> values, not just when they refer to the same
514
 
          object. We do this by overriding the methods
515
 
          <literal>equals</literal> and <literal>hashCode</literal> in the
516
 
          class <classname>Point</classname>. </para>
517
 
 
518
 
        <para>The class <classname>HashablePoint</classname> introduces the
519
 
          methods <literal>hashCode</literal> and <literal>equals</literal>
520
 
          into the class <classname>Point</classname>. These methods use
521
 
          <classname>Point</classname>'s rectangular coordinates to generate a
522
 
          hash code and to test for equality. The <literal>x</literal> and
523
 
          <literal>y</literal> coordinates are obtained using the appropriate
524
 
          get methods, which ensure the rectangular coordinates are up-to-date
525
 
          before returning their values. </para>
526
 
 
527
 
        <programlisting><![CDATA[
528
 
public aspect HashablePoint {
529
 
 
530
 
   public int Point.hashCode() {
531
 
      return (int) (getX() + getY() % Integer.MAX_VALUE);
532
 
   }
533
 
 
534
 
   public boolean Point.equals(Object o) {
535
 
      if (o == this) { return true; }
536
 
      if (!(o instanceof Point)) { return false; }
537
 
      Point other = (Point)o;
538
 
      return (getX() == other.getX()) && (getY() == other.getY());
539
 
   }
540
 
 
541
 
   public static void main(String[] args) {
542
 
      Hashtable h = new Hashtable();
543
 
      Point p1 = new Point();
544
 
 
545
 
      p1.setRectangular(10, 10);
546
 
      Point p2 = new Point();
547
 
 
548
 
      p2.setRectangular(10, 10);
549
 
 
550
 
      System.out.println("p1 = " + p1);
551
 
      System.out.println("p2 = " + p2);
552
 
      System.out.println("p1.hashCode() = " + p1.hashCode());
553
 
      System.out.println("p2.hashCode() = " + p2.hashCode());
554
 
 
555
 
      h.put(p1, "P1");
556
 
      System.out.println("Got: " + h.get(p2));
557
 
   }
558
 
}
559
 
]]></programlisting>
560
 
 
561
 
        <para> Again, we supply a <literal>main</literal> method in the aspect
562
 
        for testing.
563
 
        </para>
564
 
 
565
 
      </sect3>
566
 
 
567
 
    </sect2>
568
 
 
569
 
  </sect1>
570
 
 
571
 
<!--  ============================================================ -->
572
 
<!--  ============================================================ -->
573
 
 
574
 
  <sect1>
575
 
    <title>Development Aspects</title>
576
 
 
577
 
  <sect2>
578
 
    <title>Tracing Aspects</title>
579
 
 
580
 
      <para>(The code for this example is in
581
 
      <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.)
582
 
      </para>
583
 
 
584
 
    <sect3>
585
 
      <title>Overview</title>
586
 
 
587
 
        <para>
588
 
        Writing a class that provides tracing functionality is easy: a couple
589
 
        of functions, a boolean flag for turning tracing on and off, a choice
590
 
        for an output stream, maybe some code for formatting the output---these
591
 
        are all elements that <classname>Trace</classname> classes have been
592
 
        known to have. <classname>Trace</classname> classes may be highly
593
 
        sophisticated, too, if the task of tracing the execution of a program
594
 
        demands so.
595
 
      </para>
596
 
 
597
 
      <para>
598
 
        But developing the support for tracing is just one part of the effort
599
 
        of inserting tracing into a program, and, most likely, not the biggest
600
 
        part. The other part of the effort is calling the tracing functions at
601
 
        appropriate times. In large systems, this interaction with the tracing
602
 
        support can be overwhelming.  Plus, tracing is one of those things that
603
 
        slows the system down, so these calls should often be pulled out of the
604
 
        system before the product is shipped. For these reasons, it is not
605
 
        unusual for developers to write ad-hoc scripting programs that rewrite
606
 
        the source code by inserting/deleting trace calls before and after the
607
 
        method bodies.
608
 
      </para>
609
 
 
610
 
      <para>
611
 
        AspectJ can be used for some of these tracing concerns in a less ad-hoc
612
 
        way.  Tracing can be seen as a concern that crosscuts the entire system
613
 
        and as such is amenable to encapsulation in an aspect.  In addition, it
614
 
        is fairly independent of what the system is doing. Therefore tracing is
615
 
        one of those kind of system aspects that can potentially be plugged in
616
 
        and unplugged without any side-effects in the basic functionality of
617
 
        the system.
618
 
      </para>
619
 
    </sect3>
620
 
 
621
 
    <sect3>
622
 
      <title>An Example Application</title>
623
 
 
624
 
      <para>
625
 
        Throughout this example we will use a simple application that contains
626
 
        only four classes. The application is about shapes. The
627
 
        <classname>TwoDShape</classname> class is the root of the shape
628
 
        hierarchy:
629
 
      </para>
630
 
 
631
 
<programlisting><![CDATA[
632
 
public abstract class TwoDShape {
633
 
    protected double x, y;
634
 
    protected TwoDShape(double x, double y) {
635
 
        this.x = x; this.y = y;
636
 
    }
637
 
    public double getX() { return x; }
638
 
    public double getY() { return y; }
639
 
    public double distance(TwoDShape s) {
640
 
        double dx = Math.abs(s.getX() - x);
641
 
        double dy = Math.abs(s.getY() - y);
642
 
        return Math.sqrt(dx*dx + dy*dy);
643
 
    }
644
 
    public abstract double perimeter();
645
 
    public abstract double area();
646
 
    public String toString() {
647
 
        return (" @ (" + String.valueOf(x) + ", " + String.valueOf(y) + ") ");
648
 
    }
649
 
}
650
 
]]></programlisting>
651
 
 
652
 
      <para>
653
 
        <classname>TwoDShape</classname> has two subclasses,
654
 
        <classname>Circle</classname> and <classname>Square</classname>:
655
 
      </para>
656
 
 
657
 
<programlisting><![CDATA[
658
 
public class Circle extends TwoDShape {
659
 
    protected double r;
660
 
    public Circle(double x, double y, double r) {
661
 
        super(x, y); this.r = r;
662
 
    }
663
 
    public Circle(double x, double y) { this(  x,   y, 1.0); }
664
 
    public Circle(double r)           { this(0.0, 0.0,   r); }
665
 
    public Circle()                   { this(0.0, 0.0, 1.0); }
666
 
    public double perimeter() {
667
 
        return 2 * Math.PI * r;
668
 
    }
669
 
    public double area() {
670
 
        return Math.PI * r*r;
671
 
    }
672
 
    public String toString() {
673
 
        return ("Circle radius = " + String.valueOf(r) + super.toString());
674
 
    }
675
 
}
676
 
]]></programlisting>
677
 
 
678
 
<programlisting><![CDATA[
679
 
public class Square extends TwoDShape {
680
 
    protected double s;    // side
681
 
    public Square(double x, double y, double s) {
682
 
        super(x, y); this.s = s;
683
 
    }
684
 
    public Square(double x, double y) { this(  x,   y, 1.0); }
685
 
    public Square(double s)           { this(0.0, 0.0,   s); }
686
 
    public Square()                   { this(0.0, 0.0, 1.0); }
687
 
    public double perimeter() {
688
 
        return 4 * s;
689
 
    }
690
 
    public double area() {
691
 
        return s*s;
692
 
    }
693
 
    public String toString() {
694
 
        return ("Square side = " + String.valueOf(s) + super.toString());
695
 
    }
696
 
}
697
 
]]></programlisting>
698
 
 
699
 
      <para>
700
 
        To run this application, compile the classes. You can do it with or
701
 
        without ajc, the AspectJ compiler. If you've installed AspectJ, go to
702
 
        the directory
703
 
        <filename><replaceable>InstallDir</replaceable>/examples</filename> and
704
 
        type:
705
 
      </para>
706
 
 
707
 
<programlisting>
708
 
ajc -argfile tracing/notrace.lst
709
 
</programlisting>
710
 
 
711
 
      <para>To run the program, type</para>
712
 
 
713
 
<programlisting>
714
 
java tracing.ExampleMain
715
 
</programlisting>
716
 
 
717
 
      <para>(we don't need anything special on the classpath since this is pure
718
 
      Java code).  You should see the following output:</para>
719
 
 
720
 
<programlisting><![CDATA[
721
 
c1.perimeter() = 12.566370614359172
722
 
c1.area() = 12.566370614359172
723
 
s1.perimeter() = 4.0
724
 
s1.area() = 1.0
725
 
c2.distance(c1) = 4.242640687119285
726
 
s1.distance(c1) = 2.23606797749979
727
 
s1.toString(): Square side = 1.0 @ (1.0, 2.0)
728
 
]]></programlisting>
729
 
 
730
 
      </sect3>
731
 
    <sect3>
732
 
      <title>Tracing&mdash;Version 1</title>
733
 
 
734
 
      <para>
735
 
        In a first attempt to insert tracing in this application, we will start
736
 
        by writing a <classname>Trace</classname> class that is exactly what we
737
 
        would write if we didn't have aspects.  The implementation is in
738
 
        <filename>version1/Trace.java</filename>.  Its public interface is:
739
 
      </para>
740
 
 
741
 
<programlisting><![CDATA[
742
 
public class Trace {
743
 
    public static int TRACELEVEL = 0;
744
 
    public static void initStream(PrintStream s) {...}
745
 
    public static void traceEntry(String str) {...}
746
 
    public static void traceExit(String str) {...}
747
 
}
748
 
]]></programlisting>
749
 
 
750
 
      <para>
751
 
        If we didn't have AspectJ, we would have to insert calls to
752
 
        <literal>traceEntry</literal> and <literal>traceExit</literal> in all
753
 
        methods and constructors we wanted to trace, and to initialize
754
 
        <literal>TRACELEVEL</literal> and the stream. If we wanted to trace all
755
 
        the methods and constructors in our example, that would amount to
756
 
        around 40 calls, and we would hope we had not forgotten any method. But
757
 
        we can do that more consistently and reliably with the following
758
 
        aspect (found in <filename>version1/TraceMyClasses.java</filename>):
759
 
      </para>
760
 
 
761
 
<programlisting><![CDATA[
762
 
aspect TraceMyClasses {
763
 
    pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square);
764
 
    pointcut myConstructor(): myClass() && execution(new(..));
765
 
    pointcut myMethod(): myClass() && execution(* *(..));
766
 
 
767
 
    before (): myConstructor() {
768
 
        Trace.traceEntry("" + thisJoinPointStaticPart.getSignature());
769
 
    }
770
 
    after(): myConstructor() {
771
 
        Trace.traceExit("" + thisJoinPointStaticPart.getSignature());
772
 
    }
773
 
 
774
 
    before (): myMethod() {
775
 
        Trace.traceEntry("" + thisJoinPointStaticPart.getSignature());
776
 
    }
777
 
    after(): myMethod() {
778
 
        Trace.traceExit("" + thisJoinPointStaticPart.getSignature());
779
 
    }
780
 
}]]></programlisting>
781
 
 
782
 
      <para>
783
 
        This aspect performs the tracing calls at appropriate times. According
784
 
        to this aspect, tracing is performed at the entrance and exit of every
785
 
        method and constructor defined within the shape hierarchy.
786
 
      </para>
787
 
 
788
 
      <para>
789
 
        What is printed at before and after each of the traced
790
 
        join points is the signature of the method executing. Since the
791
 
        signature is static information, we can get it through
792
 
        <literal>thisJoinPointStaticPart</literal>.
793
 
      </para>
794
 
 
795
 
      <para>
796
 
        To run this version of tracing, go to the directory
797
 
        <filename><replaceable>InstallDir</replaceable>/examples</filename> and
798
 
        type:
799
 
      </para>
800
 
 
801
 
<programlisting><![CDATA[
802
 
  ajc -argfile tracing/tracev1.lst
803
 
]]></programlisting>
804
 
 
805
 
      <para>
806
 
        Running the main method of
807
 
        <classname>tracing.version1.TraceMyClasses</classname> should produce
808
 
        the output:
809
 
      </para>
810
 
 
811
 
<programlisting><![CDATA[
812
 
  --> tracing.TwoDShape(double, double)
813
 
  <-- tracing.TwoDShape(double, double)
814
 
  --> tracing.Circle(double, double, double)
815
 
  <-- tracing.Circle(double, double, double)
816
 
  --> tracing.TwoDShape(double, double)
817
 
  <-- tracing.TwoDShape(double, double)
818
 
  --> tracing.Circle(double, double, double)
819
 
  <-- tracing.Circle(double, double, double)
820
 
  --> tracing.Circle(double)
821
 
  <-- tracing.Circle(double)
822
 
  --> tracing.TwoDShape(double, double)
823
 
  <-- tracing.TwoDShape(double, double)
824
 
  --> tracing.Square(double, double, double)
825
 
  <-- tracing.Square(double, double, double)
826
 
  --> tracing.Square(double, double)
827
 
  <-- tracing.Square(double, double)
828
 
  --> double tracing.Circle.perimeter()
829
 
  <-- double tracing.Circle.perimeter()
830
 
c1.perimeter() = 12.566370614359172
831
 
  --> double tracing.Circle.area()
832
 
  <-- double tracing.Circle.area()
833
 
c1.area() = 12.566370614359172
834
 
  --> double tracing.Square.perimeter()
835
 
  <-- double tracing.Square.perimeter()
836
 
s1.perimeter() = 4.0
837
 
  --> double tracing.Square.area()
838
 
  <-- double tracing.Square.area()
839
 
s1.area() = 1.0
840
 
  --> double tracing.TwoDShape.distance(TwoDShape)
841
 
    --> double tracing.TwoDShape.getX()
842
 
    <-- double tracing.TwoDShape.getX()
843
 
    --> double tracing.TwoDShape.getY()
844
 
    <-- double tracing.TwoDShape.getY()
845
 
  <-- double tracing.TwoDShape.distance(TwoDShape)
846
 
c2.distance(c1) = 4.242640687119285
847
 
  --> double tracing.TwoDShape.distance(TwoDShape)
848
 
    --> double tracing.TwoDShape.getX()
849
 
    <-- double tracing.TwoDShape.getX()
850
 
    --> double tracing.TwoDShape.getY()
851
 
    <-- double tracing.TwoDShape.getY()
852
 
  <-- double tracing.TwoDShape.distance(TwoDShape)
853
 
s1.distance(c1) = 2.23606797749979
854
 
  --> String tracing.Square.toString()
855
 
    --> String tracing.TwoDShape.toString()
856
 
    <-- String tracing.TwoDShape.toString()
857
 
  <-- String tracing.Square.toString()
858
 
s1.toString(): Square side = 1.0 @ (1.0, 2.0)
859
 
]]></programlisting>
860
 
 
861
 
      <para>
862
 
        When <filename>TraceMyClasses.java</filename> is not provided to
863
 
        <command>ajc</command>, the aspect does not have any affect on the
864
 
        system and the tracing is unplugged.
865
 
      </para>
866
 
    </sect3>
867
 
 
868
 
    <sect3>
869
 
      <title>Tracing&mdash;Version 2</title>
870
 
 
871
 
      <para>
872
 
        Another way to accomplish the same thing would be to write a reusable
873
 
        tracing aspect that can be used not only for these application classes,
874
 
        but for any class. One way to do this is to merge the tracing
875
 
        functionality of <literal>Trace&mdash;version1</literal> with the
876
 
        crosscutting support of
877
 
        <literal>TraceMyClasses&mdash;version1</literal>. We end up with a
878
 
        <literal>Trace</literal> aspect (found in
879
 
        <filename>version2/Trace.java</filename>) with the following public
880
 
        interface
881
 
      </para>
882
 
 
883
 
<programlisting><![CDATA[
884
 
abstract aspect Trace {
885
 
 
886
 
    public static int TRACELEVEL = 2;
887
 
    public static void initStream(PrintStream s) {...}
888
 
    protected static void traceEntry(String str) {...}
889
 
    protected static void traceExit(String str) {...}
890
 
    abstract pointcut myClass();
891
 
}
892
 
]]></programlisting>
893
 
 
894
 
      <para>
895
 
        In order to use it, we need to define our own subclass that knows about
896
 
        our application classes, in <filename>version2/TraceMyClasses.java</filename>:
897
 
      </para>
898
 
 
899
 
<programlisting><![CDATA[
900
 
public aspect TraceMyClasses extends Trace {
901
 
    pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square);
902
 
 
903
 
    public static void main(String[] args) {
904
 
        Trace.TRACELEVEL = 2;
905
 
        Trace.initStream(System.err);
906
 
        ExampleMain.main(args);
907
 
    }
908
 
}
909
 
]]></programlisting>
910
 
 
911
 
      <para>
912
 
        Notice that we've simply made the pointcut <literal>classes</literal>,
913
 
        that was an abstract pointcut in the super-aspect, concrete. To run
914
 
        this version of tracing, go to the directory
915
 
        <filename>examples</filename> and type:
916
 
      </para>
917
 
 
918
 
<programlisting><![CDATA[
919
 
  ajc -argfile tracing/tracev2.lst
920
 
]]></programlisting>
921
 
 
922
 
      <para>
923
 
        The file tracev2.lst lists the application classes as well as this
924
 
        version of the files Trace.java and TraceMyClasses.java. Running the
925
 
        main method of <classname>tracing.version2.TraceMyClasses</classname>
926
 
        should output exactly the same trace information as that from version
927
 
        1.
928
 
      </para>
929
 
 
930
 
      <para>
931
 
        The entire implementation of the new <classname>Trace</classname> class
932
 
        is:
933
 
      </para>
934
 
 
935
 
<programlisting><![CDATA[
936
 
abstract aspect Trace {
937
 
 
938
 
    // implementation part
939
 
 
940
 
    public static int TRACELEVEL = 2;
941
 
    protected static PrintStream stream = System.err;
942
 
    protected static int callDepth = 0;
943
 
 
944
 
    public static void initStream(PrintStream s) {
945
 
        stream = s;
946
 
    }
947
 
    protected static void traceEntry(String str) {
948
 
        if (TRACELEVEL == 0) return;
949
 
        if (TRACELEVEL == 2) callDepth++;
950
 
        printEntering(str);
951
 
    }
952
 
    protected static void traceExit(String str) {
953
 
        if (TRACELEVEL == 0) return;
954
 
        printExiting(str);
955
 
        if (TRACELEVEL == 2) callDepth--;
956
 
    }
957
 
    private static void printEntering(String str) {
958
 
        printIndent();
959
 
        stream.println("--> " + str);
960
 
    }
961
 
    private static void printExiting(String str) {
962
 
        printIndent();
963
 
        stream.println("<-- " + str);
964
 
    }
965
 
    private static void printIndent() {
966
 
        for (int i = 0; i < callDepth; i++)
967
 
            stream.print("  ");
968
 
    }
969
 
 
970
 
    // protocol part
971
 
 
972
 
    abstract pointcut myClass();
973
 
 
974
 
    pointcut myConstructor(): myClass() && execution(new(..));
975
 
    pointcut myMethod(): myClass() && execution(* *(..));
976
 
 
977
 
    before(): myConstructor() {
978
 
        traceEntry("" + thisJoinPointStaticPart.getSignature());
979
 
    }
980
 
    after(): myConstructor() {
981
 
        traceExit("" + thisJoinPointStaticPart.getSignature());
982
 
    }
983
 
 
984
 
    before(): myMethod() {
985
 
        traceEntry("" + thisJoinPointStaticPart.getSignature());
986
 
    }
987
 
    after(): myMethod() {
988
 
        traceExit("" + thisJoinPointStaticPart.getSignature());
989
 
    }
990
 
}
991
 
]]></programlisting>
992
 
 
993
 
      <para>
994
 
        This version differs from version 1 in several subtle ways. The first
995
 
        thing to notice is that this <classname>Trace</classname> class merges
996
 
        the functional part of tracing with the crosscutting of the tracing
997
 
        calls. That is, in version 1, there was a sharp separation between the
998
 
        tracing support (the class <classname>Trace</classname>) and the
999
 
        crosscutting usage of it (by the class
1000
 
        <classname>TraceMyClasses</classname>). In this version those two
1001
 
        things are merged. That's why the description of this class explicitly
1002
 
        says that "Trace messages are printed before and after constructors and
1003
 
        methods are," which is what we wanted in the first place. That is, the
1004
 
        placement of the calls, in this version, is established by the aspect
1005
 
        class itself, leaving less opportunity for misplacing calls.</para>
1006
 
 
1007
 
      <para>
1008
 
        A consequence of this is that there is no need for providing traceEntry
1009
 
        and traceExit as public operations of this class. You can see that they
1010
 
        were classified as protected. They are supposed to be internal
1011
 
        implementation details of the advice.
1012
 
      </para>
1013
 
 
1014
 
      <para>
1015
 
        The key piece of this aspect is the abstract pointcut classes that
1016
 
        serves as the base for the definition of the pointcuts constructors and
1017
 
        methods. Even though <classname>classes</classname> is abstract, and
1018
 
        therefore no concrete classes are mentioned, we can put advice on it,
1019
 
        as well as on the pointcuts that are based on it. The idea is "we don't
1020
 
        know exactly what the pointcut will be, but when we do, here's what we
1021
 
        want to do with it." In some ways, abstract pointcuts are similar to
1022
 
        abstract methods. Abstract methods don't provide the implementation,
1023
 
        but you know that the concrete subclasses will, so you can invoke those
1024
 
        methods.
1025
 
      </para>
1026
 
    </sect3>
1027
 
    </sect2>
1028
 
  </sect1>
1029
 
 
1030
 
<!--  ============================================================ -->
1031
 
<!--  ============================================================ -->
1032
 
 
1033
 
  <sect1>
1034
 
    <title>Production Aspects</title>
1035
 
 
1036
 
    <!--  ==================== -->
1037
 
 
1038
 
  <sect2><!-- A Bean Aspect -->
1039
 
    <title>A Bean Aspect</title>
1040
 
 
1041
 
      <para>(The code for this example is in
1042
 
      <filename><replaceable>InstallDir</replaceable>/examples/bean</filename>.)
1043
 
      </para>
1044
 
 
1045
 
    <para>
1046
 
      This example examines an aspect that makes Point objects into a Java beans
1047
 
      with bound properties. </para>
1048
 
 
1049
 
    <sect3>
1050
 
      <title>Introduction</title>
1051
 
      <para>
1052
 
        Java beans are reusable software components that can be visually
1053
 
        manipulated in a builder tool. The requirements for an object to be a
1054
 
        bean are few. Beans must define a no-argument constructor and must be
1055
 
        either <classname>Serializable</classname> or
1056
 
        <classname>Externalizable</classname>. Any properties of the object
1057
 
        that are to be treated as bean properties should be indicated by the
1058
 
        presence of appropriate <literal>get</literal> and
1059
 
        <literal>set</literal> methods whose names are
1060
 
            <literal>get</literal><emphasis>property</emphasis> and
1061
 
            <literal>set </literal><emphasis>property</emphasis>
1062
 
        where <emphasis>property</emphasis> is the name of a field in the bean
1063
 
        class. Some bean properties, known as bound properties, fire events
1064
 
        whenever their values change so that any registered listeners (such as,
1065
 
        other beans) will be informed of those changes. Making a bound property
1066
 
        involves keeping a list of registered listeners, and creating and
1067
 
        dispatching event objects in methods that change the property values,
1068
 
        such as set<emphasis>property</emphasis> methods.</para>
1069
 
 
1070
 
      <para>
1071
 
        <classname>Point</classname> is a simple class representing points with
1072
 
        rectangular coordinates. <classname>Point</classname> does not know
1073
 
        anything about being a bean: there are set methods for
1074
 
        <literal>x</literal> and <literal>y</literal> but they do not fire
1075
 
        events, and the class is not serializable. Bound is an aspect that
1076
 
        makes <classname>Point</classname> a serializable class and makes its
1077
 
        <literal>get</literal> and <literal>set</literal> methods support the
1078
 
        bound property protocol.
1079
 
      </para>
1080
 
    </sect3>
1081
 
 
1082
 
    <sect3>
1083
 
        <title>The Class <classname>Point</classname></title>
1084
 
 
1085
 
        <para>
1086
 
        The class <classname>Point</classname> is a very simple class with
1087
 
        trivial getters and setters, and a simple vector offset method.
1088
 
      </para>
1089
 
 
1090
 
        <programlisting><![CDATA[
1091
 
class Point {
1092
 
 
1093
 
  protected int x = 0;
1094
 
  protected int y = 0;
1095
 
 
1096
 
  public int getX() {
1097
 
    return x;
1098
 
  }
1099
 
 
1100
 
  public int getY() {
1101
 
    return y;
1102
 
  }
1103
 
 
1104
 
  public void setRectangular(int newX, int newY) {
1105
 
    setX(newX);
1106
 
    setY(newY);
1107
 
  }
1108
 
 
1109
 
  public void setX(int newX) {
1110
 
    x = newX;
1111
 
  }
1112
 
 
1113
 
  public void setY(int newY) {
1114
 
    y = newY;
1115
 
  }
1116
 
 
1117
 
  public void offset(int deltaX, int deltaY) {
1118
 
    setRectangular(x + deltaX, y + deltaY);
1119
 
  }
1120
 
 
1121
 
  public String toString() {
1122
 
    return "(" + getX() + ", " + getY() + ")" ;
1123
 
  }
1124
 
}]]></programlisting>
1125
 
 
1126
 
    </sect3>
1127
 
 
1128
 
    <sect3>
1129
 
      <title>The Aspect <classname>BoundPoint</classname></title>
1130
 
 
1131
 
      <para>
1132
 
        The aspect <classname>BoundPoint</classname> adds "beanness" to
1133
 
        <classname>Point</classname> objects. The first thing it does is
1134
 
        privately introduce a reference to an instance of
1135
 
        <classname>PropertyChangeSupport</classname> into all
1136
 
        <classname>Point</classname> objects. The property change
1137
 
        support object must be constructed with a reference to the bean for
1138
 
        which it is providing support, so it is initialized by passing it this,
1139
 
        an instance of <classname>Point</classname>. The support field is
1140
 
        privately introduced, so only the code in the aspect can refer to it.
1141
 
      </para>
1142
 
 
1143
 
      <para>
1144
 
        Methods for registering and managing listeners for property change
1145
 
        events are introduced into <classname>Point</classname> by the
1146
 
        introductions. These methods delegate the work to the
1147
 
        property change support object.
1148
 
      </para>
1149
 
 
1150
 
      <para>
1151
 
        The introduction also makes <classname>Point</classname> implement the
1152
 
        <classname>Serializable</classname> interface. Implementing
1153
 
        <classname>Serializable</classname> does not require any methods to be
1154
 
        implemented. Serialization for <classname>Point</classname> objects is
1155
 
        provided by the default serialization method.
1156
 
      </para>
1157
 
 
1158
 
      <para>
1159
 
        The pointcut <function>setters</function> names the
1160
 
        <literal>set</literal> methods: reception by a
1161
 
        <classname>Point</classname> object of any method whose name begins
1162
 
        with '<literal>set</literal>' and takes one parameter. The around
1163
 
        advice on <literal>setters()</literal> stores the values
1164
 
        of the <literal>X</literal> and <literal>Y</literal> properties, calls
1165
 
        the original <literal>set</literal> method and then fires the
1166
 
        appropriate property change event according to which set method was
1167
 
        called. Note that the call to the method proceed needs to pass along
1168
 
        the <literal>Point p</literal>. The rule of thumb is that context that
1169
 
        an around advice exposes must be passed forward to continue.
1170
 
      </para>
1171
 
 
1172
 
<programlisting><![CDATA[
1173
 
aspect BoundPoint {
1174
 
  private PropertyChangeSupport Point.support = new PropertyChangeSupport(this);
1175
 
 
1176
 
  public void Point.addPropertyChangeListener(PropertyChangeListener listener){
1177
 
    support.addPropertyChangeListener(listener);
1178
 
  }
1179
 
 
1180
 
  public void Point.addPropertyChangeListener(String propertyName,
1181
 
                                              PropertyChangeListener listener){
1182
 
 
1183
 
    support.addPropertyChangeListener(propertyName, listener);
1184
 
  }
1185
 
 
1186
 
  public void Point.removePropertyChangeListener(String propertyName,
1187
 
                                                 PropertyChangeListener listener) {
1188
 
    support.removePropertyChangeListener(propertyName, listener);
1189
 
  }
1190
 
 
1191
 
  public void Point.removePropertyChangeListener(PropertyChangeListener listener) {
1192
 
    support.removePropertyChangeListener(listener);
1193
 
  }
1194
 
 
1195
 
  public void Point.hasListeners(String propertyName) {
1196
 
    support.hasListeners(propertyName);
1197
 
  }
1198
 
 
1199
 
  declare parents: Point implements Serializable;
1200
 
 
1201
 
  pointcut setter(Point p): call(void Point.set*(*)) && target(p);
1202
 
 
1203
 
  void around(Point p): setter(p) {
1204
 
        String propertyName =
1205
 
      thisJoinPointStaticPart.getSignature().getName().substring("set".length());
1206
 
        int oldX = p.getX();
1207
 
        int oldY = p.getY();
1208
 
        proceed(p);
1209
 
        if (propertyName.equals("X")){
1210
 
      firePropertyChange(p, propertyName, oldX, p.getX());
1211
 
        } else {
1212
 
      firePropertyChange(p, propertyName, oldY, p.getY());
1213
 
        }
1214
 
  }
1215
 
 
1216
 
  void firePropertyChange(Point p,
1217
 
                          String property,
1218
 
                          double oldval,
1219
 
                          double newval) {
1220
 
        p.support.firePropertyChange(property,
1221
 
                                 new Double(oldval),
1222
 
                                 new Double(newval));
1223
 
  }
1224
 
}
1225
 
]]></programlisting>
1226
 
 
1227
 
    </sect3>
1228
 
 
1229
 
    <sect3>
1230
 
      <title>The Test Program</title>
1231
 
 
1232
 
      <para>
1233
 
        The test program registers itself as a property change listener to a
1234
 
        <literal>Point</literal> object that it creates and then performs
1235
 
        simple manipulation of that point: calling its set methods and the
1236
 
        offset method. Then it serializes the point and writes it to a file and
1237
 
        then reads it back. The result of saving and restoring the point is that
1238
 
        a new point is created.
1239
 
      </para>
1240
 
 
1241
 
<programlisting><![CDATA[
1242
 
  class Demo implements PropertyChangeListener {
1243
 
 
1244
 
    static final String fileName = "test.tmp";
1245
 
 
1246
 
    public void propertyChange(PropertyChangeEvent e){
1247
 
      System.out.println("Property " + e.getPropertyName() + " changed from " +
1248
 
         e.getOldValue() + " to " + e.getNewValue() );
1249
 
    }
1250
 
 
1251
 
    public static void main(String[] args){
1252
 
      Point p1 = new Point();
1253
 
      p1.addPropertyChangeListener(new Demo());
1254
 
      System.out.println("p1 =" + p1);
1255
 
      p1.setRectangular(5,2);
1256
 
      System.out.println("p1 =" + p1);
1257
 
      p1.setX( 6 );
1258
 
      p1.setY( 3 );
1259
 
      System.out.println("p1 =" + p1);
1260
 
      p1.offset(6,4);
1261
 
      System.out.println("p1 =" + p1);
1262
 
      save(p1, fileName);
1263
 
      Point p2 = (Point) restore(fileName);
1264
 
      System.out.println("Had: " + p1);
1265
 
      System.out.println("Got: " + p2);
1266
 
      }
1267
 
    ...
1268
 
  }
1269
 
]]></programlisting>
1270
 
 
1271
 
    </sect3>
1272
 
    <sect3>
1273
 
      <title>Compiling and Running the Example</title>
1274
 
      <para>To compile and run this example, go to the examples directory and type:
1275
 
      </para>
1276
 
 
1277
 
<programlisting><![CDATA[
1278
 
ajc -argfile bean/files.lst
1279
 
java bean.Demo
1280
 
]]></programlisting>
1281
 
 
1282
 
      </sect3>
1283
 
    </sect2>
1284
 
 
1285
 
    <!--  ==================== -->
1286
 
 
1287
 
  <sect2><!-- The Subject/Observer Protocol -->
1288
 
    <title>The Subject/Observer Protocol</title>
1289
 
 
1290
 
      <para>(The code for this example is in
1291
 
      <filename><replaceable>InstallDir</replaceable>/examples/observer</filename>.)
1292
 
      </para>
1293
 
 
1294
 
    <para>
1295
 
      This demo illustrates how the Subject/Observer design pattern can be
1296
 
      coded with aspects. </para>
1297
 
 
1298
 
    <sect3>
1299
 
      <title>Overview</title>
1300
 
      <para>
1301
 
         The demo consists of the following: A colored label is a renderable
1302
 
         object that has a color that cycles through a set of colors, and a
1303
 
         number that records the number of cycles it has been through. A button
1304
 
         is an action item that records when it is clicked.
1305
 
      </para>
1306
 
 
1307
 
      <para>
1308
 
        With these two kinds of objects, we can build up a Subject/Observer
1309
 
        relationship in which colored labels observe the clicks of buttons;
1310
 
        that is, where colored labels are the observers and buttons are the
1311
 
        subjects.
1312
 
      </para>
1313
 
 
1314
 
      <para>
1315
 
        The demo is designed and implemented using the Subject/Observer design
1316
 
        pattern. The remainder of this example explains the classes and aspects
1317
 
        of this demo, and tells you how to run it.
1318
 
      </para>
1319
 
    </sect3>
1320
 
 
1321
 
    <sect3>
1322
 
      <title>Generic Components</title>
1323
 
 
1324
 
      <para>
1325
 
        The generic parts of the protocol are the interfaces
1326
 
        <classname>Subject</classname> and <classname>Observer</classname>, and
1327
 
        the abstract aspect <classname>SubjectObserverProtocol</classname>. The
1328
 
        <classname>Subject</classname> interface is simple, containing methods
1329
 
        to add, remove, and view <classname>Observer</classname> objects, and a
1330
 
        method for getting data about state changes:
1331
 
      </para>
1332
 
 
1333
 
<programlisting><![CDATA[
1334
 
    interface Subject {
1335
 
      void addObserver(Observer obs);
1336
 
      void removeObserver(Observer obs);
1337
 
      Vector getObservers();
1338
 
      Object getData();
1339
 
  }
1340
 
]]></programlisting>
1341
 
 
1342
 
      <para> The <classname>Observer</classname> interface is just as simple,
1343
 
        with methods to set and get <classname>Subject</classname> objects, and
1344
 
        a method to call when the subject gets updated.
1345
 
      </para>
1346
 
 
1347
 
<programlisting><![CDATA[
1348
 
  interface Observer {
1349
 
      void setSubject(Subject s);
1350
 
      Subject getSubject();
1351
 
      void update();
1352
 
  }
1353
 
]]></programlisting>
1354
 
 
1355
 
      <para>
1356
 
        The <classname>SubjectObserverProtocol</classname> aspect contains
1357
 
        within it all of the generic parts of the protocol, namely, how to fire
1358
 
        the <classname>Observer</classname> objects' update methods when some
1359
 
        state changes in a subject.
1360
 
      </para>
1361
 
 
1362
 
<programlisting><![CDATA[
1363
 
  abstract aspect SubjectObserverProtocol {
1364
 
 
1365
 
      abstract pointcut stateChanges(Subject s);
1366
 
 
1367
 
      after(Subject s): stateChanges(s) {
1368
 
          for (int i = 0; i < s.getObservers().size(); i++) {
1369
 
              ((Observer)s.getObservers().elementAt(i)).update();
1370
 
          }
1371
 
      }
1372
 
 
1373
 
      private Vector Subject.observers = new Vector();
1374
 
      public void   Subject.addObserver(Observer obs) {
1375
 
          observers.addElement(obs);
1376
 
          obs.setSubject(this);
1377
 
      }
1378
 
      public void   Subject.removeObserver(Observer obs) {
1379
 
          observers.removeElement(obs);
1380
 
          obs.setSubject(null);
1381
 
      }
1382
 
      public Vector Subject.getObservers() { return observers; }
1383
 
 
1384
 
      private Subject Observer.subject = null;
1385
 
      public void     Observer.setSubject(Subject s) { subject = s; }
1386
 
      public Subject  Observer.getSubject() { return subject; }
1387
 
 
1388
 
  }
1389
 
]]></programlisting>
1390
 
 
1391
 
      <para>
1392
 
        Note that this aspect does three things. It define an abstract pointcut
1393
 
        that extending aspects can override. It defines advice that should run
1394
 
        after the join points of the pointcut. And it introduces state and
1395
 
        behavior onto the <classname>Subject</classname> and
1396
 
        <classname>Observer</classname> interfaces.
1397
 
      </para>
1398
 
    </sect3>
1399
 
 
1400
 
    <sect3>
1401
 
      <title>Application Classes</title>
1402
 
 
1403
 
      <para> <classname>Button</classname> objects extend
1404
 
        <classname>java.awt.Button</classname>, and all they do is make sure
1405
 
        the <literal>void click()</literal> method is called whenever a button
1406
 
        is clicked.
1407
 
      </para>
1408
 
 
1409
 
<programlisting><![CDATA[
1410
 
  class Button extends java.awt.Button {
1411
 
 
1412
 
      static final Color  defaultBackgroundColor = Color.gray;
1413
 
      static final Color  defaultForegroundColor = Color.black;
1414
 
      static final String defaultText = "cycle color";
1415
 
 
1416
 
      Button(Display display) {
1417
 
          super();
1418
 
          setLabel(defaultText);
1419
 
          setBackground(defaultBackgroundColor);
1420
 
          setForeground(defaultForegroundColor);
1421
 
          addActionListener(new ActionListener() {
1422
 
                  public void actionPerformed(ActionEvent e) {
1423
 
                      Button.this.click();
1424
 
                  }
1425
 
              });
1426
 
          display.addToFrame(this);
1427
 
      }
1428
 
 
1429
 
      public void click() {}
1430
 
 
1431
 
  }
1432
 
]]></programlisting>
1433
 
 
1434
 
      <para>
1435
 
        Note that this class knows nothing about being a Subject.
1436
 
      </para>
1437
 
      <para>
1438
 
        ColorLabel objects are labels that support the void colorCycle()
1439
 
        method. Again, they know nothing about being an observer.
1440
 
      </para>
1441
 
 
1442
 
<programlisting><![CDATA[
1443
 
  class ColorLabel extends Label {
1444
 
 
1445
 
      ColorLabel(Display display) {
1446
 
          super();
1447
 
          display.addToFrame(this);
1448
 
      }
1449
 
 
1450
 
      final static Color[] colors = {Color.red, Color.blue,
1451
 
                                     Color.green, Color.magenta};
1452
 
      private int colorIndex = 0;
1453
 
      private int cycleCount = 0;
1454
 
      void colorCycle() {
1455
 
          cycleCount++;
1456
 
          colorIndex = (colorIndex + 1) % colors.length;
1457
 
          setBackground(colors[colorIndex]);
1458
 
          setText("" + cycleCount);
1459
 
      }
1460
 
  }
1461
 
]]></programlisting>
1462
 
 
1463
 
      <para>
1464
 
        Finally, the <classname>SubjectObserverProtocolImpl</classname>
1465
 
        implements the subject/observer protocol, with
1466
 
        <classname>Button</classname> objects as subjects and
1467
 
        <classname>ColorLabel</classname> objects as observers:
1468
 
      </para>
1469
 
 
1470
 
<programlisting><![CDATA[
1471
 
package observer;
1472
 
 
1473
 
import java.util.Vector;
1474
 
 
1475
 
aspect SubjectObserverProtocolImpl extends SubjectObserverProtocol {
1476
 
 
1477
 
    declare parents: Button implements Subject;
1478
 
    public Object Button.getData() { return this; }
1479
 
 
1480
 
    declare parents: ColorLabel implements Observer;
1481
 
    public void    ColorLabel.update() {
1482
 
        colorCycle();
1483
 
    }
1484
 
 
1485
 
    pointcut stateChanges(Subject s):
1486
 
        target(s) &&
1487
 
        call(void Button.click());
1488
 
 
1489
 
}]]></programlisting>
1490
 
 
1491
 
      <para>
1492
 
        It does this by introducing the appropriate interfaces onto the
1493
 
        <classname>Button</classname> and <classname>ColorLabel</classname>
1494
 
        classes, making sure the methods required by the interfaces are
1495
 
        implemented, and providing a definition for the
1496
 
        <literal>stateChanges</literal> pointcut. Now, every time a
1497
 
        <classname>Button</classname> is clicked, all
1498
 
        <classname>ColorLabel</classname> objects observing that button will
1499
 
        <literal>colorCycle</literal>.
1500
 
      </para>
1501
 
    </sect3>
1502
 
 
1503
 
    <sect3>
1504
 
      <title>Compiling and Running</title>
1505
 
 
1506
 
      <para> <classname>Demo</classname> is the top class that starts this
1507
 
        demo. It instantiates a two buttons and three observers and links them
1508
 
        together as subjects and observers. So to run the demo, go to the
1509
 
        <filename>examples</filename> directory and type:
1510
 
      </para>
1511
 
 
1512
 
<programlisting><![CDATA[
1513
 
  ajc -argfile observer/files.lst
1514
 
  java observer.Demo
1515
 
]]></programlisting>
1516
 
 
1517
 
      </sect3>
1518
 
    </sect2>
1519
 
 
1520
 
    <!--  ==================== -->
1521
 
 
1522
 
    <sect2>
1523
 
    <title>A Simple Telecom Simulation</title>
1524
 
 
1525
 
      <para>(The code for this example is in
1526
 
      <filename><replaceable>InstallDir</replaceable>/examples/telecom</filename>.)
1527
 
      </para>
1528
 
 
1529
 
    <para>
1530
 
      This example illustrates some ways that dependent concerns can be encoded
1531
 
      with aspects. It uses an example system comprising a simple model of
1532
 
      telephone connections to which timing and billing features are added
1533
 
      using aspects, where the billing feature depends upon the timing feature.
1534
 
    </para>
1535
 
 
1536
 
    <sect3>
1537
 
      <title>The Application</title>
1538
 
 
1539
 
      <para>
1540
 
        The example application is a simple simulation of a telephony system in
1541
 
        which customers make, accept, merge and hang-up both local and long
1542
 
        distance calls. The application architecture is in three layers.
1543
 
      </para>
1544
 
      <itemizedlist>
1545
 
        <listitem>
1546
 
          <para>
1547
 
            The basic objects  provide basic functionality to simulate
1548
 
            customers, calls and connections (regular calls have one
1549
 
            connection, conference calls have more than one).
1550
 
          </para>
1551
 
        </listitem>
1552
 
 
1553
 
        <listitem>
1554
 
          <para>
1555
 
            The timing feature is concerned with timing the connections and
1556
 
            keeping the total connection time per customer. Aspects are used to
1557
 
            add a timer to each connection and to manage the total time per
1558
 
            customer.
1559
 
          </para>
1560
 
        </listitem>
1561
 
 
1562
 
        <listitem>
1563
 
          <para>
1564
 
            The billing feature is concerned with charging customers for the
1565
 
            calls they make. Aspects are used to calculate a charge per
1566
 
            connection and, upon termination of a connection, to add the charge
1567
 
            to the appropriate customer's bill. The billing aspect builds upon
1568
 
            the timing aspect: it uses a pointcut defined in Timing and it uses
1569
 
            the timers that are associated with connections.
1570
 
          </para>
1571
 
        </listitem>
1572
 
      </itemizedlist>
1573
 
      <para>
1574
 
        The simulation of system has three configurations: basic, timing and
1575
 
        billing. Programs for the three configurations are in classes
1576
 
        <classname>BasicSimulation</classname>,
1577
 
        <classname>TimingSimulation</classname> and
1578
 
        <classname>BillingSimulation</classname>. These share a common
1579
 
        superclass <classname>AbstractSimulation</classname>, which defines the
1580
 
        method run with the simulation itself and the method wait used to
1581
 
        simulate elapsed time.
1582
 
      </para>
1583
 
    </sect3>
1584
 
 
1585
 
    <sect3>
1586
 
      <title>The Basic Objects</title>
1587
 
 
1588
 
      <para>
1589
 
        The telecom simulation comprises the classes
1590
 
        <classname>Customer</classname>, <classname>Call</classname> and the
1591
 
        abstract class <classname>Connection</classname> with its two concrete
1592
 
        subclasses <classname>Local</classname> and
1593
 
        <classname>LongDistance</classname>. Customers have a name and a
1594
 
        numeric area code. They also have methods for managing calls. Simple
1595
 
        calls are made between one customer (the caller) and another (the
1596
 
        receiver), a <classname>Connection</classname> object is used to
1597
 
        connect them. Conference calls between more than two customers will
1598
 
        involve more than one connection. A customer may be involved in many
1599
 
        calls at one time.
1600
 
        <inlinemediaobject>
1601
 
          <imageobject>
1602
 
            <imagedata fileref="telecom.gif"/>
1603
 
          </imageobject>
1604
 
        </inlinemediaobject>
1605
 
      </para>
1606
 
    </sect3>
1607
 
 
1608
 
    <sect3>
1609
 
      <title>The Class <classname>Customer</classname></title>
1610
 
 
1611
 
      <para>
1612
 
        <classname>Customer</classname> has methods <literal>call</literal>,
1613
 
        <literal>pickup</literal>, <literal>hangup</literal> and
1614
 
        <literal>merge</literal> for managing calls.
1615
 
      </para>
1616
 
 
1617
 
<programlisting><![CDATA[
1618
 
public class Customer {
1619
 
 
1620
 
      private String name;
1621
 
      private int areacode;
1622
 
      private Vector calls = new Vector();
1623
 
 
1624
 
      protected void removeCall(Call c){
1625
 
          calls.removeElement(c);
1626
 
      }
1627
 
 
1628
 
      protected void addCall(Call c){
1629
 
          calls.addElement(c);
1630
 
      }
1631
 
 
1632
 
      public Customer(String name, int areacode) {
1633
 
          this.name = name;
1634
 
          this.areacode = areacode;
1635
 
      }
1636
 
 
1637
 
      public String toString() {
1638
 
          return name + "(" + areacode + ")";
1639
 
      }
1640
 
 
1641
 
      public int getAreacode(){
1642
 
          return areacode;
1643
 
      }
1644
 
 
1645
 
      public boolean localTo(Customer other){
1646
 
          return areacode == other.areacode;
1647
 
      }
1648
 
 
1649
 
      public Call call(Customer receiver) {
1650
 
          Call call = new Call(this, receiver);
1651
 
          addCall(call);
1652
 
          return call;
1653
 
      }
1654
 
 
1655
 
      public void pickup(Call call) {
1656
 
          call.pickup();
1657
 
          addCall(call);
1658
 
      }
1659
 
 
1660
 
      public void hangup(Call call) {
1661
 
          call.hangup(this);
1662
 
          removeCall(call);
1663
 
      }
1664
 
 
1665
 
      public void merge(Call call1, Call call2){
1666
 
          call1.merge(call2);
1667
 
          removeCall(call2);
1668
 
      }
1669
 
  }
1670
 
]]></programlisting>
1671
 
 
1672
 
      </sect3>
1673
 
 
1674
 
    <sect3>
1675
 
      <title>The Class <classname>Call</classname></title>
1676
 
 
1677
 
      <para>
1678
 
        Calls are created with a caller and receiver who are customers. If the
1679
 
        caller and receiver have the same area code then the call can be
1680
 
        established with a <classname>Local</classname> connection (see below),
1681
 
        otherwise a <classname>LongDistance</classname> connection is required.
1682
 
        A call comprises a number of connections between customers. Initially
1683
 
        there is only the connection between the caller and receiver but
1684
 
        additional connections can be added if calls are merged to form
1685
 
        conference calls.
1686
 
      </para>
1687
 
    </sect3>
1688
 
 
1689
 
    <sect3>
1690
 
      <title>The Class <classname>Connection</classname></title>
1691
 
 
1692
 
      <para>The class <classname>Connection</classname> models the physical
1693
 
        details of establishing a connection between customers. It does this
1694
 
        with a simple state machine (connections are initially
1695
 
        <literal>PENDING</literal>, then <literal>COMPLETED</literal> and
1696
 
        finally <literal>DROPPED</literal>). Messages are printed to the
1697
 
        console so that the state of connections can be observed. Connection is
1698
 
        an abstract class with two concrete subclasses:
1699
 
        <classname>Local</classname> and <classname>LongDistance</classname>.
1700
 
      </para>
1701
 
 
1702
 
<programlisting><![CDATA[
1703
 
  abstract class Connection {
1704
 
 
1705
 
      public static final int PENDING = 0;
1706
 
      public static final int COMPLETE = 1;
1707
 
      public static final int DROPPED = 2;
1708
 
 
1709
 
      Customer caller, receiver;
1710
 
      private int state = PENDING;
1711
 
 
1712
 
      Connection(Customer a, Customer b) {
1713
 
          this.caller = a;
1714
 
          this.receiver = b;
1715
 
      }
1716
 
 
1717
 
      public int getState(){
1718
 
          return state;
1719
 
      }
1720
 
 
1721
 
      public Customer getCaller() { return caller; }
1722
 
 
1723
 
      public Customer getReceiver() { return receiver; }
1724
 
 
1725
 
      void complete() {
1726
 
          state = COMPLETE;
1727
 
          System.out.println("connection completed");
1728
 
      }
1729
 
 
1730
 
      void drop() {
1731
 
          state = DROPPED;
1732
 
          System.out.println("connection dropped");
1733
 
      }
1734
 
 
1735
 
      public boolean connects(Customer c){
1736
 
          return (caller == c || receiver == c);
1737
 
      }
1738
 
 
1739
 
  }
1740
 
]]></programlisting>
1741
 
 
1742
 
      </sect3>
1743
 
 
1744
 
    <sect3>
1745
 
      <title>The Class Local</title>
1746
 
 
1747
 
<programlisting><![CDATA[
1748
 
  class Local extends Connection {
1749
 
      Local(Customer a, Customer b) {
1750
 
          super(a, b);
1751
 
          System.out.println("[new local connection from " +
1752
 
             a + " to " + b + "]");
1753
 
      }
1754
 
  }
1755
 
]]></programlisting>
1756
 
 
1757
 
      </sect3>
1758
 
 
1759
 
    <sect3>
1760
 
      <title>The Class LongDistance</title>
1761
 
 
1762
 
<programlisting><![CDATA[
1763
 
  class LongDistance extends Connection {
1764
 
      LongDistance(Customer a, Customer b) {
1765
 
          super(a, b);
1766
 
          System.out.println("[new long distance connection from " +
1767
 
              a + " to " + b + "]");
1768
 
      }
1769
 
  }
1770
 
]]></programlisting>
1771
 
 
1772
 
      </sect3>
1773
 
 
1774
 
    <sect3>
1775
 
      <title>Compiling and Running the Basic Simulation</title>
1776
 
 
1777
 
      <para>
1778
 
        The source files for the basic system are listed in the file
1779
 
        <filename>basic.lst</filename>. To build and run the basic system, in a
1780
 
        shell window, type these commands:
1781
 
      </para>
1782
 
 
1783
 
<programlisting><![CDATA[
1784
 
ajc -argfile telecom/basic.lst
1785
 
java telecom.BasicSimulation
1786
 
]]></programlisting>
1787
 
 
1788
 
      </sect3>
1789
 
 
1790
 
    <sect3>
1791
 
      <title>Timing</title>
1792
 
      <para>
1793
 
        The <classname>Timing</classname> aspect keeps track of total
1794
 
        connection time for each <classname>Customer</classname> by starting
1795
 
        and stopping a timer associated with each connection. It uses some
1796
 
        helper classes:
1797
 
      </para>
1798
 
 
1799
 
      <sect4>
1800
 
        <title>The Class <classname>Timer</classname></title>
1801
 
 
1802
 
        <para>
1803
 
          A <classname>Timer</classname> object simply records the current time
1804
 
          when it is started and stopped, and returns their difference when
1805
 
          asked for the elapsed time. The aspect
1806
 
          <classname>TimerLog</classname> (below) can be used to cause the
1807
 
          start and stop times to be printed to standard output.
1808
 
        </para>
1809
 
 
1810
 
<programlisting><![CDATA[
1811
 
  class Timer {
1812
 
      long startTime, stopTime;
1813
 
 
1814
 
      public void start() {
1815
 
          startTime = System.currentTimeMillis();
1816
 
          stopTime = startTime;
1817
 
      }
1818
 
 
1819
 
      public void stop() {
1820
 
          stopTime = System.currentTimeMillis();
1821
 
      }
1822
 
 
1823
 
      public long getTime() {
1824
 
          return stopTime - startTime;
1825
 
      }
1826
 
  }
1827
 
]]></programlisting>
1828
 
 
1829
 
        </sect4>
1830
 
      </sect3>
1831
 
 
1832
 
      <sect3>
1833
 
        <title>The Aspect <classname>TimerLog</classname></title>
1834
 
 
1835
 
        <para>
1836
 
          The aspect <classname>TimerLog</classname> can be included in a
1837
 
          build to get the timer to announce when it is started and stopped.
1838
 
        </para>
1839
 
 
1840
 
<programlisting><![CDATA[
1841
 
public aspect TimerLog {
1842
 
 
1843
 
    after(Timer t): target(t) && call(* Timer.start())  {
1844
 
      System.err.println("Timer started: " + t.startTime);
1845
 
    }
1846
 
 
1847
 
    after(Timer t): target(t) && call(* Timer.stop()) {
1848
 
      System.err.println("Timer stopped: " + t.stopTime);
1849
 
    }
1850
 
}
1851
 
]]></programlisting>
1852
 
 
1853
 
        </sect3>
1854
 
 
1855
 
      <sect3>
1856
 
        <title>The Aspect <classname>Timing</classname></title>
1857
 
 
1858
 
        <para>
1859
 
          The aspect <classname>Timing</classname> introduces attribute
1860
 
          <literal>totalConnectTime</literal> into the class
1861
 
          <classname>Customer</classname> to store the accumulated connection
1862
 
          time per <classname>Customer</classname>. It introduces attribute
1863
 
          timer into <classname>Connection</classname> to associate a timer
1864
 
          with each <classname>Connection</classname>. Two pieces of after
1865
 
          advice ensure that the timer is started when a connection is
1866
 
          completed and and stopped when it is dropped. The pointcut
1867
 
          <literal>endTiming</literal> is defined so that it can be used by the
1868
 
          <classname>Billing</classname> aspect.
1869
 
        </para>
1870
 
 
1871
 
<programlisting><![CDATA[
1872
 
public aspect Timing {
1873
 
 
1874
 
    public long Customer.totalConnectTime = 0;
1875
 
 
1876
 
    public long getTotalConnectTime(Customer cust) {
1877
 
        return cust.totalConnectTime;
1878
 
    }
1879
 
    private Timer Connection.timer = new Timer();
1880
 
    public Timer getTimer(Connection conn) { return conn.timer; }
1881
 
 
1882
 
    after (Connection c): target(c) && call(void Connection.complete()) {
1883
 
        getTimer(c).start();
1884
 
    }
1885
 
 
1886
 
    pointcut endTiming(Connection c): target(c) &&
1887
 
        call(void Connection.drop());
1888
 
 
1889
 
    after(Connection c): endTiming(c) {
1890
 
        getTimer(c).stop();
1891
 
        c.getCaller().totalConnectTime += getTimer(c).getTime();
1892
 
        c.getReceiver().totalConnectTime += getTimer(c).getTime();
1893
 
    }
1894
 
}]]></programlisting>
1895
 
 
1896
 
        </sect3>
1897
 
 
1898
 
    <sect3>
1899
 
      <title>Billing</title>
1900
 
 
1901
 
      <para>
1902
 
        The Billing system adds billing functionality to the telecom
1903
 
        application on top of timing.
1904
 
      </para>
1905
 
 
1906
 
      <sect4>
1907
 
        <title>The Aspect <classname>Billing</classname></title>
1908
 
 
1909
 
        <para>
1910
 
          The aspect <classname>Billing</classname> introduces attribute
1911
 
          <literal>payer</literal> into <classname>Connection</classname>
1912
 
          to indicate who initiated the call and therefore who is
1913
 
          responsible to pay for it. It also introduces method
1914
 
          <literal>callRate</literal> into <classname>Connection</classname>
1915
 
          so that local and long distance calls can be charged
1916
 
          differently. The call charge must be calculated after the timer is
1917
 
          stopped; the after advice on pointcut
1918
 
          <literal>Timing.endTiming</literal> does this and
1919
 
          <classname>Billing</classname> dominates Timing to make
1920
 
          sure that this advice runs after <classname>Timing's</classname>
1921
 
          advice on the same join point. It introduces attribute
1922
 
          <literal>totalCharge</literal> and its associated methods into
1923
 
          <classname>Customer</classname> (to manage the
1924
 
          customer's bill information.
1925
 
        </para>
1926
 
 
1927
 
<programlisting><![CDATA[
1928
 
public aspect Billing dominates Timing {
1929
 
    // domination required to get advice on endtiming in the right order
1930
 
 
1931
 
    public static final long LOCAL_RATE = 3;
1932
 
    public static final long LONG_DISTANCE_RATE = 10;
1933
 
 
1934
 
 
1935
 
    public Customer Connection.payer;
1936
 
    public Customer getPayer(Connection conn) { return conn.payer; }
1937
 
 
1938
 
    after(Customer cust) returning (Connection conn):
1939
 
        args(cust, ..) && call(Connection+.new(..)) {
1940
 
        conn.payer = cust;
1941
 
    }
1942
 
 
1943
 
    public abstract long Connection.callRate();
1944
 
 
1945
 
 
1946
 
    public long LongDistance.callRate() { return LONG_DISTANCE_RATE; }
1947
 
    public long Local.callRate() { return LOCAL_RATE; }
1948
 
 
1949
 
 
1950
 
    after(Connection conn): Timing.endTiming(conn) {
1951
 
        long time = Timing.aspectOf().getTimer(conn).getTime();
1952
 
        long rate = conn.callRate();
1953
 
        long cost = rate * time;
1954
 
        getPayer(conn).addCharge(cost);
1955
 
    }
1956
 
 
1957
 
 
1958
 
    public long Customer.totalCharge = 0;
1959
 
    public long getTotalCharge(Customer cust) { return cust.totalCharge; }
1960
 
 
1961
 
    public void Customer.addCharge(long charge){
1962
 
        totalCharge += charge;
1963
 
    }
1964
 
}
1965
 
]]></programlisting>
1966
 
 
1967
 
        </sect4>
1968
 
    </sect3>
1969
 
 
1970
 
    <sect3>
1971
 
      <title>Accessing the Introduced State</title>
1972
 
 
1973
 
      <para>
1974
 
        Both the aspects <classname>Timing</classname> and
1975
 
        <classname>Billing</classname> contain the definition of operations
1976
 
        that the rest of the system may want to access. For example, when
1977
 
        running the simulation with one or both aspects, we want to find out
1978
 
        how much time each customer spent on the telephone and how big their
1979
 
        bill is. That information is also stored in the classes, but they are
1980
 
        accessed through static methods of the aspects, since the state they
1981
 
        refer to is private to the aspect.
1982
 
      </para>
1983
 
 
1984
 
      <para>
1985
 
        Take a look at the file <filename>TimingSimulation.java</filename>. The
1986
 
        most important method of this class is the method
1987
 
        <filename>report(Customer c)</filename>, which is used in the method
1988
 
        run of the superclass <classname>AbstractSimulation</classname>. This
1989
 
        method is intended to print out the status of the customer, with
1990
 
        respect to the <classname>Timing</classname> feature.
1991
 
      </para>
1992
 
 
1993
 
<programlisting><![CDATA[
1994
 
  protected void report(Customer c){
1995
 
      Timing t = Timing.aspectOf();
1996
 
      System.out.println(c + " spent " + t.getTotalConnectTime(c));
1997
 
  }
1998
 
]]></programlisting>
1999
 
 
2000
 
      </sect3>
2001
 
 
2002
 
    <sect3>
2003
 
      <title>Compiling and Running</title>
2004
 
 
2005
 
      <para>
2006
 
        The files timing.lst and billing.lst contain file lists for the timing
2007
 
        and billing configurations. To build and run the application with only
2008
 
        the timing feature, go to the directory examples and type:
2009
 
      </para>
2010
 
 
2011
 
<programlisting><![CDATA[
2012
 
  ajc -argfile telecom/timing.lst
2013
 
  java telecom.TimingSimulation
2014
 
]]></programlisting>
2015
 
 
2016
 
      <para>
2017
 
        To build and run the application with the timing and billing features,
2018
 
        go to the directory examples and type:
2019
 
      </para>
2020
 
 
2021
 
<programlisting><![CDATA[
2022
 
  ajc -argfile telecom/billing.lst
2023
 
  java telecom.BillingSimulation
2024
 
]]></programlisting>
2025
 
 
2026
 
      </sect3>
2027
 
 
2028
 
    <sect3>
2029
 
      <title>Discussion</title>
2030
 
 
2031
 
      <para>
2032
 
        There are some explicit dependencies between the aspects Billing and
2033
 
        Timing:
2034
 
        <itemizedlist>
2035
 
          <listitem>
2036
 
            <para>
2037
 
              Billing is declared to dominate Timing so that Billing's after
2038
 
              advice runs after that of Timing  when they are on the same join
2039
 
              point.
2040
 
            </para>
2041
 
          </listitem>
2042
 
 
2043
 
          <listitem>
2044
 
            <para>
2045
 
              Billing uses the pointcut Timing.endTiming.
2046
 
            </para>
2047
 
          </listitem>
2048
 
 
2049
 
          <listitem>
2050
 
            <para>
2051
 
              Billing needs access to the timer associated with a connection.
2052
 
            </para>
2053
 
          </listitem>
2054
 
        </itemizedlist>
2055
 
      </para>
2056
 
    </sect3>
2057
 
    </sect2>
2058
 
  </sect1>
2059
 
 
2060
 
<!--  ============================================================ -->
2061
 
<!--  ============================================================ -->
2062
 
 
2063
 
  <sect1>
2064
 
    <title>Reusable Aspects</title>
2065
 
 
2066
 
    <sect2>
2067
 
      <title>Tracing Aspects Revisited</title>
2068
 
 
2069
 
      <para>(The code for this example is in
2070
 
      <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.)
2071
 
      </para>
2072
 
 
2073
 
    <sect3>
2074
 
      <title>Tracing&mdash;Version 3</title>
2075
 
 
2076
 
      <para>
2077
 
        One advantage of not exposing the methods traceEntry and traceExit as
2078
 
        public operations is that we can easily change their interface without
2079
 
        any dramatic consequences in the rest of the code.
2080
 
      </para>
2081
 
 
2082
 
      <para>
2083
 
        Consider, again, the program without AspectJ. Suppose, for example,
2084
 
        that at some point later the requirements for tracing change, stating
2085
 
        that the trace messages should always include the string representation
2086
 
        of the object whose methods are being traced. This can be achieved in
2087
 
        at least two ways. One way is keep the interface of the methods
2088
 
        <literal>traceEntry</literal> and <literal>traceExit</literal> as it
2089
 
        was before,
2090
 
      </para>
2091
 
 
2092
 
<programlisting><![CDATA[
2093
 
  public static void traceEntry(String str);
2094
 
  public static void traceExit(String str);
2095
 
]]></programlisting>
2096
 
 
2097
 
      <para>
2098
 
        In this case, the caller is responsible for ensuring that the string
2099
 
        representation of the object is part of the string given as argument.
2100
 
        So, calls must look like:
2101
 
      </para>
2102
 
 
2103
 
<programlisting><![CDATA[
2104
 
  Trace.traceEntry("Square.distance in " + toString());
2105
 
]]></programlisting>
2106
 
 
2107
 
      <para>
2108
 
        Another way is to enforce the requirement with a second argument in the
2109
 
        trace operations, e.g.
2110
 
      </para>
2111
 
 
2112
 
<programlisting><![CDATA[
2113
 
  public static void traceEntry(String str, Object obj);
2114
 
  public static void traceExit(String str, Object obj);
2115
 
]]></programlisting>
2116
 
 
2117
 
      <para>
2118
 
        In this case, the caller is still responsible for sending the right
2119
 
        object, but at least there is some guarantees that some object will be
2120
 
        passed. The calls will look like:
2121
 
      </para>
2122
 
 
2123
 
<programlisting><![CDATA[
2124
 
  Trace.traceEntry("Square.distance", this);
2125
 
]]></programlisting>
2126
 
 
2127
 
      <para>
2128
 
        In either case, this change to the requirements of tracing will have
2129
 
        dramatic consequences in the rest of the code -- every call to the
2130
 
        trace operations traceEntry and traceExit must be changed!
2131
 
      </para>
2132
 
 
2133
 
      <para>
2134
 
        Here's another advantage of doing tracing with an aspect. We've already
2135
 
        seen that in version 2 <literal>traceEntry</literal> and
2136
 
        <literal>traceExit</literal> are not publicly exposed. So changing
2137
 
        their interfaces, or the way they are used, has only a small effect
2138
 
        inside the <classname>Trace</classname> class. Here's a partial view at
2139
 
        the implementation of <classname>Trace</classname>, version 3. The
2140
 
        differences with respect to version 2 are stressed in the
2141
 
        comments:
2142
 
      </para>
2143
 
 
2144
 
<programlisting><![CDATA[
2145
 
abstract aspect Trace {
2146
 
 
2147
 
    public static int TRACELEVEL = 0;
2148
 
    protected static PrintStream stream = null;
2149
 
    protected static int callDepth = 0;
2150
 
 
2151
 
    public static void initStream(PrintStream s) {
2152
 
        stream = s;
2153
 
    }
2154
 
 
2155
 
    protected static void traceEntry(String str, Object o) {
2156
 
        if (TRACELEVEL == 0) return;
2157
 
        if (TRACELEVEL == 2) callDepth++;
2158
 
        printEntering(str + ": " + o.toString());
2159
 
    }
2160
 
 
2161
 
    protected static void traceExit(String str, Object o) {
2162
 
        if (TRACELEVEL == 0) return;
2163
 
        printExiting(str + ": " + o.toString());
2164
 
        if (TRACELEVEL == 2) callDepth--;
2165
 
    }
2166
 
 
2167
 
    private static void printEntering(String str) {
2168
 
        printIndent();
2169
 
        stream.println("Entering " + str);
2170
 
    }
2171
 
 
2172
 
    private static void printExiting(String str) {
2173
 
        printIndent();
2174
 
        stream.println("Exiting " + str);
2175
 
    }
2176
 
 
2177
 
 
2178
 
    private static void printIndent() {
2179
 
        for (int i = 0; i < callDepth; i++)
2180
 
            stream.print("  ");
2181
 
    }
2182
 
 
2183
 
 
2184
 
    abstract pointcut myClass(Object obj);
2185
 
 
2186
 
    pointcut myConstructor(Object obj): myClass(obj) && execution(new(..));
2187
 
    pointcut myMethod(Object obj): myClass(obj) &&
2188
 
        execution(* *(..)) && !execution(String toString());
2189
 
 
2190
 
    before(Object obj): myConstructor(obj) {
2191
 
        traceEntry("" + thisJoinPointStaticPart.getSignature(), obj);
2192
 
    }
2193
 
    after(Object obj): myConstructor(obj) {
2194
 
        traceExit("" + thisJoinPointStaticPart.getSignature(), obj);
2195
 
    }
2196
 
 
2197
 
    before(Object obj): myMethod(obj) {
2198
 
        traceEntry("" + thisJoinPointStaticPart.getSignature(), obj);
2199
 
    }
2200
 
    after(Object obj): myMethod(obj) {
2201
 
        traceExit("" + thisJoinPointStaticPart.getSignature(), obj);
2202
 
    }
2203
 
}
2204
 
]]></programlisting>
2205
 
 
2206
 
      <para>
2207
 
        As you can see, we decided to apply the first design by preserving the
2208
 
        interface of the methods <literal>traceEntry</literal> and
2209
 
        <literal>traceExit</literal>. But it doesn't matter&mdash;we could as
2210
 
        easily have applied the second design (the code in the directory
2211
 
        <filename>examples/tracing/version3</filename> has the second design).
2212
 
        The point is that the effects of this change in the tracing
2213
 
        requirements are limited to the <classname>Trace</classname> aspect
2214
 
        class.
2215
 
      </para>
2216
 
 
2217
 
      <para>
2218
 
        One implementation change worth noticing is the specification of the
2219
 
        pointcuts. They now expose the object. To maintain full consistency
2220
 
        with the behavior of version 2, we should have included tracing for
2221
 
        static methods, by defining another pointcut for static methods and
2222
 
        advising it. We leave that as an exercise.
2223
 
      </para>
2224
 
 
2225
 
      <para>
2226
 
        Moreover, we had to exclude the execution join point of the method
2227
 
        <filename>toString</filename> from the <literal>methods</literal>
2228
 
        pointcut. The problem here is that <literal>toString</literal> is being
2229
 
        called from inside the advice.  Therefore if we trace it, we will end
2230
 
        up in an infinite recursion of calls. This is a subtle point, and one
2231
 
        that you must be aware when writing advice. If the advice calls back to
2232
 
        the objects, there is always the possibility of recursion. Keep that in
2233
 
        mind!
2234
 
      </para>
2235
 
 
2236
 
      <para>
2237
 
        In fact, esimply excluding the execution join point may not be enough,
2238
 
        if there are calls to other traced methods within it -- in which case,
2239
 
        the restriction should be
2240
 
      </para>
2241
 
      
2242
 
<programlisting><![CDATA[
2243
 
&& !cflow(execution(String toString()))
2244
 
]]></programlisting>
2245
 
 
2246
 
      <para>
2247
 
        excluding both the execution of toString methods and all join points
2248
 
        under that execution. 
2249
 
      </para>
2250
 
 
2251
 
      <para>
2252
 
        In summary, to implement the change in the tracing requirements we had
2253
 
        to make a couple of changes in the implementation of the
2254
 
        <classname>Trace</classname> aspect class, including changing the
2255
 
        specification of the pointcuts. That's only natural. But the
2256
 
        implementation changes were limited to this aspect. Without aspects, we
2257
 
        would have to change the implementation of every application class.
2258
 
      </para>
2259
 
 
2260
 
      <para>
2261
 
        Finally, to run this version of tracing, go to the directory
2262
 
        <filename>examples</filename> and type:
2263
 
      </para>
2264
 
 
2265
 
<programlisting><![CDATA[
2266
 
ajc -argfile tracing/tracev3.lst
2267
 
]]></programlisting>
2268
 
 
2269
 
      <para>
2270
 
        The file tracev3.lst lists the application classes as well as this
2271
 
        version of the files <filename>Trace.java</filename> and
2272
 
        <filename>TraceMyClasses.java</filename>. To run the program, type
2273
 
      </para>
2274
 
 
2275
 
<programlisting><![CDATA[
2276
 
java tracing.version3.TraceMyClasses
2277
 
]]></programlisting>
2278
 
 
2279
 
      <para>The output should be:</para>
2280
 
 
2281
 
<programlisting><![CDATA[
2282
 
  --> tracing.TwoDShape(double, double)
2283
 
  <-- tracing.TwoDShape(double, double)
2284
 
  --> tracing.Circle(double, double, double)
2285
 
  <-- tracing.Circle(double, double, double)
2286
 
  --> tracing.TwoDShape(double, double)
2287
 
  <-- tracing.TwoDShape(double, double)
2288
 
  --> tracing.Circle(double, double, double)
2289
 
  <-- tracing.Circle(double, double, double)
2290
 
  --> tracing.Circle(double)
2291
 
  <-- tracing.Circle(double)
2292
 
  --> tracing.TwoDShape(double, double)
2293
 
  <-- tracing.TwoDShape(double, double)
2294
 
  --> tracing.Square(double, double, double)
2295
 
  <-- tracing.Square(double, double, double)
2296
 
  --> tracing.Square(double, double)
2297
 
  <-- tracing.Square(double, double)
2298
 
  --> double tracing.Circle.perimeter()
2299
 
  <-- double tracing.Circle.perimeter()
2300
 
c1.perimeter() = 12.566370614359172
2301
 
  --> double tracing.Circle.area()
2302
 
  <-- double tracing.Circle.area()
2303
 
c1.area() = 12.566370614359172
2304
 
  --> double tracing.Square.perimeter()
2305
 
  <-- double tracing.Square.perimeter()
2306
 
s1.perimeter() = 4.0
2307
 
  --> double tracing.Square.area()
2308
 
  <-- double tracing.Square.area()
2309
 
s1.area() = 1.0
2310
 
  --> double tracing.TwoDShape.distance(TwoDShape)
2311
 
    --> double tracing.TwoDShape.getX()
2312
 
    <-- double tracing.TwoDShape.getX()
2313
 
    --> double tracing.TwoDShape.getY()
2314
 
    <-- double tracing.TwoDShape.getY()
2315
 
  <-- double tracing.TwoDShape.distance(TwoDShape)
2316
 
c2.distance(c1) = 4.242640687119285
2317
 
  --> double tracing.TwoDShape.distance(TwoDShape)
2318
 
    --> double tracing.TwoDShape.getX()
2319
 
    <-- double tracing.TwoDShape.getX()
2320
 
    --> double tracing.TwoDShape.getY()
2321
 
    <-- double tracing.TwoDShape.getY()
2322
 
  <-- double tracing.TwoDShape.distance(TwoDShape)
2323
 
s1.distance(c1) = 2.23606797749979
2324
 
  --> String tracing.Square.toString()
2325
 
    --> String tracing.TwoDShape.toString()
2326
 
    <-- String tracing.TwoDShape.toString()
2327
 
  <-- String tracing.Square.toString()
2328
 
s1.toString(): Square side = 1.0 @ (1.0, 2.0)
2329
 
]]></programlisting>
2330
 
 
2331
 
      </sect3>
2332
 
    </sect2>
2333
 
  </sect1>
2334
 
</chapter>
2335
 
 
2336
 
<!--
2337
 
Local variables:
2338
 
compile-command: "java sax.SAXCount -v progguide.xml && java com.icl.saxon.StyleSheet -w0 progguide.xml progguide.html.xsl"
2339
 
fill-column: 79
2340
 
sgml-local-ecat-files: "progguide.ced"
2341
 
sgml-parent-document:("progguide.xml" "book" "chapter")
2342
 
End:
2343
 
-->