diff options
Diffstat (limited to 'docs/progGuideDB/examples.xml')
-rw-r--r-- | docs/progGuideDB/examples.xml | 1567 |
1 files changed, 831 insertions, 736 deletions
diff --git a/docs/progGuideDB/examples.xml b/docs/progGuideDB/examples.xml index 2e6a1715d..762a4ef08 100644 --- a/docs/progGuideDB/examples.xml +++ b/docs/progGuideDB/examples.xml @@ -1,19 +1,12 @@ <chapter id="examples" xreflabel="Examples"> <title>Examples</title> - <sect1><!-- About this Chapter --> - <title>About this Chapter</title> + <sect1 id="examples-intro"> + <title>Introduction</title> - <para>This chapter consists entirely of examples of AspectJ use. - -<!-- ADD THIS IN AGAIN WHEN IT'S TRUE - The - examples have been chosen because they illustrate common AspectJ usage - patterns or techniques. Care has been taken to ensure that they also - exhibit good style, in addition to being merely syntactically and - semantically correct. ---> -</para> + <para> + This chapter consists entirely of examples of AspectJ use. + </para> <para>The examples can be grouped into four categories:</para> @@ -36,30 +29,37 @@ </sect1> +<!-- ============================== --> - <sect1> + <sect1 id="examples-howto"> <title>Obtaining, Compiling and Running the Examples</title> - <para>The examples source code is part of AspectJ's documentation - distribution which may be downloaded from <ulink - url="http://aspectj.org/dl">the AspectJ download page</ulink>.</para> + <para> + The examples source code is part of the AspectJ distribution which may be + downloaded from the AspectJ project page ( <ulink + url="http://eclipse.org/aspectj" /> ). + </para> - <para>Compiling most examples should be straightforward. Go the + <para> + Compiling most examples is straightforward. Go the <filename><replaceable>InstallDir</replaceable>/examples</filename> - directory, and look for a <filename>.lst</filename> file in one of the - example subdirectories. Use the <literal>-arglist</literal> option to - <literal>ajc</literal> to compile the example. For instance, to compile - the telecom example with billing, type </para> + directory, and look for a <filename>.lst</filename> file in one of + the example subdirectories. Use the <literal>-arglist</literal> + option to <literal>ajc</literal> to compile the example. For + instance, to compile the telecom example with billing, type + </para> <programlisting> ajc -argfile telecom/billing.lst </programlisting> - <para>To run the examples, your classpath must include the AspectJ run-time - Java archive (<literal>aspectjrt.jar</literal>). You may either set - the <literal>CLASSPATH</literal> environment variable or use the + <para> + To run the examples, your classpath must include the AspectJ run-time + Java archive (<literal>aspectjrt.jar</literal>). You may either set the + <literal>CLASSPATH</literal> environment variable or use the <literal>-classpath</literal> command line option to the Java - interpreter:</para> + interpreter: + </para> <programlisting> (In Unix use a : in the CLASSPATH) @@ -75,47 +75,51 @@ java -classpath ".;<replaceable>InstallDir</replaceable>/lib/aspectjrt.jar" tele <!-- ============================================================ --> -<!-- ============================================================ --> - - <sect1> + <sect1 id="examples-basic"> <title>Basic Techniques</title> - <para>This section presents two basic techniques of using AspectJ, one each - from the two fundamental ways of capturing crosscutting concerns: with - dynamic join points and advice, and with static introduction. Advice - changes an application's behavior. Introduction changes both an - application's behavior and its structure. </para> + <para> + This section presents two basic techniques of using AspectJ, one each + from the two fundamental ways of capturing crosscutting concerns: + with dynamic join points and advice, and with static + introduction. Advice changes an application's behavior. Introduction + changes both an application's behavior and its structure. + </para> - <para>The first example, <xref endterm="sec:JoinPointsAndtjp:title" - linkend="sec:JoinPointsAndtjp"/>, is about gathering and using - information about the join point that has triggered some advice. The - second example, <xref endterm="sec:RolesAndViews:title" - linkend="sec:RolesAndViews"/>, concerns changing an existing class - hierarchy. </para> + <para> + The first example, <xref linkend="examples-joinPoints" />, is about + gathering and using information about the join point that has + triggered some advice. The second example, <xref + linkend="examples-roles" />, concerns a crosscutting view of an + existing class hierarchy. </para> <!-- ======================================== --> - <sect2 id="sec:JoinPointsAndtjp"><!-- Join Points and thisJoinPoint --> + <sect2 id="examples-joinPoints"> <title>Join Points and <literal>thisJoinPoint</literal></title> - <titleabbrev id="sec:JoinPointsAndtjp:title">Join Points and - <literal>thisJoinPoint</literal></titleabbrev> - <para>(The code for this example is in - <filename><replaceable>InstallDir</replaceable>/examples/tjp</filename>.)</para> + <para> + (The code for this example is in + <filename><replaceable>InstallDir</replaceable>/examples/tjp</filename>.) + </para> - <para>A join point is some point in the - execution of a program together with a view into the execution context - when that point occurs. Join points are picked out by pointcuts. When a - join point is reached, before, after or around advice on that join - point may be run. </para> + <para> + A join point is some point in the execution of a program together + with a view into the execution context when that point occurs. Join + points are picked out by pointcuts. When a program reaches a join + point, advice on that join point may run in addition to (or instead + of) the join point itself. + </para> - <para>When dealing with pointcuts that pick out join points of specific - method calls, field gets, or the like, the advice will know exactly what - kind of join point it is executing under. It might even have access to - context given by its pointcut. Here, for example, since the only join - points reached will be calls of a certain method, we can get the target - and one of the args of the method directly. + <para> + When using a pointcut that picks out join points of a single kind + by name, typicaly the the advice will know exactly what kind of + join point it is associated with. The pointcut may even publish + context about the join point. Here, for example, since the only + join points picked out by the pointcut are calls of a certain + method, we can get the target value and one of the argument values + of the method calls directly. </para> <programlisting><![CDATA[ @@ -128,60 +132,71 @@ before(Point p, int x): target(p) } ]]></programlisting> - <para>But sometimes the join point is not so clear. For - instance, suppose a complex application is being debugged, and one - would like to know when any method in some class is being executed. - Then, the pointcut </para> + <para> + But sometimes the shape of the join point is not so clear. For + instance, suppose a complex application is being debugged, and we + want to trace when any method of some class is executed. The + pointcut + </para> <programlisting><![CDATA[ pointcut execsInProblemClass(): within(ProblemClass) && execution(* *(..)); ]]></programlisting> - <para>will select all join points where a method defined within the class - <classname>ProblemClass</classname> is being executed. But advice - executes when a particular join point is matched, and so the question, - "Which join point was matched?" naturally arises.</para> + <para> + will pick out each execution join point of every method defined + within <classname>ProblemClass</classname>. Since advice executes + at each join point picked out by the pointcut, we can reasonably + ask which join point was reached. + </para> - <para>Information about the join point that was matched is available to - advice through the special variable <varname>thisJoinPoint</varname>, - of type <ulink - url="../api/org/aspectj/lang/JoinPoint.html"><classname>org.aspectj.lang.JoinPoint</classname></ulink>. This - class provides methods that return</para> + <para> + Information about the join point that was matched is available to + advice through the special variable + <varname>thisJoinPoint</varname>, of type <ulink + url="../api/org/aspectj/lang/JoinPoint.html"><classname>org.aspectj.lang.JoinPoint</classname></ulink>. + Through this object we can access information such as</para> <itemizedlist spacing="compact"> - <listitem>the kind of join point that was matched + <listitem> + the kind of join point that was matched </listitem> - <listitem>the source location of the current join point + <listitem> + the source location of the code associated with the join point + </listitem> + <listitem> + normal, short and long string representations of the + current join point + </listitem> + <listitem> + the actual argument values of the join point + </listitem> + <listitem> + the signature of the member associated with the join point </listitem> - <listitem>normal, short and long string representations of the - current join point</listitem> - <listitem>the actual argument(s) to the method or field selected - by the current join point </listitem> - <listitem>the signature of the method or field selected by the - current join point</listitem> - <listitem>the target object</listitem> <listitem>the currently executing object</listitem> - <listitem>a reference to the static portion of the object - representing the current join point. This is also available through - the special variable <varname>thisJoinPointStaticPart</varname>.</listitem> - + <listitem>the target object</listitem> + <listitem> + an object encapsulating the static information about the join + point. This is also available through the special variable + <varname>thisJoinPointStaticPart</varname>.</listitem> </itemizedlist> <sect3> <title>The <classname>Demo</classname> class</title> - <para>The class <classname>tjp.Demo</classname> in + <para>The class <classname>tjp.Demo</classname> in <filename>tjp/Demo.java</filename> defines two methods - <literal>foo</literal> and <literal>bar</literal> with different - parameter lists and return types. Both are called, with suitable - arguments, by <classname>Demo</classname>'s <function>go</function> - method which was invoked from within its <function>main</function> - method. </para> + <literal>foo</literal> and <literal>bar</literal> with different + parameter lists and return types. Both are called, with suitable + arguments, by <classname>Demo</classname>'s + <function>go</function> method which was invoked from within its + <function>main</function> method. + </para> <programlisting><![CDATA[ public class Demo { - static Demo d; public static void main(String[] args){ @@ -198,47 +213,24 @@ public class Demo { System.out.println("Demo.foo(" + i + ", " + o + ")\n"); } - String bar (Integer j){ System.out.println("Demo.bar(" + j + ")\n"); return "Demo.bar(" + j + ")"; } - } ]]></programlisting> </sect3> <sect3> - <title>The Aspect <literal>GetInfo</literal></title> + <title>The <literal>GetInfo</literal> aspect</title> - <para>This aspect uses around advice to intercept the execution of + <para> + This aspect uses around advice to intercept the execution of methods <literal>foo</literal> and <literal>bar</literal> in - <classname>Demo</classname>, and prints out information garnered from - <literal>thisJoinPoint</literal> to the console. </para> - - <sect4> - <title>Defining the scope of a pointcut</title> - - <para>The pointcut <function>goCut</function> is defined as - <literal><![CDATA[cflow(this(Demo)) && execution(void - go())]]></literal> so that only executions made in the control - flow of <literal>Demo.go</literal> are intercepted. The control - flow from the method <literal>go</literal> includes the execution of - <literal>go</literal> itself, so the definition of the around - advice includes <literal>!execution(* go())</literal> to exclude it - from the set of executions advised. </para> - </sect4> - - <sect4> - <title>Printing the class and method name</title> - - <para>The name of the method and that method's defining class are - available as parts of the <ulink - url="../api/org/aspectj/lang/Signature.html">Signature</ulink>, - found using the method <literal>getSignature</literal> of either - <literal>thisJoinPoint</literal> or - <literal>thisJoinPointStaticPart</literal>. </para> + <classname>Demo</classname>, and prints out information garnered + from <literal>thisJoinPoint</literal> to the console. + </para> <programlisting><![CDATA[ aspect GetInfo { @@ -274,6 +266,35 @@ aspect GetInfo { } } ]]></programlisting> + + <sect4> + <title>Defining the scope of a pointcut</title> + + <para>The pointcut <function>goCut</function> is defined as + +<programlisting><![CDATA[ +cflow(this(Demo)) && execution(void go()) +]]></programlisting> + + so that only executions made in the control flow of + <literal>Demo.go</literal> are intercepted. The control flow + from the method <literal>go</literal> includes the execution of + <literal>go</literal> itself, so the definition of the around + advice includes <literal>!execution(* go())</literal> to + exclude it from the set of executions advised. </para> + </sect4> + + <sect4> + <title>Printing the class and method name</title> + + <para> + The name of the method and that method's defining class are + available as parts of the <ulink + url="../api/org/aspectj/lang/Signature.html">org.aspectj.lang.Signature</ulink> + object returned by calling <literal>getSignature()</literal> on + either <literal>thisJoinPoint</literal> or + <literal>thisJoinPointStaticPart</literal>. + </para> </sect4> <sect4> @@ -282,65 +303,76 @@ aspect GetInfo { <para> The static portions of the parameter details, the name and types of the parameters, can be accessed through the <ulink - url="../api/org/aspectj/lang/reflect/CodeSignature.html"><literal>CodeSignature</literal></ulink> + url="../api/org/aspectj/lang/reflect/CodeSignature.html"><literal>org.aspectj.lang.reflect.CodeSignature</literal></ulink> associated with the join point. All execution join points have code signatures, so the cast to <literal>CodeSignature</literal> cannot fail. </para> <para> The dynamic portions of the parameter details, the actual - values of the parameters, are accessed directly from the execution - join point object. </para> + values of the parameters, are accessed directly from the + execution join point object. + </para> </sect4> </sect3> </sect2> - <sect2 id="sec:RolesAndViews"> - <title>Roles and Views Using Introduction</title> - <titleabbrev id="sec:RolesAndViews:title">Roles and Views Using - Introduction</titleabbrev> +<!-- ============================== --> - <para>(The code for this example is in - <filename><replaceable>InstallDir</replaceable>/examples/introduction</filename>.)</para> + <sect2 id="examples-roles"> + <title>Roles and Views</title> - <para>Like advice, pieces of introduction are members of an aspect. They - define new members that act as if they were defined on another - class. Unlike advice, introduction affects not only the behavior of the - application, but also the structural relationship between an - application's classes. </para> + <para> + (The code for this example is in + <filename><replaceable>InstallDir</replaceable>/examples/introduction</filename>.) + </para> - <para>This is crucial: Affecting the class structure of an application at - makes these modifications available to other components of the - application.</para> + <para> + Like advice, inter-type declarations are members of an aspect. They + declare members that act as if they were defined on another class. + Unlike advice, inter-type declarations affect not only the behavior + of the application, but also the structural relationship between an + application's classes. + </para> - <para>Introduction modifies a class by adding or changing</para> - <itemizedlist spacing="compact"> - <listitem>member fields</listitem> - <listitem>member methods</listitem> - <listitem>nested classes</listitem> - </itemizedlist> + <para> + This is crucial: Publically affecting the class structure of an + application makes these modifications available to other components + of the application. + </para> - <para>and by making the class</para> + <para> + Aspects can declare inter-type - <itemizedlist spacing="compact"> - <listitem>implement interfaces</listitem> - <listitem>extend classes</listitem> - </itemizedlist> + <itemizedlist spacing="compact"> + <listitem>fields</listitem> + <listitem>methods</listitem> + <listitem>constructors</listitem> + </itemizedlist> + + and can also declare that target types + + <itemizedlist spacing="compact"> + <listitem>implement new interfaces</listitem> + <listitem>extend new classes</listitem> + </itemizedlist> + </para> <para> - This example provides three illustrations of the use of introduction to - encapsulate roles or views of a class. The class we will be introducing - into, <classname>Point</classname>, is a simple class with rectangular - and polar coordinates. Our introduction will make the class - <classname>Point</classname>, in turn, cloneable, hashable, and - comparable. These facilities are provided by introduction forms without - having to modify the class <classname>Point</classname>. - </para> + This example provides three illustrations of the use of inter-type + declarations to encapsulate roles or views of a class. The class + our aspect will be dealing with, <classname>Point</classname>, is a + simple class with rectangular and polar coordinates. Our inter-type + declarations will make the class <classname>Point</classname>, in + turn, cloneable, hashable, and comparable. These facilities are + provided by AspectJ without having to modify the code for the class + <classname>Point</classname>. + </para> <sect3> - <title>The class <classname>Point</classname></title> + <title>The <classname>Point</classname> class</title> - <para>The class <classname>Point</classname> defines geometric points + <para>The <classname>Point</classname> class defines geometric points whose interface includes polar and rectangular coordinates, plus some simple operations to relocate points. <classname>Point</classname>'s implementation has attributes for both its polar and rectangular @@ -371,35 +403,36 @@ aspect GetInfo { </sect3> <sect3> - <title>Making <classname>Point</classname>s Cloneable — The Aspect - <classname>CloneablePoint</classname></title> - - <para>This first example demonstrates the introduction of a interface - (<classname>Cloneable</classname>) and a method - (<function>clone</function>) into the class - <classname>Point</classname>. In Java, all objects inherit the method - <literal>clone</literal> from the class - <classname>Object</classname>, but an object is not cloneable unless - its class also implements the interface - <classname>Cloneable</classname>. In addition, classes frequently - have requirements over and above the simple bit-for-bit copying that - <literal>Object.clone</literal> does. In our case, we want to update - a <classname>Point</classname>'s coordinate systems before we - actually clone the <classname>Point</classname>. So we have to - override <literal>Object.clone</literal> with a new method that does - what we want. </para> - - <para>The <classname>CloneablePoint</classname> aspect uses the - <literal>declare parents</literal> form to introduce the interface - <classname>Cloneable</classname> into the class - <classname>Point</classname>. It then defines a method, - <literal>Point.clone</literal>, which overrides the method - <function>clone</function> that was inherited from - <classname>Object</classname>. <function>Point.clone</function> - updates the <classname>Point</classname>'s coordinate systems before - invoking its superclass' <function>clone</function> method.</para> - - <programlisting><![CDATA[ + <title>The <classname>CloneablePoint</classname> aspect</title> + + <para> + This first aspect is responsible for + <classname>Point</classname>'s implementation of the + <classname>Cloneable</classname> interface. It declares that + <literal>Point implements Cloneable</literal> with a + <literal>declare parents</literal> form, and also publically + declares a specialized <literal>Point</literal>'s + <literal>clone()</literal> method. In Java, all objects inherit + the method <literal>clone</literal> from the class + <classname>Object</classname>, but an object is not cloneable + unless its class also implements the interface + <classname>Cloneable</classname>. In addition, classes + frequently have requirements over and above the simple + bit-for-bit copying that <literal>Object.clone</literal> does. In + our case, we want to update a <classname>Point</classname>'s + coordinate systems before we actually clone the + <classname>Point</classname>. So our aspect makes sure that + <literal>Point</literal> overrides + <literal>Object.clone</literal> with a new method that does what + we want. + </para> + + <para> + We also define a test <literal>main</literal> method in the + aspect for convenience. + </para> + +<programlisting><![CDATA[ public aspect CloneablePoint { declare parents: Point implements Cloneable; @@ -428,34 +461,40 @@ public aspect CloneablePoint { } } ]]></programlisting> - - <para>Note that since aspects define types just as classes define - types, we can define a <function>main</function> method that is - invocable from the command line to use as a test method.</para> </sect3> <sect3> - <title>Making <classname>Point</classname>s Comparable — The - Aspect <classname>ComparablePoint</classname></title> + <title>The <classname>ComparablePoint</classname> aspect</title> - <para>This second example introduces another interface and - method into the class <classname>Point</classname>.</para> + <para> + <classname>ComparablePoint</classname> is responsible for + <literal>Point</literal>'s implementation of the + <literal>Comparable</literal> interface. </para> - <para>The interface <classname>Comparable</classname> defines the + <para> + The interface <classname>Comparable</classname> defines the single method <literal>compareTo</literal> which can be use to define a natural ordering relation among the objects of a class that - implement it. </para> - - <para>The aspect <classname>ComparablePoint</classname> introduces - implements <classname>Comparable</classname> into - <classname>Point</classname> along with a - <literal>compareTo</literal> method that can be used to compare - <classname>Point</classname>s. A <classname>Point</classname> - <literal>p1</literal> is said to be less than - another <classname>Point</classname><literal> p2</literal> if - <literal>p1</literal> is closer to the origin. </para> - - <programlisting><![CDATA[ + implement it. + </para> + + <para> + <classname>ComparablePoint</classname> uses <literal>declare + parents</literal> to declare that <literal>Point implements + Comparable</literal>, and also publically declares the + appropriate <literal>compareTo(Object)</literal> method: A + <classname>Point</classname> <literal>p1</literal> is said to be + less than another <classname>Point</classname><literal> + p2</literal> if <literal>p1</literal> is closer to the + origin. + </para> + + <para> + We also define a test <literal>main</literal> method in the + aspect for convenience. + </para> + +<programlisting><![CDATA[ public aspect ComparablePoint { declare parents: Point implements Comparable; @@ -487,18 +526,22 @@ public aspect ComparablePoint { p1.offset(1,1); System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); } -}]]></programlisting> +} +]]></programlisting> </sect3> <sect3> - <title>Making <classname>Point</classname>s Hashable — The Aspect - <classname>HashablePoint</classname></title> + <title>The <classname>HashablePoint</classname> aspect</title> - <para>The third aspect overrides two previously defined methods to - give to <classname>Point</classname> the hashing behavior we - want.</para> + <para> + Our third aspect is responsible for <literal>Point</literal>'s + overriding of <literal>Object</literal>'s + <literal>equals</literal> and <literal>hashCode</literal> methods + in order to make <literal>Point</literal>s hashable. + </para> - <para>The method <literal>Object.hashCode</literal> returns an unique + <para> + The method <literal>Object.hashCode</literal> returns an unique integer, suitable for use as a hash table key. Different implementations are allowed return different integers, but must return distinct integers for distinct objects, and the same integer @@ -513,18 +556,27 @@ public aspect ComparablePoint { <literal>theta</literal> values, not just when they refer to the same object. We do this by overriding the methods <literal>equals</literal> and <literal>hashCode</literal> in the - class <classname>Point</classname>. </para> - - <para>The class <classname>HashablePoint</classname> introduces the - methods <literal>hashCode</literal> and <literal>equals</literal> - into the class <classname>Point</classname>. These methods use - <classname>Point</classname>'s rectangular coordinates to generate a - hash code and to test for equality. The <literal>x</literal> and - <literal>y</literal> coordinates are obtained using the appropriate - get methods, which ensure the rectangular coordinates are up-to-date - before returning their values. </para> - - <programlisting><![CDATA[ + class <classname>Point</classname>. + </para> + + <para> + So <classname>HashablePoint</classname> declares + <literal>Point</literal>'s <literal>hashCode</literal> and + <literal>equals</literal> methods, using + <classname>Point</classname>'s rectangular coordinates to + generate a hash code and to test for equality. The + <literal>x</literal> and <literal>y</literal> coordinates are + obtained using the appropriate get methods, which ensure the + rectangular coordinates are up-to-date before returning their + values. + </para> + + <para> + And again, we supply a <literal>main</literal> method in the + aspect for testing. + </para> + +<programlisting><![CDATA[ public aspect HashablePoint { public int Point.hashCode() { @@ -558,75 +610,68 @@ public aspect HashablePoint { } ]]></programlisting> - <para> Again, we supply a <literal>main</literal> method in the aspect - for testing. - </para> - </sect3> - </sect2> - </sect1> <!-- ============================================================ --> <!-- ============================================================ --> - <sect1> + <sect1 id="examples-development"> <title>Development Aspects</title> - <sect2> - <title>Tracing Aspects</title> + <sect2> + <title>Tracing using aspects</title> - <para>(The code for this example is in - <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.) + <para> + (The code for this example is in + <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.) </para> - <sect3> - <title>Overview</title> - - <para> - Writing a class that provides tracing functionality is easy: a couple - of functions, a boolean flag for turning tracing on and off, a choice - for an output stream, maybe some code for formatting the output---these - are all elements that <classname>Trace</classname> classes have been - known to have. <classname>Trace</classname> classes may be highly - sophisticated, too, if the task of tracing the execution of a program - demands so. + <para> + Writing a class that provides tracing functionality is easy: a + couple of functions, a boolean flag for turning tracing on and + off, a choice for an output stream, maybe some code for + formatting the output -- these are all elements that + <classname>Trace</classname> classes have been known to + have. <classname>Trace</classname> classes may be highly + sophisticated, too, if the task of tracing the execution of a + program demands it. </para> <para> - But developing the support for tracing is just one part of the effort - of inserting tracing into a program, and, most likely, not the biggest - part. The other part of the effort is calling the tracing functions at - appropriate times. In large systems, this interaction with the tracing - support can be overwhelming. Plus, tracing is one of those things that - slows the system down, so these calls should often be pulled out of the - system before the product is shipped. For these reasons, it is not - unusual for developers to write ad-hoc scripting programs that rewrite - the source code by inserting/deleting trace calls before and after the - method bodies. + But developing the support for tracing is just one part of the + effort of inserting tracing into a program, and, most likely, not + the biggest part. The other part of the effort is calling the + tracing functions at appropriate times. In large systems, this + interaction with the tracing support can be overwhelming. Plus, + tracing is one of those things that slows the system down, so + these calls should often be pulled out of the system before the + product is shipped. For these reasons, it is not unusual for + developers to write ad-hoc scripting programs that rewrite the + source code by inserting/deleting trace calls before and after + the method bodies. </para> <para> - AspectJ can be used for some of these tracing concerns in a less ad-hoc - way. Tracing can be seen as a concern that crosscuts the entire system - and as such is amenable to encapsulation in an aspect. In addition, it - is fairly independent of what the system is doing. Therefore tracing is - one of those kind of system aspects that can potentially be plugged in - and unplugged without any side-effects in the basic functionality of - the system. + AspectJ can be used for some of these tracing concerns in a less + ad-hoc way. Tracing can be seen as a concern that crosscuts the + entire system and as such is amenable to encapsulation in an + aspect. In addition, it is fairly independent of what the system + is doing. Therefore tracing is one of those kind of system + aspects that can potentially be plugged in and unplugged without + any side-effects in the basic functionality of the system. </para> - </sect3> - <sect3> - <title>An Example Application</title> + <sect3> + <title>An Example Application</title> - <para> - Throughout this example we will use a simple application that contains - only four classes. The application is about shapes. The - <classname>TwoDShape</classname> class is the root of the shape - hierarchy: - </para> + <para> + Throughout this example we will use a simple application that + contains only four classes. The application is about shapes. The + <classname>TwoDShape</classname> class is the root of the shape + hierarchy: + </para> <programlisting><![CDATA[ public abstract class TwoDShape { @@ -698,10 +743,10 @@ public class Square extends TwoDShape { <para> To run this application, compile the classes. You can do it with or - without ajc, the AspectJ compiler. If you've installed AspectJ, go to - the directory - <filename><replaceable>InstallDir</replaceable>/examples</filename> and - type: + without ajc, the AspectJ compiler. If you've installed AspectJ, go + to the directory + <filename><replaceable>InstallDir</replaceable>/examples</filename> + and type: </para> <programlisting> @@ -727,15 +772,16 @@ s1.distance(c1) = 2.23606797749979 s1.toString(): Square side = 1.0 @ (1.0, 2.0) ]]></programlisting> - </sect3> + </sect3> <sect3> <title>Tracing—Version 1</title> <para> - In a first attempt to insert tracing in this application, we will start - by writing a <classname>Trace</classname> class that is exactly what we - would write if we didn't have aspects. The implementation is in - <filename>version1/Trace.java</filename>. Its public interface is: + In a first attempt to insert tracing in this application, we will + start by writing a <classname>Trace</classname> class that is + exactly what we would write if we didn't have aspects. The + implementation is in <filename>version1/Trace.java</filename>. Its + public interface is: </para> <programlisting><![CDATA[ @@ -749,13 +795,14 @@ public class Trace { <para> If we didn't have AspectJ, we would have to insert calls to - <literal>traceEntry</literal> and <literal>traceExit</literal> in all - methods and constructors we wanted to trace, and to initialize - <literal>TRACELEVEL</literal> and the stream. If we wanted to trace all - the methods and constructors in our example, that would amount to - around 40 calls, and we would hope we had not forgotten any method. But - we can do that more consistently and reliably with the following - aspect (found in <filename>version1/TraceMyClasses.java</filename>): + <literal>traceEntry</literal> and <literal>traceExit</literal> in + all methods and constructors we wanted to trace, and to initialize + <literal>TRACELEVEL</literal> and the stream. If we wanted to trace + all the methods and constructors in our example, that would amount + to around 40 calls, and we would hope we had not forgotten any + method. But we can do that more consistently and reliably with the + following aspect (found in + <filename>version1/TraceMyClasses.java</filename>): </para> <programlisting><![CDATA[ @@ -780,22 +827,23 @@ aspect TraceMyClasses { }]]></programlisting> <para> - This aspect performs the tracing calls at appropriate times. According - to this aspect, tracing is performed at the entrance and exit of every - method and constructor defined within the shape hierarchy. + This aspect performs the tracing calls at appropriate + times. According to this aspect, tracing is performed at the + entrance and exit of every method and constructor defined within + the shape hierarchy. </para> <para> - What is printed at before and after each of the traced - join points is the signature of the method executing. Since the - signature is static information, we can get it through + What is printed at before and after each of the traced join points + is the signature of the method executing. Since the signature is + static information, we can get it through <literal>thisJoinPointStaticPart</literal>. </para> <para> To run this version of tracing, go to the directory - <filename><replaceable>InstallDir</replaceable>/examples</filename> and - type: + <filename><replaceable>InstallDir</replaceable>/examples</filename> + and type: </para> <programlisting><![CDATA[ @@ -869,13 +917,13 @@ s1.toString(): Square side = 1.0 @ (1.0, 2.0) <title>Tracing—Version 2</title> <para> - Another way to accomplish the same thing would be to write a reusable - tracing aspect that can be used not only for these application classes, - but for any class. One way to do this is to merge the tracing - functionality of <literal>Trace—version1</literal> with the - crosscutting support of - <literal>TraceMyClasses—version1</literal>. We end up with a - <literal>Trace</literal> aspect (found in + Another way to accomplish the same thing would be to write a + reusable tracing aspect that can be used not only for these + application classes, but for any class. One way to do this is to + merge the tracing functionality of + <literal>Trace—version1</literal> with the crosscutting + support of <literal>TraceMyClasses—version1</literal>. We end + up with a <literal>Trace</literal> aspect (found in <filename>version2/Trace.java</filename>) with the following public interface </para> @@ -892,8 +940,9 @@ abstract aspect Trace { ]]></programlisting> <para> - In order to use it, we need to define our own subclass that knows about - our application classes, in <filename>version2/TraceMyClasses.java</filename>: + In order to use it, we need to define our own subclass that knows + about our application classes, in + <filename>version2/TraceMyClasses.java</filename>: </para> <programlisting><![CDATA[ @@ -909,10 +958,10 @@ public aspect TraceMyClasses extends Trace { ]]></programlisting> <para> - Notice that we've simply made the pointcut <literal>classes</literal>, - that was an abstract pointcut in the super-aspect, concrete. To run - this version of tracing, go to the directory - <filename>examples</filename> and type: + Notice that we've simply made the pointcut + <literal>classes</literal>, that was an abstract pointcut in the + super-aspect, concrete. To run this version of tracing, go to the + directory <filename>examples</filename> and type: </para> <programlisting><![CDATA[ @@ -921,15 +970,15 @@ public aspect TraceMyClasses extends Trace { <para> The file tracev2.lst lists the application classes as well as this - version of the files Trace.java and TraceMyClasses.java. Running the - main method of <classname>tracing.version2.TraceMyClasses</classname> - should output exactly the same trace information as that from version - 1. + version of the files Trace.java and TraceMyClasses.java. Running + the main method of + <classname>tracing.version2.TraceMyClasses</classname> should + output exactly the same trace information as that from version 1. </para> <para> - The entire implementation of the new <classname>Trace</classname> class - is: + The entire implementation of the new <classname>Trace</classname> + class is: </para> <programlisting><![CDATA[ @@ -991,37 +1040,39 @@ abstract aspect Trace { ]]></programlisting> <para> - This version differs from version 1 in several subtle ways. The first - thing to notice is that this <classname>Trace</classname> class merges - the functional part of tracing with the crosscutting of the tracing - calls. That is, in version 1, there was a sharp separation between the - tracing support (the class <classname>Trace</classname>) and the - crosscutting usage of it (by the class - <classname>TraceMyClasses</classname>). In this version those two - things are merged. That's why the description of this class explicitly - says that "Trace messages are printed before and after constructors and - methods are," which is what we wanted in the first place. That is, the - placement of the calls, in this version, is established by the aspect - class itself, leaving less opportunity for misplacing calls.</para> - - <para> - A consequence of this is that there is no need for providing traceEntry - and traceExit as public operations of this class. You can see that they - were classified as protected. They are supposed to be internal + This version differs from version 1 in several subtle ways. The + first thing to notice is that this <classname>Trace</classname> + class merges the functional part of tracing with the crosscutting + of the tracing calls. That is, in version 1, there was a sharp + separation between the tracing support (the class + <classname>Trace</classname>) and the crosscutting usage of it (by + the class <classname>TraceMyClasses</classname>). In this version + those two things are merged. That's why the description of this + class explicitly says that "Trace messages are printed before and + after constructors and methods are," which is what we wanted in the + first place. That is, the placement of the calls, in this version, + is established by the aspect class itself, leaving less opportunity + for misplacing calls.</para> + + <para> + A consequence of this is that there is no need for providing + <literal>traceEntry</literal> and <literal>traceExit</literal> as + public operations of this class. You can see that they were + classified as protected. They are supposed to be internal implementation details of the advice. </para> <para> The key piece of this aspect is the abstract pointcut classes that - serves as the base for the definition of the pointcuts constructors and - methods. Even though <classname>classes</classname> is abstract, and - therefore no concrete classes are mentioned, we can put advice on it, - as well as on the pointcuts that are based on it. The idea is "we don't - know exactly what the pointcut will be, but when we do, here's what we - want to do with it." In some ways, abstract pointcuts are similar to - abstract methods. Abstract methods don't provide the implementation, - but you know that the concrete subclasses will, so you can invoke those - methods. + serves as the base for the definition of the pointcuts constructors + and methods. Even though <classname>classes</classname> is + abstract, and therefore no concrete classes are mentioned, we can + put advice on it, as well as on the pointcuts that are based on + it. The idea is "we don't know exactly what the pointcut will be, + but when we do, here's what we want to do with it." In some ways, + abstract pointcuts are similar to abstract methods. Abstract + methods don't provide the implementation, but you know that the + concrete subclasses will, so you can invoke those methods. </para> </sect3> </sect2> @@ -1030,64 +1081,65 @@ abstract aspect Trace { <!-- ============================================================ --> <!-- ============================================================ --> - <sect1> + <sect1 id="examples-production"> <title>Production Aspects</title> <!-- ==================== --> - <sect2><!-- A Bean Aspect --> - <title>A Bean Aspect</title> + <sect2><!-- A Bean Aspect --> + <title>A Bean Aspect</title> - <para>(The code for this example is in - <filename><replaceable>InstallDir</replaceable>/examples/bean</filename>.) + <para> + (The code for this example is in + <filename><replaceable>InstallDir</replaceable>/examples/bean</filename>.) </para> - <para> - This example examines an aspect that makes Point objects into a Java beans - with bound properties. </para> + <para> + This example examines an aspect that makes Point objects into + Java beans with bound properties. + </para> - <sect3> - <title>Introduction</title> <para> Java beans are reusable software components that can be visually - manipulated in a builder tool. The requirements for an object to be a - bean are few. Beans must define a no-argument constructor and must be - either <classname>Serializable</classname> or + manipulated in a builder tool. The requirements for an object to be + a bean are few. Beans must define a no-argument constructor and + must be either <classname>Serializable</classname> or <classname>Externalizable</classname>. Any properties of the object - that are to be treated as bean properties should be indicated by the - presence of appropriate <literal>get</literal> and + that are to be treated as bean properties should be indicated by + the presence of appropriate <literal>get</literal> and <literal>set</literal> methods whose names are - <literal>get</literal><emphasis>property</emphasis> and - <literal>set </literal><emphasis>property</emphasis> - where <emphasis>property</emphasis> is the name of a field in the bean + <literal>get</literal><emphasis>property</emphasis> and + <literal>set </literal><emphasis>property</emphasis> where + <emphasis>property</emphasis> is the name of a field in the bean class. Some bean properties, known as bound properties, fire events - whenever their values change so that any registered listeners (such as, - other beans) will be informed of those changes. Making a bound property - involves keeping a list of registered listeners, and creating and - dispatching event objects in methods that change the property values, - such as set<emphasis>property</emphasis> methods.</para> + whenever their values change so that any registered listeners (such + as, other beans) will be informed of those changes. Making a bound + property involves keeping a list of registered listeners, and + creating and dispatching event objects in methods that change the + property values, such as set<emphasis>property</emphasis> + methods. + </para> <para> - <classname>Point</classname> is a simple class representing points with - rectangular coordinates. <classname>Point</classname> does not know - anything about being a bean: there are set methods for + <classname>Point</classname> is a simple class representing points + with rectangular coordinates. <classname>Point</classname> does not + know anything about being a bean: there are set methods for <literal>x</literal> and <literal>y</literal> but they do not fire events, and the class is not serializable. Bound is an aspect that - makes <classname>Point</classname> a serializable class and makes its - <literal>get</literal> and <literal>set</literal> methods support the - bound property protocol. + makes <classname>Point</classname> a serializable class and makes + its <literal>get</literal> and <literal>set</literal> methods + support the bound property protocol. </para> - </sect3> <sect3> - <title>The Class <classname>Point</classname></title> + <title>The <classname>Point</classname> class</title> - <para> - The class <classname>Point</classname> is a very simple class with + <para> + The <classname>Point</classname> class is a very simple class with trivial getters and setters, and a simple vector offset method. </para> - <programlisting><![CDATA[ +<programlisting><![CDATA[ class Point { protected int x = 0; @@ -1121,52 +1173,84 @@ class Point { public String toString() { return "(" + getX() + ", " + getY() + ")" ; } -}]]></programlisting> +} +]]></programlisting> </sect3> <sect3> - <title>The Aspect <classname>BoundPoint</classname></title> + <title>The <classname>BoundPoint</classname> aspect</title> <para> - The aspect <classname>BoundPoint</classname> adds "beanness" to - <classname>Point</classname> objects. The first thing it does is - privately introduce a reference to an instance of - <classname>PropertyChangeSupport</classname> into all - <classname>Point</classname> objects. The property change - support object must be constructed with a reference to the bean for - which it is providing support, so it is initialized by passing it this, - an instance of <classname>Point</classname>. The support field is - privately introduced, so only the code in the aspect can refer to it. + The <classname>BoundPoint</classname> aspect is responsible for + <literal>Point</literal>'s "beanness". The first thing it does is + privately declare that each <literal>Point</literal> has a + <literal>support</literal> field that holds reference to an + instance of <classname>PropertyChangeSupport</classname>. + +<programlisting><![CDATA[ + private PropertyChangeSupport Point.support = new PropertyChangeSupport(this); +]]></programlisting> + + The property change support object must be constructed with a + reference to the bean for which it is providing support, so it is + initialized by passing it <literal>this</literal>, an instance of + <classname>Point</classname>. Since the <literal>support</literal> + field is private declared in the aspect, only the code in the + aspect can refer to it. </para> <para> - Methods for registering and managing listeners for property change - events are introduced into <classname>Point</classname> by the - introductions. These methods delegate the work to the - property change support object. + The aspect also declares <literal>Point</literal>'s methods for + registering and managing listeners for property change events, + which delegate the work to the property change support object: + +<programlisting><![CDATA[ + public void Point.addPropertyChangeListener(PropertyChangeListener listener){ + support.addPropertyChangeListener(listener); + } + public void Point.addPropertyChangeListener(String propertyName, + PropertyChangeListener listener){ + + support.addPropertyChangeListener(propertyName, listener); + } + public void Point.removePropertyChangeListener(String propertyName, + PropertyChangeListener listener) { + support.removePropertyChangeListener(propertyName, listener); + } + public void Point.removePropertyChangeListener(PropertyChangeListener listener) { + support.removePropertyChangeListener(listener); + } + public void Point.hasListeners(String propertyName) { + support.hasListeners(propertyName); + } +]]></programlisting> </para> <para> - The introduction also makes <classname>Point</classname> implement the - <classname>Serializable</classname> interface. Implementing - <classname>Serializable</classname> does not require any methods to be - implemented. Serialization for <classname>Point</classname> objects is - provided by the default serialization method. + The aspect is also responsible for making sure + <classname>Point</classname> implements the + <classname>Serializable</classname> interface: + +<programlisting><![CDATA[ + declare parents: Point implements Serializable; +]]></programlisting> + + Implementing this interface in Java does not require any methods to + be implemented. Serialization for <classname>Point</classname> + objects is provided by the default serialization method. </para> <para> - The pointcut <function>setters</function> names the - <literal>set</literal> methods: reception by a - <classname>Point</classname> object of any method whose name begins - with '<literal>set</literal>' and takes one parameter. The around - advice on <literal>setters()</literal> stores the values - of the <literal>X</literal> and <literal>Y</literal> properties, calls - the original <literal>set</literal> method and then fires the - appropriate property change event according to which set method was - called. Note that the call to the method proceed needs to pass along - the <literal>Point p</literal>. The rule of thumb is that context that - an around advice exposes must be passed forward to continue. + The <function>setters</function> pointcut picks out calls to the + <literal>Point</literal>'s <literal>set</literal> methods: any + method whose name begins with "<literal>set</literal>" and takes + one parameter. The around advice on <literal>setters()</literal> + stores the values of the <literal>X</literal> and + <literal>Y</literal> properties, calls the original + <literal>set</literal> method and then fires the appropriate + property change event according to which set method was + called. </para> <programlisting><![CDATA[ @@ -1176,22 +1260,18 @@ aspect BoundPoint { public void Point.addPropertyChangeListener(PropertyChangeListener listener){ support.addPropertyChangeListener(listener); } - public void Point.addPropertyChangeListener(String propertyName, PropertyChangeListener listener){ support.addPropertyChangeListener(propertyName, listener); } - public void Point.removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { support.removePropertyChangeListener(propertyName, listener); } - public void Point.removePropertyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } - public void Point.hasListeners(String propertyName) { support.hasListeners(propertyName); } @@ -1230,12 +1310,12 @@ aspect BoundPoint { <title>The Test Program</title> <para> - The test program registers itself as a property change listener to a - <literal>Point</literal> object that it creates and then performs + The test program registers itself as a property change listener to + a <literal>Point</literal> object that it creates and then performs simple manipulation of that point: calling its set methods and the - offset method. Then it serializes the point and writes it to a file and - then reads it back. The result of saving and restoring the point is that - a new point is created. + offset method. Then it serializes the point and writes it to a file + and then reads it back. The result of saving and restoring the + point is that a new point is created. </para> <programlisting><![CDATA[ @@ -1269,9 +1349,12 @@ aspect BoundPoint { ]]></programlisting> </sect3> + <sect3> <title>Compiling and Running the Example</title> - <para>To compile and run this example, go to the examples directory and type: + + <para> + To compile and run this example, go to the examples directory and type: </para> <programlisting><![CDATA[ @@ -1284,24 +1367,25 @@ java bean.Demo <!-- ==================== --> - <sect2><!-- The Subject/Observer Protocol --> - <title>The Subject/Observer Protocol</title> + <sect2> + <title>The Subject/Observer Protocol</title> - <para>(The code for this example is in - <filename><replaceable>InstallDir</replaceable>/examples/observer</filename>.) + <para> + (The code for this example is in + <filename><replaceable>InstallDir</replaceable>/examples/observer</filename>.) </para> - <para> - This demo illustrates how the Subject/Observer design pattern can be - coded with aspects. </para> + <para> + This demo illustrates how the Subject/Observer design pattern can be + coded with aspects. + </para> - <sect3> - <title>Overview</title> <para> - The demo consists of the following: A colored label is a renderable - object that has a color that cycles through a set of colors, and a - number that records the number of cycles it has been through. A button - is an action item that records when it is clicked. + The demo consists of the following: A colored label is a + renderable object that has a color that cycles through a set of + colors, and a number that records the number of cycles it has been + through. A button is an action item that records when it is + clicked. </para> <para> @@ -1312,22 +1396,22 @@ java bean.Demo </para> <para> - The demo is designed and implemented using the Subject/Observer design - pattern. The remainder of this example explains the classes and aspects - of this demo, and tells you how to run it. + The demo is designed and implemented using the Subject/Observer + design pattern. The remainder of this example explains the classes + and aspects of this demo, and tells you how to run it. </para> - </sect3> <sect3> <title>Generic Components</title> <para> The generic parts of the protocol are the interfaces - <classname>Subject</classname> and <classname>Observer</classname>, and - the abstract aspect <classname>SubjectObserverProtocol</classname>. The - <classname>Subject</classname> interface is simple, containing methods - to add, remove, and view <classname>Observer</classname> objects, and a - method for getting data about state changes: + <classname>Subject</classname> and <classname>Observer</classname>, + and the abstract aspect + <classname>SubjectObserverProtocol</classname>. The + <classname>Subject</classname> interface is simple, containing + methods to add, remove, and view <classname>Observer</classname> + objects, and a method for getting data about state changes: </para> <programlisting><![CDATA[ @@ -1339,9 +1423,10 @@ java bean.Demo } ]]></programlisting> - <para> The <classname>Observer</classname> interface is just as simple, - with methods to set and get <classname>Subject</classname> objects, and - a method to call when the subject gets updated. + <para> + The <classname>Observer</classname> interface is just as simple, + with methods to set and get <classname>Subject</classname> objects, + and a method to call when the subject gets updated. </para> <programlisting><![CDATA[ @@ -1354,9 +1439,9 @@ java bean.Demo <para> The <classname>SubjectObserverProtocol</classname> aspect contains - within it all of the generic parts of the protocol, namely, how to fire - the <classname>Observer</classname> objects' update methods when some - state changes in a subject. + within it all of the generic parts of the protocol, namely, how to + fire the <classname>Observer</classname> objects' update methods + when some state changes in a subject. </para> <programlisting><![CDATA[ @@ -1389,21 +1474,22 @@ java bean.Demo ]]></programlisting> <para> - Note that this aspect does three things. It define an abstract pointcut - that extending aspects can override. It defines advice that should run - after the join points of the pointcut. And it introduces state and - behavior onto the <classname>Subject</classname> and - <classname>Observer</classname> interfaces. + Note that this aspect does three things. It define an abstract + pointcut that extending aspects can override. It defines advice + that should run after the join points of the pointcut. And it + declares an inter-tpye field and two inter-type methods so that + each <literal>Observer</literal> can hold onto its <literal>Subject</literal>. </para> </sect3> <sect3> <title>Application Classes</title> - <para> <classname>Button</classname> objects extend - <classname>java.awt.Button</classname>, and all they do is make sure - the <literal>void click()</literal> method is called whenever a button - is clicked. + <para> + <classname>Button</classname> objects extend + <classname>java.awt.Button</classname>, and all they do is make + sure the <literal>void click()</literal> method is called whenever + a button is clicked. </para> <programlisting><![CDATA[ @@ -1434,6 +1520,7 @@ java bean.Demo <para> Note that this class knows nothing about being a Subject. </para> + <para> ColorLabel objects are labels that support the void colorCycle() method. Again, they know nothing about being an observer. @@ -1489,24 +1576,25 @@ aspect SubjectObserverProtocolImpl extends SubjectObserverProtocol { }]]></programlisting> <para> - It does this by introducing the appropriate interfaces onto the - <classname>Button</classname> and <classname>ColorLabel</classname> - classes, making sure the methods required by the interfaces are - implemented, and providing a definition for the + It does this by assuring that <classname>Button</classname> and + <classname>ColorLabel</classname> implement the appropriate + interfaces, declaring that they implement the methods required by + those interfaces, and providing a definition for the abstract <literal>stateChanges</literal> pointcut. Now, every time a <classname>Button</classname> is clicked, all - <classname>ColorLabel</classname> objects observing that button will - <literal>colorCycle</literal>. + <classname>ColorLabel</classname> objects observing that button + will <literal>colorCycle</literal>. </para> </sect3> <sect3> <title>Compiling and Running</title> - <para> <classname>Demo</classname> is the top class that starts this - demo. It instantiates a two buttons and three observers and links them - together as subjects and observers. So to run the demo, go to the - <filename>examples</filename> directory and type: + <para> + <classname>Demo</classname> is the top class that starts this + demo. It instantiates a two buttons and three observers and links + them together as subjects and observers. So to run the demo, go to + the <filename>examples</filename> directory and type: </para> <programlisting><![CDATA[ @@ -1520,99 +1608,108 @@ aspect SubjectObserverProtocolImpl extends SubjectObserverProtocol { <!-- ==================== --> <sect2> - <title>A Simple Telecom Simulation</title> + <title>A Simple Telecom Simulation</title> - <para>(The code for this example is in - <filename><replaceable>InstallDir</replaceable>/examples/telecom</filename>.) + <para> + (The code for this example is in + <filename><replaceable>InstallDir</replaceable>/examples/telecom</filename>.) </para> - <para> - This example illustrates some ways that dependent concerns can be encoded - with aspects. It uses an example system comprising a simple model of - telephone connections to which timing and billing features are added - using aspects, where the billing feature depends upon the timing feature. - </para> - - <sect3> - <title>The Application</title> - <para> - The example application is a simple simulation of a telephony system in - which customers make, accept, merge and hang-up both local and long - distance calls. The application architecture is in three layers. + This example illustrates some ways that dependent concerns can be + encoded with aspects. It uses an example system comprising a simple + model of telephone connections to which timing and billing features + are added using aspects, where the billing feature depends upon the + timing feature. </para> - <itemizedlist> - <listitem> - <para> - The basic objects provide basic functionality to simulate - customers, calls and connections (regular calls have one - connection, conference calls have more than one). - </para> - </listitem> - <listitem> - <para> - The timing feature is concerned with timing the connections and - keeping the total connection time per customer. Aspects are used to - add a timer to each connection and to manage the total time per - customer. - </para> - </listitem> + <sect3> + <title>The Application</title> + + <para> + The example application is a simple simulation of a telephony + system in which customers make, accept, merge and hang-up both + local and long distance calls. The application architecture is in + three layers. + </para> + + <itemizedlist> + <listitem> + <para> + The basic objects provide basic functionality to simulate + customers, calls and connections (regular calls have one + connection, conference calls have more than one). + </para> + </listitem> + + <listitem> + <para> + The timing feature is concerned with timing the connections + and keeping the total connection time per customer. Aspects + are used to add a timer to each connection and to manage the + total time per customer. + </para> + </listitem> + + <listitem> + <para> + The billing feature is concerned with charging customers for + the calls they make. Aspects are used to calculate a charge + per connection and, upon termination of a connection, to add + the charge to the appropriate customer's bill. The billing + aspect builds upon the timing aspect: it uses a pointcut + defined in Timing and it uses the timers that are associated + with connections. + </para> + </listitem> + </itemizedlist> - <listitem> - <para> - The billing feature is concerned with charging customers for the - calls they make. Aspects are used to calculate a charge per - connection and, upon termination of a connection, to add the charge - to the appropriate customer's bill. The billing aspect builds upon - the timing aspect: it uses a pointcut defined in Timing and it uses - the timers that are associated with connections. - </para> - </listitem> - </itemizedlist> - <para> - The simulation of system has three configurations: basic, timing and - billing. Programs for the three configurations are in classes - <classname>BasicSimulation</classname>, - <classname>TimingSimulation</classname> and - <classname>BillingSimulation</classname>. These share a common - superclass <classname>AbstractSimulation</classname>, which defines the - method run with the simulation itself and the method wait used to - simulate elapsed time. - </para> - </sect3> + <para> + The simulation of system has three configurations: basic, timing + and billing. Programs for the three configurations are in classes + <classname>BasicSimulation</classname>, + <classname>TimingSimulation</classname> and + <classname>BillingSimulation</classname>. These share a common + superclass <classname>AbstractSimulation</classname>, which + defines the method run with the simulation itself and the method + wait used to simulate elapsed time. + </para> + </sect3> - <sect3> - <title>The Basic Objects</title> - - <para> - The telecom simulation comprises the classes - <classname>Customer</classname>, <classname>Call</classname> and the - abstract class <classname>Connection</classname> with its two concrete - subclasses <classname>Local</classname> and - <classname>LongDistance</classname>. Customers have a name and a - numeric area code. They also have methods for managing calls. Simple - calls are made between one customer (the caller) and another (the - receiver), a <classname>Connection</classname> object is used to - connect them. Conference calls between more than two customers will - involve more than one connection. A customer may be involved in many - calls at one time. - <inlinemediaobject> - <imageobject> - <imagedata fileref="telecom.gif"/> - </imageobject> - </inlinemediaobject> - </para> - </sect3> + <sect3> + <title>The Basic Objects</title> - <sect3> - <title>The Class <classname>Customer</classname></title> + <para> + The telecom simulation comprises the classes + <classname>Customer</classname>, <classname>Call</classname> and + the abstract class <classname>Connection</classname> with its two + concrete subclasses <classname>Local</classname> and + <classname>LongDistance</classname>. Customers have a name and a + numeric area code. They also have methods for managing + calls. Simple calls are made between one customer (the caller) + and another (the receiver), a <classname>Connection</classname> + object is used to connect them. Conference calls between more + than two customers will involve more than one connection. A + customer may be involved in many calls at one time. - <para> - <classname>Customer</classname> has methods <literal>call</literal>, - <literal>pickup</literal>, <literal>hangup</literal> and - <literal>merge</literal> for managing calls. - </para> + <inlinemediaobject> + <imageobject> + <imagedata fileref="telecom.gif"/> + </imageobject> + </inlinemediaobject> + </para> + + </sect3> + + <sect3> + <title>The <classname>Customer</classname> class</title> + + <para> + <classname>Customer</classname> has methods + <literal>call</literal>, <literal>pickup</literal>, + <literal>hangup</literal> and <literal>merge</literal> for + managing calls. + </para> <programlisting><![CDATA[ public class Customer { @@ -1669,34 +1766,36 @@ public class Customer { } ]]></programlisting> - </sect3> + </sect3> <sect3> - <title>The Class <classname>Call</classname></title> + <title>The <classname>Call</classname> class</title> <para> - Calls are created with a caller and receiver who are customers. If the - caller and receiver have the same area code then the call can be - established with a <classname>Local</classname> connection (see below), - otherwise a <classname>LongDistance</classname> connection is required. - A call comprises a number of connections between customers. Initially - there is only the connection between the caller and receiver but - additional connections can be added if calls are merged to form - conference calls. + Calls are created with a caller and receiver who are customers. If + the caller and receiver have the same area code then the call can + be established with a <classname>Local</classname> connection (see + below), otherwise a <classname>LongDistance</classname> connection + is required. A call comprises a number of connections between + customers. Initially there is only the connection between the + caller and receiver but additional connections can be added if + calls are merged to form conference calls. </para> </sect3> <sect3> - <title>The Class <classname>Connection</classname></title> + <title>The <classname>Connection</classname> class</title> - <para>The class <classname>Connection</classname> models the physical - details of establishing a connection between customers. It does this - with a simple state machine (connections are initially + <para> + The class <classname>Connection</classname> models the physical + details of establishing a connection between customers. It does + this with a simple state machine (connections are initially <literal>PENDING</literal>, then <literal>COMPLETED</literal> and finally <literal>DROPPED</literal>). Messages are printed to the - console so that the state of connections can be observed. Connection is - an abstract class with two concrete subclasses: - <classname>Local</classname> and <classname>LongDistance</classname>. + console so that the state of connections can be + observed. Connection is an abstract class with two concrete + subclasses: <classname>Local</classname> and + <classname>LongDistance</classname>. </para> <programlisting><![CDATA[ @@ -1739,10 +1838,16 @@ public class Customer { } ]]></programlisting> - </sect3> + </sect3> <sect3> - <title>The Class Local</title> + <title>The <literal>Local</literal> and <literal>LongDistance</literal> classes</title> + + <para> + The two kinds of connections supported by our simulation are + <literal>Local</literal> and <literal>LongDistance</literal> + connections. + </para> <programlisting><![CDATA[ class Local extends Connection { @@ -1754,11 +1859,6 @@ public class Customer { } ]]></programlisting> - </sect3> - - <sect3> - <title>The Class LongDistance</title> - <programlisting><![CDATA[ class LongDistance extends Connection { LongDistance(Customer a, Customer b) { @@ -1776,8 +1876,8 @@ public class Customer { <para> The source files for the basic system are listed in the file - <filename>basic.lst</filename>. To build and run the basic system, in a - shell window, type these commands: + <filename>basic.lst</filename>. To build and run the basic system, + in a shell window, type these commands: </para> <programlisting><![CDATA[ @@ -1788,21 +1888,22 @@ java telecom.BasicSimulation </sect3> <sect3> - <title>Timing</title> + <title>The Timing aspect</title> + <para> The <classname>Timing</classname> aspect keeps track of total - connection time for each <classname>Customer</classname> by starting - and stopping a timer associated with each connection. It uses some - helper classes: + connection time for each <classname>Customer</classname> by + starting and stopping a timer associated with each connection. It + uses some helper classes: </para> <sect4> - <title>The Class <classname>Timer</classname></title> + <title>The <classname>Timer</classname> class</title> <para> - A <classname>Timer</classname> object simply records the current time - when it is started and stopped, and returns their difference when - asked for the elapsed time. The aspect + A <classname>Timer</classname> object simply records the current + time when it is started and stopped, and returns their difference + when asked for the elapsed time. The aspect <classname>TimerLog</classname> (below) can be used to cause the start and stop times to be printed to standard output. </para> @@ -1830,11 +1931,12 @@ java telecom.BasicSimulation </sect3> <sect3> - <title>The Aspect <classname>TimerLog</classname></title> + <title>The <classname>TimerLog</classname> aspect</title> <para> - The aspect <classname>TimerLog</classname> can be included in a - build to get the timer to announce when it is started and stopped. + The <classname>TimerLog</classname> aspect can be included in a + build to get the timer to announce when it is started and + stopped. </para> <programlisting><![CDATA[ @@ -1850,22 +1952,27 @@ public aspect TimerLog { } ]]></programlisting> - </sect3> + </sect3> <sect3> - <title>The Aspect <classname>Timing</classname></title> + <title>The <classname>Timing</classname> aspect</title> <para> - The aspect <classname>Timing</classname> introduces attribute - <literal>totalConnectTime</literal> into the class + The <classname>Timing</classname> aspect is declares an + inter-type field <literal>totalConnectTime</literal> for <classname>Customer</classname> to store the accumulated connection - time per <classname>Customer</classname>. It introduces attribute - timer into <classname>Connection</classname> to associate a timer - with each <classname>Connection</classname>. Two pieces of after - advice ensure that the timer is started when a connection is - completed and and stopped when it is dropped. The pointcut - <literal>endTiming</literal> is defined so that it can be used by the - <classname>Billing</classname> aspect. + time per <classname>Customer</classname>. It also declares that + each <classname>Connection</classname> object has a timer. + +<programlisting><![CDATA[ + public long Customer.totalConnectTime = 0; + private Timer Connection.timer = new Timer(); +]]></programlisting> + + Two pieces of after advice ensure that the timer is started when + a connection is completed and and stopped when it is dropped. The + pointcut <literal>endTiming</literal> is defined so that it can + be used by the <classname>Billing</classname> aspect. </para> <programlisting><![CDATA[ @@ -1893,45 +2000,42 @@ public aspect Timing { } }]]></programlisting> - </sect3> + </sect3> <sect3> - <title>Billing</title> + <title>The <literal>Billing</literal> aspect</title> <para> The Billing system adds billing functionality to the telecom application on top of timing. </para> - <sect4> - <title>The Aspect <classname>Billing</classname></title> - - <para> - The aspect <classname>Billing</classname> introduces attribute - <literal>payer</literal> into <classname>Connection</classname> - to indicate who initiated the call and therefore who is - responsible to pay for it. It also introduces method - <literal>callRate</literal> into <classname>Connection</classname> - so that local and long distance calls can be charged - differently. The call charge must be calculated after the timer is - stopped; the after advice on pointcut - <literal>Timing.endTiming</literal> does this and - <classname>Billing</classname> dominates Timing to make - sure that this advice runs after <classname>Timing's</classname> - advice on the same join point. It introduces attribute - <literal>totalCharge</literal> and its associated methods into - <classname>Customer</classname> (to manage the - customer's bill information. - </para> + <para> + The <classname>Billing</classname> aspect declares that each + <classname>Connection</classname> has a <literal>payer</literal> + inter-type field to indicate who initiated the call and therefore + who is responsible to pay for it. It also declares the inter-type + method <literal>callRate</literal> of + <classname>Connection</classname> so that local and long distance + calls can be charged differently. The call charge must be + calculated after the timer is stopped; the after advice on pointcut + <literal>Timing.endTiming</literal> does this, and + <classname>Billing</classname> is declared to be more precedent + than <classname>Timing</classname> to make sure that this advice + runs after <classname>Timing</classname>'s advice on the same join + point. Finally, it declares inter-type methods and fields for + <classname>Customer</classname> to handle the + <literal>totalCharge</literal>. + </para> <programlisting><![CDATA[ -public aspect Billing dominates Timing { - // domination required to get advice on endtiming in the right order +public aspect Billing { + // precedence required to get advice on endtiming in the right order + declare precedence: Billing, Timing; public static final long LOCAL_RATE = 3; public static final long LONG_DISTANCE_RATE = 10; - public Customer Connection.payer; public Customer getPayer(Connection conn) { return conn.payer; } @@ -1942,11 +2046,9 @@ public aspect Billing dominates Timing { public abstract long Connection.callRate(); - public long LongDistance.callRate() { return LONG_DISTANCE_RATE; } public long Local.callRate() { return LOCAL_RATE; } - after(Connection conn): Timing.endTiming(conn) { long time = Timing.aspectOf().getTimer(conn).getTime(); long rate = conn.callRate(); @@ -1954,7 +2056,6 @@ public aspect Billing dominates Timing { getPayer(conn).addCharge(cost); } - public long Customer.totalCharge = 0; public long getTotalCharge(Customer cust) { return cust.totalCharge; } @@ -1964,30 +2065,31 @@ public aspect Billing dominates Timing { } ]]></programlisting> - </sect4> </sect3> <sect3> - <title>Accessing the Introduced State</title> + <title>Accessing the inter-type state</title> <para> Both the aspects <classname>Timing</classname> and <classname>Billing</classname> contain the definition of operations that the rest of the system may want to access. For example, when - running the simulation with one or both aspects, we want to find out - how much time each customer spent on the telephone and how big their - bill is. That information is also stored in the classes, but they are - accessed through static methods of the aspects, since the state they - refer to is private to the aspect. + running the simulation with one or both aspects, we want to find + out how much time each customer spent on the telephone and how big + their bill is. That information is also stored in the classes, but + they are accessed through static methods of the aspects, since the + state they refer to is private to the aspect. </para> <para> - Take a look at the file <filename>TimingSimulation.java</filename>. The - most important method of this class is the method - <filename>report(Customer c)</filename>, which is used in the method - run of the superclass <classname>AbstractSimulation</classname>. This - method is intended to print out the status of the customer, with - respect to the <classname>Timing</classname> feature. + Take a look at the file + <filename>TimingSimulation.java</filename>. The most important + method of this class is the method + <filename>report(Customer)</filename>, which is used in the method + run of the superclass + <classname>AbstractSimulation</classname>. This method is intended + to print out the status of the customer, with respect to the + <classname>Timing</classname> feature. </para> <programlisting><![CDATA[ @@ -1996,16 +2098,16 @@ public aspect Billing dominates Timing { System.out.println(c + " spent " + t.getTotalConnectTime(c)); } ]]></programlisting> - </sect3> <sect3> <title>Compiling and Running</title> <para> - The files timing.lst and billing.lst contain file lists for the timing - and billing configurations. To build and run the application with only - the timing feature, go to the directory examples and type: + The files timing.lst and billing.lst contain file lists for the + timing and billing configurations. To build and run the application + with only the timing feature, go to the directory examples and + type: </para> <programlisting><![CDATA[ @@ -2014,8 +2116,8 @@ public aspect Billing dominates Timing { ]]></programlisting> <para> - To build and run the application with the timing and billing features, - go to the directory examples and type: + To build and run the application with the timing and billing + features, go to the directory examples and type: </para> <programlisting><![CDATA[ @@ -2029,14 +2131,15 @@ public aspect Billing dominates Timing { <title>Discussion</title> <para> - There are some explicit dependencies between the aspects Billing and - Timing: + There are some explicit dependencies between the aspects Billing + and Timing: + <itemizedlist> <listitem> <para> - Billing is declared to dominate Timing so that Billing's after - advice runs after that of Timing when they are on the same join - point. + Billing is declared more precedent than Timing so that Billing's + after advice runs after that of Timing when they are on the + same join point. </para> </listitem> @@ -2060,86 +2163,88 @@ public aspect Billing dominates Timing { <!-- ============================================================ --> <!-- ============================================================ --> - <sect1> + <sect1 id="examples-reusable"> <title>Reusable Aspects</title> <sect2> - <title>Tracing Aspects Revisited</title> + <title>Tracing using Aspects, Revisited</title> - <para>(The code for this example is in - <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.) + <para> + (The code for this example is in + <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.) </para> - <sect3> - <title>Tracing—Version 3</title> + <sect3> + <title>Tracing—Version 3</title> - <para> - One advantage of not exposing the methods traceEntry and traceExit as - public operations is that we can easily change their interface without - any dramatic consequences in the rest of the code. - </para> + <para> + One advantage of not exposing the methods traceEntry and + traceExit as public operations is that we can easily change their + interface without any dramatic consequences in the rest of the + code. + </para> - <para> - Consider, again, the program without AspectJ. Suppose, for example, - that at some point later the requirements for tracing change, stating - that the trace messages should always include the string representation - of the object whose methods are being traced. This can be achieved in - at least two ways. One way is keep the interface of the methods - <literal>traceEntry</literal> and <literal>traceExit</literal> as it - was before, - </para> + <para> + Consider, again, the program without AspectJ. Suppose, for + example, that at some point later the requirements for tracing + change, stating that the trace messages should always include the + string representation of the object whose methods are being + traced. This can be achieved in at least two ways. One way is + keep the interface of the methods <literal>traceEntry</literal> + and <literal>traceExit</literal> as it was before, + </para> <programlisting><![CDATA[ public static void traceEntry(String str); public static void traceExit(String str); ]]></programlisting> - <para> - In this case, the caller is responsible for ensuring that the string - representation of the object is part of the string given as argument. - So, calls must look like: - </para> + <para> + In this case, the caller is responsible for ensuring that the + string representation of the object is part of the string given + as argument. So, calls must look like: + </para> <programlisting><![CDATA[ Trace.traceEntry("Square.distance in " + toString()); ]]></programlisting> - <para> - Another way is to enforce the requirement with a second argument in the - trace operations, e.g. - </para> + <para> + Another way is to enforce the requirement with a second argument + in the trace operations, e.g. + </para> <programlisting><![CDATA[ public static void traceEntry(String str, Object obj); public static void traceExit(String str, Object obj); ]]></programlisting> - <para> - In this case, the caller is still responsible for sending the right - object, but at least there is some guarantees that some object will be - passed. The calls will look like: - </para> + <para> + In this case, the caller is still responsible for sending the + right object, but at least there is some guarantees that some + object will be passed. The calls will look like: + </para> <programlisting><![CDATA[ Trace.traceEntry("Square.distance", this); ]]></programlisting> - <para> - In either case, this change to the requirements of tracing will have - dramatic consequences in the rest of the code -- every call to the - trace operations traceEntry and traceExit must be changed! - </para> - - <para> - Here's another advantage of doing tracing with an aspect. We've already - seen that in version 2 <literal>traceEntry</literal> and - <literal>traceExit</literal> are not publicly exposed. So changing - their interfaces, or the way they are used, has only a small effect - inside the <classname>Trace</classname> class. Here's a partial view at - the implementation of <classname>Trace</classname>, version 3. The - differences with respect to version 2 are stressed in the - comments: - </para> + <para> + In either case, this change to the requirements of tracing will + have dramatic consequences in the rest of the code -- every call + to the trace operations traceEntry and traceExit must be changed! + </para> + + <para> + Here's another advantage of doing tracing with an aspect. We've + already seen that in version 2 <literal>traceEntry</literal> and + <literal>traceExit</literal> are not publicly exposed. So + changing their interfaces, or the way they are used, has only a + small effect inside the <classname>Trace</classname> + class. Here's a partial view at the implementation of + <classname>Trace</classname>, version 3. The differences with + respect to version 2 are stressed in the comments: + </para> <programlisting><![CDATA[ abstract aspect Trace { @@ -2174,13 +2279,11 @@ abstract aspect Trace { stream.println("Exiting " + str); } - private static void printIndent() { for (int i = 0; i < callDepth; i++) stream.print(" "); } - abstract pointcut myClass(Object obj); pointcut myConstructor(Object obj): myClass(obj) && execution(new(..)); @@ -2204,57 +2307,58 @@ abstract aspect Trace { ]]></programlisting> <para> - As you can see, we decided to apply the first design by preserving the - interface of the methods <literal>traceEntry</literal> and - <literal>traceExit</literal>. But it doesn't matter—we could as - easily have applied the second design (the code in the directory - <filename>examples/tracing/version3</filename> has the second design). - The point is that the effects of this change in the tracing - requirements are limited to the <classname>Trace</classname> aspect - class. + As you can see, we decided to apply the first design by preserving + the interface of the methods <literal>traceEntry</literal> and + <literal>traceExit</literal>. But it doesn't matter—we could + as easily have applied the second design (the code in the directory + <filename>examples/tracing/version3</filename> has the second + design). The point is that the effects of this change in the + tracing requirements are limited to the + <classname>Trace</classname> aspect class. </para> <para> - One implementation change worth noticing is the specification of the - pointcuts. They now expose the object. To maintain full consistency - with the behavior of version 2, we should have included tracing for - static methods, by defining another pointcut for static methods and - advising it. We leave that as an exercise. + One implementation change worth noticing is the specification of + the pointcuts. They now expose the object. To maintain full + consistency with the behavior of version 2, we should have included + tracing for static methods, by defining another pointcut for static + methods and advising it. We leave that as an exercise. </para> <para> Moreover, we had to exclude the execution join point of the method <filename>toString</filename> from the <literal>methods</literal> - pointcut. The problem here is that <literal>toString</literal> is being - called from inside the advice. Therefore if we trace it, we will end - up in an infinite recursion of calls. This is a subtle point, and one - that you must be aware when writing advice. If the advice calls back to - the objects, there is always the possibility of recursion. Keep that in - mind! + pointcut. The problem here is that <literal>toString</literal> is + being called from inside the advice. Therefore if we trace it, we + will end up in an infinite recursion of calls. This is a subtle + point, and one that you must be aware when writing advice. If the + advice calls back to the objects, there is always the possibility + of recursion. Keep that in mind! </para> <para> - In fact, esimply excluding the execution join point may not be enough, - if there are calls to other traced methods within it -- in which case, - the restriction should be + In fact, esimply excluding the execution join point may not be + enough, if there are calls to other traced methods within it -- in + which case, the restriction should be </para> - + <programlisting><![CDATA[ && !cflow(execution(String toString())) ]]></programlisting> <para> - excluding both the execution of toString methods and all join points - under that execution. + excluding both the execution of toString methods and all join + points under that execution. </para> <para> - In summary, to implement the change in the tracing requirements we had - to make a couple of changes in the implementation of the + In summary, to implement the change in the tracing requirements we + had to make a couple of changes in the implementation of the <classname>Trace</classname> aspect class, including changing the specification of the pointcuts. That's only natural. But the - implementation changes were limited to this aspect. Without aspects, we - would have to change the implementation of every application class. + implementation changes were limited to this aspect. Without + aspects, we would have to change the implementation of every + application class. </para> <para> @@ -2332,12 +2436,3 @@ s1.toString(): Square side = 1.0 @ (1.0, 2.0) </sect2> </sect1> </chapter> - -<!-- -Local variables: -compile-command: "java sax.SAXCount -v progguide.xml && java com.icl.saxon.StyleSheet -w0 progguide.xml progguide.html.xsl" -fill-column: 79 -sgml-local-ecat-files: "progguide.ced" -sgml-parent-document:("progguide.xml" "book" "chapter") -End: ---> |