aboutsummaryrefslogtreecommitdiffstats
path: root/docs/progGuideDB/examples.xml
diff options
context:
space:
mode:
Diffstat (limited to 'docs/progGuideDB/examples.xml')
-rw-r--r--docs/progGuideDB/examples.xml1567
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 &mdash; 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 &mdash; 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 &mdash; 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&mdash;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&mdash;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&mdash;version1</literal> with the
- crosscutting support of
- <literal>TraceMyClasses&mdash;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&mdash;version1</literal> with the crosscutting
+ support of <literal>TraceMyClasses&mdash;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&mdash;Version 3</title>
+ <sect3>
+ <title>Tracing&mdash;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&mdash;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&mdash;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:
--->