diff options
Diffstat (limited to 'docs/progGuideDB')
-rw-r--r-- | docs/progGuideDB/aspectjdoc.dsl | 124 | ||||
-rw-r--r-- | docs/progGuideDB/aspects.gif | bin | 0 -> 7071 bytes | |||
-rw-r--r-- | docs/progGuideDB/bibliography.xml | 70 | ||||
-rw-r--r-- | docs/progGuideDB/build.sh | 79 | ||||
-rw-r--r-- | docs/progGuideDB/examples.xml | 2343 | ||||
-rw-r--r-- | docs/progGuideDB/figureUML.gif | bin | 0 -> 3480 bytes | |||
-rw-r--r-- | docs/progGuideDB/gettingstarted.xml | 1090 | ||||
-rw-r--r-- | docs/progGuideDB/glossary.xml | 192 | ||||
-rw-r--r-- | docs/progGuideDB/idioms.xml | 104 | ||||
-rw-r--r-- | docs/progGuideDB/language.xml | 1226 | ||||
-rw-r--r-- | docs/progGuideDB/limitations.xml | 123 | ||||
-rw-r--r-- | docs/progGuideDB/overview.gif | bin | 0 -> 2576 bytes | |||
-rw-r--r-- | docs/progGuideDB/pitfalls.xml | 103 | ||||
-rw-r--r-- | docs/progGuideDB/preface.xml | 52 | ||||
-rw-r--r-- | docs/progGuideDB/progguide.html.xsl | 9 | ||||
-rw-r--r-- | docs/progGuideDB/progguide.xml | 83 | ||||
-rw-r--r-- | docs/progGuideDB/quickreference.xml | 658 | ||||
-rw-r--r-- | docs/progGuideDB/semantics.xml | 2361 | ||||
-rw-r--r-- | docs/progGuideDB/telecom.gif | bin | 0 -> 4047 bytes |
19 files changed, 8617 insertions, 0 deletions
diff --git a/docs/progGuideDB/aspectjdoc.dsl b/docs/progGuideDB/aspectjdoc.dsl new file mode 100644 index 000000000..37ce64bd6 --- /dev/null +++ b/docs/progGuideDB/aspectjdoc.dsl @@ -0,0 +1,124 @@ +<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+ <!ENTITY html-ss PUBLIC "-//Norman Walsh//DOCUMENT DocBook HTML Stylesheet//EN" CDATA DSSSL>
+ <!ENTITY print-ss PUBLIC "-//Norman Walsh//DOCUMENT DocBook Print Stylesheet//EN" CDATA DSSSL>
+]>
+
+<style-sheet>
+
+<!-- Customizations for the HTML version -->
+
+<style-specification id="html" use="html-stylesheet">
+<style-specification-body>
+
+;; Specify the CSS stylesheet to use
+(define %stylesheet% "../../style.css")
+
+;; Suppress Lists of Tables, Examples, ...
+(define ($generate-book-lot-list$)
+ '())
+
+;; Display only the first two section levels in the table of contents
+(define (toc-depth nd)
+ (if (string=? (gi nd) (normalize "book"))
+ 2
+ 1))
+
+;; Make references be appendices (or chapters), not parts.
+(define (en-label-number-format-list)
+ (list
+ (list (normalize "set") "1")
+ (list (normalize "book") "1")
+ (list (normalize "prefix") "1")
+ (list (normalize "part") "I")
+ (list (normalize "chapter") "1")
+ (list (normalize "appendix") "A")
+ ;;(list (normalize "reference") "1") ; references-as-chapters
+ (list (normalize "reference") "A") ; references-as-appendices
+ (list (normalize "example") "1")
+ (list (normalize "figure") "1")
+ (list (normalize "table") "1")
+ (list (normalize "procedure") "1")
+ (list (normalize "step") "1")
+ (list (normalize "refsect1") "1")
+ (list (normalize "refsect2") "1")
+ (list (normalize "refsect3") "1")
+ (list (normalize "sect1") "1")
+ (list (normalize "sect2") "1")
+ (list (normalize "sect3") "1")
+ (list (normalize "sect4") "1")
+ (list (normalize "sect5") "1")
+ (list (normalize "section") "1")
+ ))
+ ;;; for references-as-appendices
+ (define (reference-number-sibling-list cmp) (list (normalize "appendix")))
+ (define (appendix-number-sibling-list cmp) (list (normalize "reference")))
+ ;;; for references-as-chapters
+ ;;(define (reference-number-sibling-list cmp) (list (normalize "chapter")))
+ ;;(define (chapter-number-sibling-list cmp) (list (normalize "reference")))
+
+
+</style-specification-body>
+</style-specification>
+<external-specification id="html-stylesheet" document="html-ss">
+
+
+<!-- Customizations for the print version -->
+
+<style-specification id="print" use="print-stylesheet">
+<style-specification-body>
+
+;; Suppress Lists of Tables, Examples, ...
+(define ($generate-book-lot-list$)
+ '())
+
+;; Display only the first two section levels in the table of contents
+(define (toc-depth nd)
+ (if (string=? (gi nd) (normalize "book"))
+ 2
+ 1))
+
+(define %two-side% #t)
+(define bop-footnotes #t) ; doesn't seem to work
+
+;; Make references be appendices (or chapters), not parts.
+(define (en-label-number-format-list)
+ (list
+ (list (normalize "set") "1")
+ (list (normalize "book") "1")
+ (list (normalize "prefix") "1")
+ (list (normalize "part") "I")
+ (list (normalize "chapter") "1")
+ (list (normalize "appendix") "A")
+ ;;(list (normalize "reference") "1") ; references-as-chapters
+ (list (normalize "reference") "A") ; references-as-appendices
+ (list (normalize "example") "1")
+ (list (normalize "figure") "1")
+ (list (normalize "table") "1")
+ (list (normalize "procedure") "1")
+ (list (normalize "step") "1")
+ (list (normalize "refsect1") "1")
+ (list (normalize "refsect2") "1")
+ (list (normalize "refsect3") "1")
+ (list (normalize "sect1") "1")
+ (list (normalize "sect2") "1")
+ (list (normalize "sect3") "1")
+ (list (normalize "sect4") "1")
+ (list (normalize "sect5") "1")
+ (list (normalize "section") "1")
+ ))
+ ;;; for references-as-appendices
+ (define (reference-number-sibling-list cmp) (list (normalize "appendix")))
+ (define (appendix-number-sibling-list cmp) (list (normalize "reference")))
+ ;;; for references-as-chapters
+ ;;(define (reference-number-sibling-list cmp) (list (normalize "chapter")))
+ ;;(define (chapter-number-sibling-list cmp) (list (normalize "reference")))
+
+</style-specification-body>
+</style-specification>
+<external-specification id="print-stylesheet" document="print-ss">
+
+</style-sheet>
+
+<!-- Local Variables -->
+<!-- mode: scheme -->
+<!-- End -->
diff --git a/docs/progGuideDB/aspects.gif b/docs/progGuideDB/aspects.gif Binary files differnew file mode 100644 index 000000000..8bca684ad --- /dev/null +++ b/docs/progGuideDB/aspects.gif diff --git a/docs/progGuideDB/bibliography.xml b/docs/progGuideDB/bibliography.xml new file mode 100644 index 000000000..4d6c1f80f --- /dev/null +++ b/docs/progGuideDB/bibliography.xml @@ -0,0 +1,70 @@ +<bibliography> + + <title>Bibliography</title> + +<!-- <biblioentry> --> +<!-- <authorgroup> --> +<!-- <author> --> +<!-- <firstname></firstname> <surname></surname> --> +<!-- </author> --> +<!-- </authorgroup> --> +<!-- <title></title> --> +<!-- <publisher> --> +<!-- <publishername></publishername> --> +<!-- <address><city></city></address> --> +<!-- </publisher> --> +<!-- <copyright><year></year></copyright> --> +<!-- </biblioentry> --> + +<!-- The state element doesn't appear in HTML, so overload the city element. --> + + <biblioentry> + <authorgroup> + <author> + <firstname>Doug</firstname> <surname>Lea</surname> + </author> + </authorgroup> + <title>Concurrent Programming in Java, Second Edition</title> + <publisher> + <publishername>Addison-Wesley</publishername> + <address><city>Reading, MA</city></address> + </publisher> + <copyright><year>1999</year></copyright> + </biblioentry> + + <biblioentry> + <authorgroup> + <author> + <firstname>Gregor</firstname> <surname>Kiczales, et al</surname> + </author> + </authorgroup> + <title>An Overview of AspectJ</title> + <publisher> + <publishername>in Proceedings of the 5th European Conference on Object + Oriented Programming (ECOOP), Springer</publishername> + <address><city>Budapest, Hungary</city></address> + </publisher> + <copyright><year>2001</year></copyright> + </biblioentry> + + <biblioentry> + <authorgroup> + <author> + <firstname>Betrand</firstname><surname>Meyer</surname> + </author> + </authorgroup> + <title>Object-Oriented Software Construction, 2/e</title> + <publisher> + <publishername>Prentice-Hall</publishername> + <address><city>New York, NY</city></address> + </publisher> + <copyright><year>1999</year></copyright> + </biblioentry> + +</bibliography> + +<!-- Local variables: --> +<!-- fill-column: 79 --> +<!-- sgml-local-ecat-files: progguide.ced --> +<!-- sgml-parent-document:("progguide.sgml" "book" "bibliography") --> +<!-- End: --> diff --git a/docs/progGuideDB/build.sh b/docs/progGuideDB/build.sh new file mode 100644 index 000000000..19499ff3b --- /dev/null +++ b/docs/progGuideDB/build.sh @@ -0,0 +1,79 @@ +#/bin/sh
+
+JAVA_HOME="/opt/IBMJava2-13"
+DOCBOOK_HOME="/usr/local/docbook"
+
+SAXON="/home/vladimir/aspectj-external-lib/saxon"
+XERCES="/usr/local/xerces-1_4_3"
+
+saxon() { java -cp $SAXON/saxon.jar com.icl.saxon.StyleSheet $*; }
+xerces() { java -cp $XERCES/xercesSamples.jar sax.SAXCount -v $* ; }
+
+# echo ""; echo ""
+# echo "The following REMARKS still exist:"; echo ""
+# egrep -n -A3 "<remark>" *.xml
+# echo ""; echo ""
+
+# echo "Checking for required RPMS..."
+# for RPM in docbook-dtd docbook-xsl; do
+# rpm -q $RPM >/dev/null
+# if [ $? = 1 ]; then
+# echo "${RPM}: Required RPM not installed. Exiting..."
+# exit 1
+# fi
+# done
+
+# echo "Checking for required programs..."
+# for PROG in java tex; do
+# type $PROG >/dev/null 2>/dev/null
+# if [ $? = 1 ]; then
+# echo "$prog not found in PATH. Exiting..."
+# exit 1
+# fi
+# done
+
+# echo "Checking for required files..."
+# for FILE in $JAVA_HOME/jre/lib/ext/saxon.jar; do
+# if [ ! -s $FILE ]; then
+# echo "$FILE not found. Exiting..."
+# exit 1
+# fi
+# done
+
+OPT=$1
+shift 1
+
+if [ "$OPT" == "-v" ]; then
+ COMMAND="xerces -v progguide.xml"
+ echo "
Validating the XML source: $COMMAND"
+ ${COMMAND}
+fi
+
+if [ "$OPT" == "-t" ]; then
+ COMMAND='openjade -t tex -d aspectjdoc.dsl#print /usr/share/sgml/xml.dcl progguide.xml'
+ echo "
Creating TeX from XML: $COMMAND"
+ ${COMMAND}
+ COMMAND="pdfjadetex progguide.tex"
+ echo "
Creating PDF from TeX: $COMMAND"
+ ${COMMAND}
+ ${COMMAND}
+ exit
+fi
+
+COMMAND="saxon -w0 progguide.xml progguide.html.xsl"
+echo "
Transforming XML to HTML: $COMMAND"
+${COMMAND}
+
+# echo "Transforming XML to FO..."
+# saxon -w0 -o progguide.fo progguide.xml ${XSL_STYLESHEET_HOME}/fo/docbook.xsl >progguide.fo.log 2>&1
+
+# echo -n "Transforming FO to PostScript"
+# tex --interaction nonstopmode -fmt /usr/local/texmf/tex/xmltex/base/xmltex progguide.fo >|progguide.ps.1.log 2>&1
+# echo "Pass 2..."
+# tex --interaction nonstopmode -fmt /usr/local/texmf/tex/xmltex/base/xmltex progguide.fo >|progguide.ps.2.log 2>&1
+# dvips progguide -o
+
+# echo "Transforming FO to PDF..."
+# pdflatex --interaction nonstopmode -fmt /usr/local/texmf/tex/xmltex/base/pdfxmltex progguide.fo >|progguide.pdf.log
+
+
diff --git a/docs/progGuideDB/examples.xml b/docs/progGuideDB/examples.xml new file mode 100644 index 000000000..2e6a1715d --- /dev/null +++ b/docs/progGuideDB/examples.xml @@ -0,0 +1,2343 @@ +<chapter id="examples" xreflabel="Examples"> + <title>Examples</title> + + <sect1><!-- About this Chapter --> + <title>About this Chapter</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>The examples can be grouped into four categories:</para> + + <simplelist columns="2" type="horiz"> + <member><emphasis role="bold">technique</emphasis></member> + <member>Examples which illustrate how to use one or more features of the + language. </member> + + <member><emphasis role="bold">development</emphasis></member> + <member>Examples of using AspectJ during the development phase of a + project. </member> + + <member><emphasis role="bold">production</emphasis></member> + <member>Examples of using AspectJ to provide functionality in an + application. </member> + + <member><emphasis role="bold">reusable</emphasis></member> + <member>Examples of reuse of aspects and pointcuts.</member> + </simplelist> + + </sect1> + + + <sect1> + <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>Compiling most examples should be 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> + +<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 + <literal>-classpath</literal> command line option to the Java + interpreter:</para> + +<programlisting> +(In Unix use a : in the CLASSPATH) +java -classpath ".:<replaceable>InstallDir</replaceable>/lib/aspectjrt.jar" telecom.billingSimulation +</programlisting> + +<programlisting> +(In Windows use a ; in the CLASSPATH) +java -classpath ".;<replaceable>InstallDir</replaceable>/lib/aspectjrt.jar" telecom.billingSimulation +</programlisting> + + </sect1> + + +<!-- ============================================================ --> +<!-- ============================================================ --> + + + <sect1> + <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>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> + +<!-- ======================================== --> + + <sect2 id="sec:JoinPointsAndtjp"><!-- Join Points and thisJoinPoint --> + <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>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>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> + +<programlisting><![CDATA[ +before(Point p, int x): target(p) + && args(x) + && call(void setX(int)) { + if (!p.assertX(x)) { + System.out.println("Illegal value for x"); return; + } +} +]]></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> + +<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>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> + + <itemizedlist spacing="compact"> + <listitem>the kind of join point that was matched + </listitem> + <listitem>the source location of the current 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> + + </itemizedlist> + + <sect3> + <title>The <classname>Demo</classname> class</title> + + <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> + +<programlisting><![CDATA[ +public class Demo { + + static Demo d; + + public static void main(String[] args){ + new Demo().go(); + } + + void go(){ + d = new Demo(); + d.foo(1,d); + System.out.println(d.bar(new Integer(3))); + } + + void foo(int i, Object o){ + 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> + + <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> + +<programlisting><![CDATA[ +aspect GetInfo { + + static final void println(String s){ System.out.println(s); } + + pointcut goCut(): cflow(this(Demo) && execution(void go())); + + pointcut demoExecs(): within(Demo) && execution(* *(..)); + + Object around(): demoExecs() && !execution(* go()) && goCut() { + println("Intercepted message: " + + thisJoinPointStaticPart.getSignature().getName()); + println("in class: " + + thisJoinPointStaticPart.getSignature().getDeclaringType().getName()); + printParameters(thisJoinPoint); + println("Running original method: \n" ); + Object result = proceed(); + println(" result: " + result ); + return result; + } + + static private void printParameters(JoinPoint jp) { + println("Arguments: " ); + Object[] args = jp.getArgs(); + String[] names = ((CodeSignature)jp.getSignature()).getParameterNames(); + Class[] types = ((CodeSignature)jp.getSignature()).getParameterTypes(); + for (int i = 0; i < args.length; i++) { + println(" " + i + ". " + names[i] + + " : " + types[i].getName() + + " = " + args[i]); + } + } +} +]]></programlisting> + </sect4> + + <sect4> + <title>Printing the parameters</title> + + <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> + 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> + </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> + + <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>This is crucial: Affecting the class structure of an application at + makes these modifications available to other components of the + application.</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>and by making the class</para> + + <itemizedlist spacing="compact"> + <listitem>implement interfaces</listitem> + <listitem>extend classes</listitem> + </itemizedlist> + + <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> + + <sect3> + <title>The class <classname>Point</classname></title> + + <para>The class <classname>Point</classname> 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 + coordinates, plus flags to indicate which currently reflect the + position of the point. Some operations cause the polar coordinates to + be updated from the rectangular, and some have the opposite effect. + This implementation, which is in intended to give the minimum number + of conversions between coordinate systems, has the property that not + all the attributes stored in a <classname>Point</classname> object + are necessary to give a canonical representation such as might be + used for storing, comparing, cloning or making hash codes from + points. Thus the aspects, though simple, are not totally trivial. + </para> + + <para> + The diagram below gives an overview of the aspects and their + interaction with the class <classname>Point</classname>.</para> + + <para> + <inlinemediaobject> + <imageobject> + <imagedata fileref="aspects.gif"/> + </imageobject> + </inlinemediaobject> + </para> + <para></para> + + </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[ +public aspect CloneablePoint { + + declare parents: Point implements Cloneable; + + public Object Point.clone() throws CloneNotSupportedException { + // we choose to bring all fields up to date before cloning. + makeRectangular(); + makePolar(); + return super.clone(); + } + + public static void main(String[] args){ + Point p1 = new Point(); + Point p2 = null; + + p1.setPolar(Math.PI, 1.0); + try { + p2 = (Point)p1.clone(); + } catch (CloneNotSupportedException e) {} + System.out.println("p1 =" + p1 ); + System.out.println("p2 =" + p2 ); + + p1.rotate(Math.PI / -2); + System.out.println("p1 =" + p1 ); + System.out.println("p2 =" + p2 ); + } +} +]]></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> + + <para>This second example introduces another interface and + method into the class <classname>Point</classname>.</para> + + <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[ +public aspect ComparablePoint { + + declare parents: Point implements Comparable; + + public int Point.compareTo(Object o) { + return (int) (this.getRho() - ((Point)o).getRho()); + } + + public static void main(String[] args){ + Point p1 = new Point(); + Point p2 = new Point(); + + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.setRectangular(2,5); + p2.setRectangular(2,5); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p2.setRectangular(3,6); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.setPolar(Math.PI, 4); + p2.setPolar(Math.PI, 4); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.rotate(Math.PI / 4.0); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.offset(1,1); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + } +}]]></programlisting> + </sect3> + + <sect3> + <title>Making <classname>Point</classname>s Hashable — The Aspect + <classname>HashablePoint</classname></title> + + <para>The third aspect overrides two previously defined methods to + give to <classname>Point</classname> the hashing behavior we + want.</para> + + <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 + for objects that test equal. But since the default implementation + of <literal>Object.equal</literal> returns <literal>true</literal> + only when two objects are identical, we need to redefine both + <function>equals</function> and <function>hashCode</function> to work + correctly with objects of type <classname>Point</classname>. For + example, we want two <classname>Point</classname> objects to test + equal when they have the same <literal>x</literal> and + <literal>y</literal> values, or the same <literal>rho</literal> and + <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[ +public aspect HashablePoint { + + public int Point.hashCode() { + return (int) (getX() + getY() % Integer.MAX_VALUE); + } + + public boolean Point.equals(Object o) { + if (o == this) { return true; } + if (!(o instanceof Point)) { return false; } + Point other = (Point)o; + return (getX() == other.getX()) && (getY() == other.getY()); + } + + public static void main(String[] args) { + Hashtable h = new Hashtable(); + Point p1 = new Point(); + + p1.setRectangular(10, 10); + Point p2 = new Point(); + + p2.setRectangular(10, 10); + + System.out.println("p1 = " + p1); + System.out.println("p2 = " + p2); + System.out.println("p1.hashCode() = " + p1.hashCode()); + System.out.println("p2.hashCode() = " + p2.hashCode()); + + h.put(p1, "P1"); + System.out.println("Got: " + h.get(p2)); + } +} +]]></programlisting> + + <para> Again, we supply a <literal>main</literal> method in the aspect + for testing. + </para> + + </sect3> + + </sect2> + + </sect1> + +<!-- ============================================================ --> +<!-- ============================================================ --> + + <sect1> + <title>Development Aspects</title> + + <sect2> + <title>Tracing Aspects</title> + + <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> + + <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. + </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. + </para> + </sect3> + + <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> + +<programlisting><![CDATA[ +public abstract class TwoDShape { + protected double x, y; + protected TwoDShape(double x, double y) { + this.x = x; this.y = y; + } + public double getX() { return x; } + public double getY() { return y; } + public double distance(TwoDShape s) { + double dx = Math.abs(s.getX() - x); + double dy = Math.abs(s.getY() - y); + return Math.sqrt(dx*dx + dy*dy); + } + public abstract double perimeter(); + public abstract double area(); + public String toString() { + return (" @ (" + String.valueOf(x) + ", " + String.valueOf(y) + ") "); + } +} +]]></programlisting> + + <para> + <classname>TwoDShape</classname> has two subclasses, + <classname>Circle</classname> and <classname>Square</classname>: + </para> + +<programlisting><![CDATA[ +public class Circle extends TwoDShape { + protected double r; + public Circle(double x, double y, double r) { + super(x, y); this.r = r; + } + public Circle(double x, double y) { this( x, y, 1.0); } + public Circle(double r) { this(0.0, 0.0, r); } + public Circle() { this(0.0, 0.0, 1.0); } + public double perimeter() { + return 2 * Math.PI * r; + } + public double area() { + return Math.PI * r*r; + } + public String toString() { + return ("Circle radius = " + String.valueOf(r) + super.toString()); + } +} +]]></programlisting> + +<programlisting><![CDATA[ +public class Square extends TwoDShape { + protected double s; // side + public Square(double x, double y, double s) { + super(x, y); this.s = s; + } + public Square(double x, double y) { this( x, y, 1.0); } + public Square(double s) { this(0.0, 0.0, s); } + public Square() { this(0.0, 0.0, 1.0); } + public double perimeter() { + return 4 * s; + } + public double area() { + return s*s; + } + public String toString() { + return ("Square side = " + String.valueOf(s) + super.toString()); + } +} +]]></programlisting> + + <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: + </para> + +<programlisting> +ajc -argfile tracing/notrace.lst +</programlisting> + + <para>To run the program, type</para> + +<programlisting> +java tracing.ExampleMain +</programlisting> + + <para>(we don't need anything special on the classpath since this is pure + Java code). You should see the following output:</para> + +<programlisting><![CDATA[ +c1.perimeter() = 12.566370614359172 +c1.area() = 12.566370614359172 +s1.perimeter() = 4.0 +s1.area() = 1.0 +c2.distance(c1) = 4.242640687119285 +s1.distance(c1) = 2.23606797749979 +s1.toString(): Square side = 1.0 @ (1.0, 2.0) +]]></programlisting> + + </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: + </para> + +<programlisting><![CDATA[ +public class Trace { + public static int TRACELEVEL = 0; + public static void initStream(PrintStream s) {...} + public static void traceEntry(String str) {...} + public static void traceExit(String str) {...} +} +]]></programlisting> + + <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>): + </para> + +<programlisting><![CDATA[ +aspect TraceMyClasses { + pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); + pointcut myConstructor(): myClass() && execution(new(..)); + pointcut myMethod(): myClass() && execution(* *(..)); + + before (): myConstructor() { + Trace.traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myConstructor() { + Trace.traceExit("" + thisJoinPointStaticPart.getSignature()); + } + + before (): myMethod() { + Trace.traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myMethod() { + Trace.traceExit("" + thisJoinPointStaticPart.getSignature()); + } +}]]></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. + </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 + <literal>thisJoinPointStaticPart</literal>. + </para> + + <para> + To run this version of tracing, go to the directory + <filename><replaceable>InstallDir</replaceable>/examples</filename> and + type: + </para> + +<programlisting><![CDATA[ + ajc -argfile tracing/tracev1.lst +]]></programlisting> + + <para> + Running the main method of + <classname>tracing.version1.TraceMyClasses</classname> should produce + the output: + </para> + +<programlisting><![CDATA[ + --> tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Circle(double, double, double) + <-- tracing.Circle(double, double, double) + --> tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Circle(double, double, double) + <-- tracing.Circle(double, double, double) + --> tracing.Circle(double) + <-- tracing.Circle(double) + --> tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Square(double, double, double) + <-- tracing.Square(double, double, double) + --> tracing.Square(double, double) + <-- tracing.Square(double, double) + --> double tracing.Circle.perimeter() + <-- double tracing.Circle.perimeter() +c1.perimeter() = 12.566370614359172 + --> double tracing.Circle.area() + <-- double tracing.Circle.area() +c1.area() = 12.566370614359172 + --> double tracing.Square.perimeter() + <-- double tracing.Square.perimeter() +s1.perimeter() = 4.0 + --> double tracing.Square.area() + <-- double tracing.Square.area() +s1.area() = 1.0 + --> double tracing.TwoDShape.distance(TwoDShape) + --> double tracing.TwoDShape.getX() + <-- double tracing.TwoDShape.getX() + --> double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.distance(TwoDShape) +c2.distance(c1) = 4.242640687119285 + --> double tracing.TwoDShape.distance(TwoDShape) + --> double tracing.TwoDShape.getX() + <-- double tracing.TwoDShape.getX() + --> double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.distance(TwoDShape) +s1.distance(c1) = 2.23606797749979 + --> String tracing.Square.toString() + --> String tracing.TwoDShape.toString() + <-- String tracing.TwoDShape.toString() + <-- String tracing.Square.toString() +s1.toString(): Square side = 1.0 @ (1.0, 2.0) +]]></programlisting> + + <para> + When <filename>TraceMyClasses.java</filename> is not provided to + <command>ajc</command>, the aspect does not have any affect on the + system and the tracing is unplugged. + </para> + </sect3> + + <sect3> + <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 + <filename>version2/Trace.java</filename>) with the following public + interface + </para> + +<programlisting><![CDATA[ +abstract aspect Trace { + + public static int TRACELEVEL = 2; + public static void initStream(PrintStream s) {...} + protected static void traceEntry(String str) {...} + protected static void traceExit(String str) {...} + abstract pointcut myClass(); +} +]]></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>: + </para> + +<programlisting><![CDATA[ +public aspect TraceMyClasses extends Trace { + pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); + + public static void main(String[] args) { + Trace.TRACELEVEL = 2; + Trace.initStream(System.err); + ExampleMain.main(args); + } +} +]]></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: + </para> + +<programlisting><![CDATA[ + ajc -argfile tracing/tracev2.lst +]]></programlisting> + + <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. + </para> + + <para> + The entire implementation of the new <classname>Trace</classname> class + is: + </para> + +<programlisting><![CDATA[ +abstract aspect Trace { + + // implementation part + + public static int TRACELEVEL = 2; + protected static PrintStream stream = System.err; + protected static int callDepth = 0; + + public static void initStream(PrintStream s) { + stream = s; + } + protected static void traceEntry(String str) { + if (TRACELEVEL == 0) return; + if (TRACELEVEL == 2) callDepth++; + printEntering(str); + } + protected static void traceExit(String str) { + if (TRACELEVEL == 0) return; + printExiting(str); + if (TRACELEVEL == 2) callDepth--; + } + private static void printEntering(String str) { + printIndent(); + stream.println("--> " + str); + } + private static void printExiting(String str) { + printIndent(); + stream.println("<-- " + str); + } + private static void printIndent() { + for (int i = 0; i < callDepth; i++) + stream.print(" "); + } + + // protocol part + + abstract pointcut myClass(); + + pointcut myConstructor(): myClass() && execution(new(..)); + pointcut myMethod(): myClass() && execution(* *(..)); + + before(): myConstructor() { + traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myConstructor() { + traceExit("" + thisJoinPointStaticPart.getSignature()); + } + + before(): myMethod() { + traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myMethod() { + traceExit("" + thisJoinPointStaticPart.getSignature()); + } +} +]]></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 + 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. + </para> + </sect3> + </sect2> + </sect1> + +<!-- ============================================================ --> +<!-- ============================================================ --> + + <sect1> + <title>Production Aspects</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> + + <para> + This example examines an aspect that makes Point objects into a 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 + <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 + <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 + 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> + + <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 + <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. + </para> + </sect3> + + <sect3> + <title>The Class <classname>Point</classname></title> + + <para> + The class <classname>Point</classname> is a very simple class with + trivial getters and setters, and a simple vector offset method. + </para> + + <programlisting><![CDATA[ +class Point { + + protected int x = 0; + protected int y = 0; + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public void setRectangular(int newX, int newY) { + setX(newX); + setY(newY); + } + + public void setX(int newX) { + x = newX; + } + + public void setY(int newY) { + y = newY; + } + + public void offset(int deltaX, int deltaY) { + setRectangular(x + deltaX, y + deltaY); + } + + public String toString() { + return "(" + getX() + ", " + getY() + ")" ; + } +}]]></programlisting> + + </sect3> + + <sect3> + <title>The Aspect <classname>BoundPoint</classname></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. + </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. + </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. + </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. + </para> + +<programlisting><![CDATA[ +aspect BoundPoint { + private PropertyChangeSupport Point.support = new PropertyChangeSupport(this); + + 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); + } + + declare parents: Point implements Serializable; + + pointcut setter(Point p): call(void Point.set*(*)) && target(p); + + void around(Point p): setter(p) { + String propertyName = + thisJoinPointStaticPart.getSignature().getName().substring("set".length()); + int oldX = p.getX(); + int oldY = p.getY(); + proceed(p); + if (propertyName.equals("X")){ + firePropertyChange(p, propertyName, oldX, p.getX()); + } else { + firePropertyChange(p, propertyName, oldY, p.getY()); + } + } + + void firePropertyChange(Point p, + String property, + double oldval, + double newval) { + p.support.firePropertyChange(property, + new Double(oldval), + new Double(newval)); + } +} +]]></programlisting> + + </sect3> + + <sect3> + <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 + 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. + </para> + +<programlisting><![CDATA[ + class Demo implements PropertyChangeListener { + + static final String fileName = "test.tmp"; + + public void propertyChange(PropertyChangeEvent e){ + System.out.println("Property " + e.getPropertyName() + " changed from " + + e.getOldValue() + " to " + e.getNewValue() ); + } + + public static void main(String[] args){ + Point p1 = new Point(); + p1.addPropertyChangeListener(new Demo()); + System.out.println("p1 =" + p1); + p1.setRectangular(5,2); + System.out.println("p1 =" + p1); + p1.setX( 6 ); + p1.setY( 3 ); + System.out.println("p1 =" + p1); + p1.offset(6,4); + System.out.println("p1 =" + p1); + save(p1, fileName); + Point p2 = (Point) restore(fileName); + System.out.println("Had: " + p1); + System.out.println("Got: " + p2); + } + ... + } +]]></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> + +<programlisting><![CDATA[ +ajc -argfile bean/files.lst +java bean.Demo +]]></programlisting> + + </sect3> + </sect2> + + <!-- ==================== --> + + <sect2><!-- The Subject/Observer Protocol --> + <title>The Subject/Observer Protocol</title> + + <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> + + <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. + </para> + + <para> + With these two kinds of objects, we can build up a Subject/Observer + relationship in which colored labels observe the clicks of buttons; + that is, where colored labels are the observers and buttons are the + subjects. + </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. + </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: + </para> + +<programlisting><![CDATA[ + interface Subject { + void addObserver(Observer obs); + void removeObserver(Observer obs); + Vector getObservers(); + Object getData(); + } +]]></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> + +<programlisting><![CDATA[ + interface Observer { + void setSubject(Subject s); + Subject getSubject(); + void update(); + } +]]></programlisting> + + <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. + </para> + +<programlisting><![CDATA[ + abstract aspect SubjectObserverProtocol { + + abstract pointcut stateChanges(Subject s); + + after(Subject s): stateChanges(s) { + for (int i = 0; i < s.getObservers().size(); i++) { + ((Observer)s.getObservers().elementAt(i)).update(); + } + } + + private Vector Subject.observers = new Vector(); + public void Subject.addObserver(Observer obs) { + observers.addElement(obs); + obs.setSubject(this); + } + public void Subject.removeObserver(Observer obs) { + observers.removeElement(obs); + obs.setSubject(null); + } + public Vector Subject.getObservers() { return observers; } + + private Subject Observer.subject = null; + public void Observer.setSubject(Subject s) { subject = s; } + public Subject Observer.getSubject() { return subject; } + + } +]]></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. + </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> + +<programlisting><![CDATA[ + class Button extends java.awt.Button { + + static final Color defaultBackgroundColor = Color.gray; + static final Color defaultForegroundColor = Color.black; + static final String defaultText = "cycle color"; + + Button(Display display) { + super(); + setLabel(defaultText); + setBackground(defaultBackgroundColor); + setForeground(defaultForegroundColor); + addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Button.this.click(); + } + }); + display.addToFrame(this); + } + + public void click() {} + + } +]]></programlisting> + + <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. + </para> + +<programlisting><![CDATA[ + class ColorLabel extends Label { + + ColorLabel(Display display) { + super(); + display.addToFrame(this); + } + + final static Color[] colors = {Color.red, Color.blue, + Color.green, Color.magenta}; + private int colorIndex = 0; + private int cycleCount = 0; + void colorCycle() { + cycleCount++; + colorIndex = (colorIndex + 1) % colors.length; + setBackground(colors[colorIndex]); + setText("" + cycleCount); + } + } +]]></programlisting> + + <para> + Finally, the <classname>SubjectObserverProtocolImpl</classname> + implements the subject/observer protocol, with + <classname>Button</classname> objects as subjects and + <classname>ColorLabel</classname> objects as observers: + </para> + +<programlisting><![CDATA[ +package observer; + +import java.util.Vector; + +aspect SubjectObserverProtocolImpl extends SubjectObserverProtocol { + + declare parents: Button implements Subject; + public Object Button.getData() { return this; } + + declare parents: ColorLabel implements Observer; + public void ColorLabel.update() { + colorCycle(); + } + + pointcut stateChanges(Subject s): + target(s) && + call(void Button.click()); + +}]]></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 + <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>. + </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> + +<programlisting><![CDATA[ + ajc -argfile observer/files.lst + java observer.Demo +]]></programlisting> + + </sect3> + </sect2> + + <!-- ==================== --> + + <sect2> + <title>A Simple Telecom Simulation</title> + + <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. + </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> + <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 Class <classname>Customer</classname></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 { + + private String name; + private int areacode; + private Vector calls = new Vector(); + + protected void removeCall(Call c){ + calls.removeElement(c); + } + + protected void addCall(Call c){ + calls.addElement(c); + } + + public Customer(String name, int areacode) { + this.name = name; + this.areacode = areacode; + } + + public String toString() { + return name + "(" + areacode + ")"; + } + + public int getAreacode(){ + return areacode; + } + + public boolean localTo(Customer other){ + return areacode == other.areacode; + } + + public Call call(Customer receiver) { + Call call = new Call(this, receiver); + addCall(call); + return call; + } + + public void pickup(Call call) { + call.pickup(); + addCall(call); + } + + public void hangup(Call call) { + call.hangup(this); + removeCall(call); + } + + public void merge(Call call1, Call call2){ + call1.merge(call2); + removeCall(call2); + } + } +]]></programlisting> + + </sect3> + + <sect3> + <title>The Class <classname>Call</classname></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. + </para> + </sect3> + + <sect3> + <title>The Class <classname>Connection</classname></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 + <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>. + </para> + +<programlisting><![CDATA[ + abstract class Connection { + + public static final int PENDING = 0; + public static final int COMPLETE = 1; + public static final int DROPPED = 2; + + Customer caller, receiver; + private int state = PENDING; + + Connection(Customer a, Customer b) { + this.caller = a; + this.receiver = b; + } + + public int getState(){ + return state; + } + + public Customer getCaller() { return caller; } + + public Customer getReceiver() { return receiver; } + + void complete() { + state = COMPLETE; + System.out.println("connection completed"); + } + + void drop() { + state = DROPPED; + System.out.println("connection dropped"); + } + + public boolean connects(Customer c){ + return (caller == c || receiver == c); + } + + } +]]></programlisting> + + </sect3> + + <sect3> + <title>The Class Local</title> + +<programlisting><![CDATA[ + class Local extends Connection { + Local(Customer a, Customer b) { + super(a, b); + System.out.println("[new local connection from " + + a + " to " + b + "]"); + } + } +]]></programlisting> + + </sect3> + + <sect3> + <title>The Class LongDistance</title> + +<programlisting><![CDATA[ + class LongDistance extends Connection { + LongDistance(Customer a, Customer b) { + super(a, b); + System.out.println("[new long distance connection from " + + a + " to " + b + "]"); + } + } +]]></programlisting> + + </sect3> + + <sect3> + <title>Compiling and Running the Basic Simulation</title> + + <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: + </para> + +<programlisting><![CDATA[ +ajc -argfile telecom/basic.lst +java telecom.BasicSimulation +]]></programlisting> + + </sect3> + + <sect3> + <title>Timing</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: + </para> + + <sect4> + <title>The Class <classname>Timer</classname></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 + <classname>TimerLog</classname> (below) can be used to cause the + start and stop times to be printed to standard output. + </para> + +<programlisting><![CDATA[ + class Timer { + long startTime, stopTime; + + public void start() { + startTime = System.currentTimeMillis(); + stopTime = startTime; + } + + public void stop() { + stopTime = System.currentTimeMillis(); + } + + public long getTime() { + return stopTime - startTime; + } + } +]]></programlisting> + + </sect4> + </sect3> + + <sect3> + <title>The Aspect <classname>TimerLog</classname></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. + </para> + +<programlisting><![CDATA[ +public aspect TimerLog { + + after(Timer t): target(t) && call(* Timer.start()) { + System.err.println("Timer started: " + t.startTime); + } + + after(Timer t): target(t) && call(* Timer.stop()) { + System.err.println("Timer stopped: " + t.stopTime); + } +} +]]></programlisting> + + </sect3> + + <sect3> + <title>The Aspect <classname>Timing</classname></title> + + <para> + The aspect <classname>Timing</classname> introduces attribute + <literal>totalConnectTime</literal> into the class + <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. + </para> + +<programlisting><![CDATA[ +public aspect Timing { + + public long Customer.totalConnectTime = 0; + + public long getTotalConnectTime(Customer cust) { + return cust.totalConnectTime; + } + private Timer Connection.timer = new Timer(); + public Timer getTimer(Connection conn) { return conn.timer; } + + after (Connection c): target(c) && call(void Connection.complete()) { + getTimer(c).start(); + } + + pointcut endTiming(Connection c): target(c) && + call(void Connection.drop()); + + after(Connection c): endTiming(c) { + getTimer(c).stop(); + c.getCaller().totalConnectTime += getTimer(c).getTime(); + c.getReceiver().totalConnectTime += getTimer(c).getTime(); + } +}]]></programlisting> + + </sect3> + + <sect3> + <title>Billing</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> + +<programlisting><![CDATA[ +public aspect Billing dominates Timing { + // domination required to get advice on endtiming in the right order + + 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; } + + after(Customer cust) returning (Connection conn): + args(cust, ..) && call(Connection+.new(..)) { + conn.payer = cust; + } + + 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(); + long cost = rate * time; + getPayer(conn).addCharge(cost); + } + + + public long Customer.totalCharge = 0; + public long getTotalCharge(Customer cust) { return cust.totalCharge; } + + public void Customer.addCharge(long charge){ + totalCharge += charge; + } +} +]]></programlisting> + + </sect4> + </sect3> + + <sect3> + <title>Accessing the Introduced 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. + </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. + </para> + +<programlisting><![CDATA[ + protected void report(Customer c){ + Timing t = Timing.aspectOf(); + 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: + </para> + +<programlisting><![CDATA[ + ajc -argfile telecom/timing.lst + java telecom.TimingSimulation +]]></programlisting> + + <para> + To build and run the application with the timing and billing features, + go to the directory examples and type: + </para> + +<programlisting><![CDATA[ + ajc -argfile telecom/billing.lst + java telecom.BillingSimulation +]]></programlisting> + + </sect3> + + <sect3> + <title>Discussion</title> + + <para> + 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. + </para> + </listitem> + + <listitem> + <para> + Billing uses the pointcut Timing.endTiming. + </para> + </listitem> + + <listitem> + <para> + Billing needs access to the timer associated with a connection. + </para> + </listitem> + </itemizedlist> + </para> + </sect3> + </sect2> + </sect1> + +<!-- ============================================================ --> +<!-- ============================================================ --> + + <sect1> + <title>Reusable Aspects</title> + + <sect2> + <title>Tracing Aspects Revisited</title> + + <para>(The code for this example is in + <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.) + </para> + + <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> + 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> + +<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> + +<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> + +<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> + +<programlisting><![CDATA[ +abstract aspect Trace { + + public static int TRACELEVEL = 0; + protected static PrintStream stream = null; + protected static int callDepth = 0; + + public static void initStream(PrintStream s) { + stream = s; + } + + protected static void traceEntry(String str, Object o) { + if (TRACELEVEL == 0) return; + if (TRACELEVEL == 2) callDepth++; + printEntering(str + ": " + o.toString()); + } + + protected static void traceExit(String str, Object o) { + if (TRACELEVEL == 0) return; + printExiting(str + ": " + o.toString()); + if (TRACELEVEL == 2) callDepth--; + } + + private static void printEntering(String str) { + printIndent(); + stream.println("Entering " + str); + } + + private static void printExiting(String str) { + printIndent(); + stream.println("Exiting " + str); + } + + + private static void printIndent() { + for (int i = 0; i < callDepth; i++) + stream.print(" "); + } + + + abstract pointcut myClass(Object obj); + + pointcut myConstructor(Object obj): myClass(obj) && execution(new(..)); + pointcut myMethod(Object obj): myClass(obj) && + execution(* *(..)) && !execution(String toString()); + + before(Object obj): myConstructor(obj) { + traceEntry("" + thisJoinPointStaticPart.getSignature(), obj); + } + after(Object obj): myConstructor(obj) { + traceExit("" + thisJoinPointStaticPart.getSignature(), obj); + } + + before(Object obj): myMethod(obj) { + traceEntry("" + thisJoinPointStaticPart.getSignature(), obj); + } + after(Object obj): myMethod(obj) { + traceExit("" + thisJoinPointStaticPart.getSignature(), obj); + } +} +]]></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. + </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. + </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! + </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 + </para> + +<programlisting><![CDATA[ +&& !cflow(execution(String toString())) +]]></programlisting> + + <para> + 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 + <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. + </para> + + <para> + Finally, to run this version of tracing, go to the directory + <filename>examples</filename> and type: + </para> + +<programlisting><![CDATA[ +ajc -argfile tracing/tracev3.lst +]]></programlisting> + + <para> + The file tracev3.lst lists the application classes as well as this + version of the files <filename>Trace.java</filename> and + <filename>TraceMyClasses.java</filename>. To run the program, type + </para> + +<programlisting><![CDATA[ +java tracing.version3.TraceMyClasses +]]></programlisting> + + <para>The output should be:</para> + +<programlisting><![CDATA[ + --> tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Circle(double, double, double) + <-- tracing.Circle(double, double, double) + --> tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Circle(double, double, double) + <-- tracing.Circle(double, double, double) + --> tracing.Circle(double) + <-- tracing.Circle(double) + --> tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Square(double, double, double) + <-- tracing.Square(double, double, double) + --> tracing.Square(double, double) + <-- tracing.Square(double, double) + --> double tracing.Circle.perimeter() + <-- double tracing.Circle.perimeter() +c1.perimeter() = 12.566370614359172 + --> double tracing.Circle.area() + <-- double tracing.Circle.area() +c1.area() = 12.566370614359172 + --> double tracing.Square.perimeter() + <-- double tracing.Square.perimeter() +s1.perimeter() = 4.0 + --> double tracing.Square.area() + <-- double tracing.Square.area() +s1.area() = 1.0 + --> double tracing.TwoDShape.distance(TwoDShape) + --> double tracing.TwoDShape.getX() + <-- double tracing.TwoDShape.getX() + --> double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.distance(TwoDShape) +c2.distance(c1) = 4.242640687119285 + --> double tracing.TwoDShape.distance(TwoDShape) + --> double tracing.TwoDShape.getX() + <-- double tracing.TwoDShape.getX() + --> double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.distance(TwoDShape) +s1.distance(c1) = 2.23606797749979 + --> String tracing.Square.toString() + --> String tracing.TwoDShape.toString() + <-- String tracing.TwoDShape.toString() + <-- String tracing.Square.toString() +s1.toString(): Square side = 1.0 @ (1.0, 2.0) +]]></programlisting> + + </sect3> + </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: +--> diff --git a/docs/progGuideDB/figureUML.gif b/docs/progGuideDB/figureUML.gif Binary files differnew file mode 100644 index 000000000..c4bf8db9a --- /dev/null +++ b/docs/progGuideDB/figureUML.gif diff --git a/docs/progGuideDB/gettingstarted.xml b/docs/progGuideDB/gettingstarted.xml new file mode 100644 index 000000000..7cd6becbd --- /dev/null +++ b/docs/progGuideDB/gettingstarted.xml @@ -0,0 +1,1090 @@ +<chapter id="gettingstarted" xreflabel="Getting Started with AspectJ"> + + <title>Getting Started with AspectJ</title> + + <sect1> + <title>Introduction</title> + + <para>Many software developers are attracted to the idea of aspect-oriented + programming + <indexterm> + <primary>aspect-oriented programming</primary> + </indexterm> + (AOP) + <indexterm> + <primary>AOP</primary> + <see> aspect-oriented programming</see> + </indexterm> + but unsure about how to begin using the technology. They + recognize the concept of crosscutting concerns, and know that they have + had problems with the implementation of such concerns in the past. But + there are many questions about how to adopt AOP into the development + process. Common questions include: + <itemizedlist spacing="compact"> + <listitem> + <para>Can I use aspects in my existing code?</para> + </listitem> + <listitem> + <para>What kinds of benefits can I expect to get from using aspects? + </para> + </listitem> + <listitem> + <para>How do I find aspects in my programs?</para> + </listitem> + <listitem> + <para>How steep is the learning curve for AOP?</para> + </listitem> + <listitem> + <para>What are the risks of using this new technology?</para> + </listitem> + </itemizedlist></para> + + <para>This chapter addresses these questions in the context of AspectJ a + general-purpose aspect-oriented extension to Java. A series of abridged + examples illustrate the kinds of aspects programmers may want to + implement using AspectJ and the benefits associated with doing so. + Readers who would like to understand the examples in more detail, or who + want to learn how to program examples like these, can find the complete + examples and supporting material on the AspectJ web site(<ulink + url="http://aspectj.org/documentation/papersAndSlides/figures-cacm2001.zip"></ulink>).</para> + + <para>A significant risk in adopting any new technology is going too + far too fast. Concern about this risk causes many organizations to + be conservative about adopting new technology. To address this + issue, the examples in this chapter are grouped into three broad + categories, with aspects that are easier to adopt into existing + development projects coming earlier in this chapter. The next + section, <xref linkend="aspectjsemantics"/>, we present the core + of AspectJ's semantics, and in <xref linkend="developmentaspects"/>, + we present aspects that facilitate tasks such as debugging, + testing and performance tuning of applications. And, in the section + following, <xref linkend="productionaspects"/>, we present aspects + that implement crosscutting functionality common in Java + applications. We will defer discussing a third category of aspects, + reusable aspects until <xref linkend="aspectjlanguage"/>. </para> + + <para>These categories are informal, and this ordering is not the only way + to adopt AspectJ. Some developers may want to use a production aspect + right away. But our experience with current AspectJ users suggests that + this is one ordering that allows developers to get experience with (and + benefit from) AOP technology quickly, while also minimizing risk.</para> + + </sect1> + + <sect1 id="aspectjsemantics" xreflabel="AspectJ Semantics"> + <title>AspectJ Semantics</title> + + <indexterm> + <primary>AspectJ</primary> + <secondary>semantics</secondary> + <tertiary>overview</tertiary> + </indexterm> + + <para>This section presents a brief introduction to the features of AspectJ + used later in this chapter. These features are at the core of the + language, but this is by no means a complete overview of AspectJ.</para> + + <para>The semantics are presented using a simple figure editor system. A + <classname>Figure</classname> consists of a number of + <classname>FigureElements</classname>, which can be either + <classname>Point</classname>s or <classname>Line</classname>s. The + <classname>Figure</classname> class provides factory services. There is + also a <classname>Display</classname>. Most example programs later in + this chapter are based on this system as well.</para> + + <para> + <mediaobject> + <imageobject> + <imagedata fileref="figureUML.gif"/> + </imageobject> + <caption><para>UML for the <literal>FigureEditor</literal> + example</para></caption> + </mediaobject> + </para> + + <para>The motivation for AspectJ (and likewise for aspect-oriented + programming) is the realization that there are issues or concerns + that are not well captured by traditional programming + methodologies. Consider the problem of enforcing a security policy + in some application. By its nature, security cuts across many of + the natural units of modularity of the application. Moreover, the + security policy must be uniformly applied to any additions as the + application evolves. And the security policy that is being applied + might itself evolve. Capturing concerns like a security policy in + a disciplined way is difficult and error-prone in a traditional + programming language.</para> + + <para>Concerns like security cut across the natural units of + modularity. For object-oriented programming languages, the natural + unit of modularity is the class. But in object-oriented + programming languages, crosscutting concerns are not easily turned + into classes precisely because they cut across classes, and so + these aren't reusable, they can't be refined or inherited, + they are spread through out the program in an undisciplined way, + in short, they are difficult to work with.</para> + + <para>Aspect-oriented programming is a way of modularizing + crosscutting concerns much like object-oriented programming is a + way of modularizing common concerns. AspectJ is an implementation + of aspect-oriented programming for Java.</para> + + <para>AspectJ adds to Java just one new concept, a join point, and + a few new constructs: pointcuts, advice, introduction and aspects. + Pointcuts and advice dynamically affect program flow, and + introduction statically affects a program's class + heirarchy.</para> + + <para>A <emphasis>join point</emphasis> + <indexterm><primary>join point</primary></indexterm> + is a well-defined point in the program flow. + <emphasis>Pointcuts</emphasis> + <indexterm><primary>pointcut</primary></indexterm> + select certain join points and values at those points. + <emphasis>Advice</emphasis> + <indexterm> <primary>advice</primary></indexterm> + defines code that is executed when a pointcut is reached. These + are, then, the dynamic parts of AspectJ.</para> + + <para>AspectJ also has a way of affecting a program statically. + <emphasis>Introduction</emphasis> + <indexterm><primary>introduction</primary></indexterm> + is how AspectJ modifies a program's static structure, namely, the + members of its classes and the relationship between + classes.</para> + + <para>The last new construct in AspectJ is the + <emphasis>aspect</emphasis>. + <indexterm><primary>aspect</primary></indexterm> + Aspects, are AspectJ's unit of modularity for crosscutting + concerns They are defined in terms of pointcuts, advice and + introduction.</para> + + <para>In the sections immediately following, we are first going to look at + join points and how they compose into pointcuts. Then we will look + at advice, the code which is run when a pointcut is reached. We + will see how to combine pointcuts and advice into aspects, AspectJ's + reusable, inheritable unit of modularity. Lastly, we will look at + how to modify a program's class structure with introduction. </para> + + <sect2> + <title>The Dynamic Join Point Model</title> + <indexterm> + <primary>join point</primary> + <secondary>model</secondary> + </indexterm> + + <para>A critical element in the design of any aspect-oriented + language is the join point model. The join point model provides + the common frame of reference that makes it possible to define + the dynamic structure of crosscutting concerns.</para> + + <para>This chapter describes AspectJ's dynamic join points, in + which join points are certain well-defined points in the + execution of the program. Later we will discuss introduction, + AspectJ's form for modifying a program statically. </para> + + <para>AspectJ provides for many kinds of join points, but this + chapter discusses only one of them: method call join points. A + method call join point encompasses the actions of an object + receiving a method call. It includes all the actions that + comprise a method call, starting after all arguments are + evaluated up to and including normal or abrupt return.</para> + + <para>Each method call itself is one join point. The dynamic + context of a method call may include many other join points: all + the join points that occur when executing the called method and + any methods that it calls.</para> + + </sect2> + + <sect2> + <title>Pointcut Designators</title> + + <para>In AspectJ, <emphasis>pointcut designators</emphasis> (or + simply pointcuts) identify certain join points in the program + flow. For example, the pointcut</para> + + <programlisting format="linespecific"> +call(void Point.setX(int))</programlisting> + + <para>identifies any call to the method <function>setX</function> + defined on <classname>Point</classname> objects. Pointcuts can be + composed using a filter composition semantics, so for example:</para> + + <programlisting format="linespecific"> +call(void Point.setX(int)) || +call(void Point.setY(int))</programlisting> + + <para>identifies any call to either the <function>setX</function> or + <function>setY</function> methods defined by + <classname>Point</classname>.</para> + + <para>Programmers can define their own pointcuts, and pointcuts + can identify join points from many different classes — in + other words, they can crosscut classes. So, for example, the + following declares a new, named pointcut:</para> + +<programlisting format="linespecific"> +pointcut move(): call(void FigureElement.setXY(int,int)) || + call(void Point.setX(int)) || + call(void Point.setY(int)) || + call(void Line.setP1(Point)) || + call(void Line.setP2(Point));</programlisting> + + <para>The effect of this declaration is that <function>move</function> is + now a pointcut that identifies any call to methods that move figure + elements. </para> + + <sect3> + <title>Property-Based Primitive Pointcuts</title> + <indexterm> + <primary>pointcut</primary> + <secondary>primitive</secondary> + </indexterm> + <indexterm> + <primary>pointcut</primary> + <secondary>name-based</secondary> + </indexterm> + <indexterm> + <primary>pointcut</primary> + <secondary>property-based</secondary> + </indexterm> + + <para>The previous pointcuts are all based on explicit enumeration + of a set of method signatures. We call this + <emphasis>name-based</emphasis> crosscutting. AspectJ also + provides mechanisms that enable specifying a pointcut in terms + of properties of methods other than their exact name. We call + this <emphasis>property-based</emphasis> crosscutting. The + simplest of these involve using wildcards in certain fields of + the method signature. For example:</para> + +<programlisting format="linespecific"> +call(void Figure.make*(..))</programlisting> + + <para>identifies calls to any method defined on + <classname>Figure</classname>, for which the name begins with + "<function>make</function>", specifically the factory methods + <function>makePoint</function> and <function>makeLine</function>; + and</para> + + <programlisting format="linespecific"> +call(public * Figure.* (..))</programlisting> + + <para>identifies calls to any public method defined on + <classname>Figure</classname>.</para> + + <para>One very powerful primitive pointcut, + <function>cflow</function>, identifies join points based on whether + they occur in the dynamic context of another pointcut. So</para> + + <programlisting format="linespecific"> +cflow(move())</programlisting> + + <para>identifies all join points that occur between receiving method + calls for the methods in <function>move</function> and returning from + those calls (either normally or by throwing an exception.) </para> + + </sect3> + + </sect2> + + <sect2> + <title>Advice</title> + <indexterm> + <primary>advice</primary> + </indexterm> + + <para>Pointcuts are used in the definition of advice. AspectJ has + several different kinds of advice that define additional code that + should run at join points. <emphasis>Before advice</emphasis> + <indexterm> + <primary>advice</primary> + <secondary>before</secondary> + </indexterm> + runs when a join point is reached and + before the computation proceeds, i.e. it runs when computation + reaches the method call and before the actual method starts running. + <emphasis>After advice</emphasis> + <indexterm> + <primary>advice</primary> + <secondary>after</secondary> + </indexterm> + runs after the computation 'under the join point' finishes, i.e. after + the method body has run, and just before control is returned to the + caller. <emphasis>Around advice</emphasis> + <indexterm> + <primary>advice</primary> + <secondary>around</secondary> + </indexterm> + runs when the join point is reached, and has explicit control over + whether the computation under the join point is allowed to run at + all. (Around advice and some variants of after advice are not + discussed in this chapter.)</para> + +<programlisting><![CDATA[ +after(): move() { + System.out.println("A figure element moved."); +} +]]></programlisting> + + <sect3> + <title>Exposing Context in Pointcuts</title> + + <para>Pointcuts can also expose part of the execution context at + their join points. Values exposed by a pointcut can be used in + the body of advice declarations. In the following code, the + pointcut exposes three values from calls to + <function>setXY</function>: the + <classname>FigureElement</classname> receiving the call, the + new value for <literal>x</literal> and the new value for + <literal>y</literal>. The advice then prints the figure + element that was moved and its new <literal>x</literal> and + <literal>y</literal> coordinates after each + <classname>setXY</classname> method call.</para> + +<programlisting><![CDATA[ +pointcut setXY(FigureElement fe, int x, int y): + call(void FigureElement.setXY(int, int)) + && target(fe) + && args(x, y); + +after(FigureElement fe, int x, int y): setXY(fe, x, y) { + System.out.println(fe + " moved to (" + x + ", " + y + ")."); +} +]]></programlisting> + + </sect3> + + </sect2> + + <sect2> + <title>Introduction</title> + <indexterm><primary>aspect</primary></indexterm> + + <para>Introduction is AspectJ's form for modifying classes and their + hierarchy. Introduction adds new members to classes and alters the + inheritance relationship between classes. Unlike advice that operates + primarily dynamically, introduction operates statically, at compilation + time. Introduction changes the declaration of classes, and it is these + changed classes that are inherited, extended or instantiated by the + rest of the program.</para> + + <para>Consider the problem of adding a new capability to some existing + classes that are already part of a class heirarchy, i.e. they already + extend a class. In Java, one creates an interface that captures + this new capability, and then adds to <emphasis>each affected + class</emphasis> a method that implements this interface.</para> + + <para>AspectJ can do better. The new capability is a crosscutting concern + because it affects multiple classes. Using AspectJ's introduction form, + we can introduce into existing classes the methods or fields that are + necessary to implement the new capability. + </para> + + <para>Suppose we want to have <classname>Screen</classname> objects + observe changes to <classname>Point</classname> objects, where + <classname>Point</classname> is an existing class. We can implement + this by introducing into the class <classname>Point</classname> an + instance field, <varname>observers</varname>, that keeps track of the + <classname>Screen</classname> objects that are observing + <classname>Point</classname>s. Observers are added or removed with the + static methods <function>addObserver</function> and + <function>removeObserver</function>. The pointcut + <function>changes</function> defines what we want to observe, and the + after advice defines what we want to do when we observe a change. Note + that neither <classname>Screen</classname>'s nor + <classname>Point</classname>'s code has to be modified, and that all + the changes needed to support this new capability are local to this + aspect.</para> + + <programlisting><![CDATA[ +aspect PointObserving { + + private Vector Point.observers = new Vector(); + + public static void addObserver(Point p, Screen s) { + p.observers.add(s); + } + + public static void removeObserver(Point p, Screen s) { + p.observers.remove(s); + } + + pointcut changes(Point p): target(p) && call(void Point.set*(int)); + + after(Point p): changes(p) { + Iterator iter = p.observers.iterator(); + while ( iter.hasNext() ) { + updateObserver(p, (Screen)iter.next()); + } + } + + static void updateObserver(Point p, Screen s) { + s.display(p); + } +}]]></programlisting> + </sect2> + + <sect2> + <title>Aspect Declarations</title> + + <para>An <emphasis>aspect</emphasis> + <indexterm><primary>aspect</primary></indexterm> is a modular unit of + crosscutting implementation. It is defined very much like a class, + and can have methods, fields, and initializers. The crosscutting + implementation is provided in terms of pointcuts, advice and + introductions. Only aspects may include advice, so while AspectJ + may define crosscutting effects, the declaration of those effects is + localized.</para> + + <para>The next three sections present the use of aspects in + increasingly sophisticated ways. Development aspects are easily removed + from production builds. Production aspects are intended to be used in + both development and in production, but tend to affect only a few + classes. Finally, reusable aspects require the most experience to get + right.</para> + + </sect2> + + </sect1> + + <sect1 id="developmentaspects" xreflabel="Development Aspects"> + <title>Development Aspects</title> + <indexterm> + <primary>aspect</primary> + <secondary>development</secondary> + </indexterm> + + <para>This section presents examples of aspects that can be used during + development of Java applications. These aspects facilitate debugging, + testing and performance tuning work. The aspects define behavior that + ranges from simple tracing, to profiling, to testing of internal + consistency within the application. Using AspectJ makes it possible to + cleanly modularize this kind of functionality, thereby making it possible + to easily enable and disable the functionality when desired. </para> + + <sect2> + <title>Tracing, Logging, and Profiling</title> + <indexterm> + <primary>tracing</primary> + </indexterm> + <indexterm> + <primary>logging</primary> + </indexterm> + <indexterm> + <primary>profiling</primary> + </indexterm> + + <para>This first example shows how to increase the visibility of the + internal workings of a program. It is a simple tracing aspect that + prints a message at specified method calls. In our figure editor + example, one such aspect might simply trace whenever points are + drawn.</para> + +<programlisting><![CDATA[ +aspect SimpleTracing { + pointcut tracedCall(): + call(void FigureElement.draw(GraphicsContext)); + + before(): tracedCall() { + System.out.println("Entering: " + thisJoinPoint); + } +} +]]></programlisting> + + <para>This code makes use of the <literal>thisJoinPoint</literal> special + variable. Within all advice bodies this variable is bound to an object + that describes the current join point. The effect of this code + is to print a line like the following every time a figure element + receives a <function>draw</function> method call:</para> + +<programlisting><![CDATA[ +Entering: call(void FigureElement.draw(GraphicsContext)) +]]></programlisting> + + <para>To understand the benefit of coding this with AspectJ consider + changing the set of method calls that are traced. With AspectJ, this + just requires editing the definition of the + <function>tracedCalls</function> pointcut and recompiling. The + individual methods that are traced do not need to be edited.</para> + + <para>When debugging, programmers often invest considerable effort in + figuring out a good set of trace points to use when looking for a + particular kind of problem. When debugging is complete or appears to + be complete it is frustrating to have to lose that investment by + deleting trace statements from the code. The alternative of just + commenting them out makes the code look bad, and can cause trace + statements for one kind of debugging to get confused with trace + statements for another kind of debugging.</para> + + <para>With AspectJ it is easy to both preserve the work of designing a + good set of trace points and disable the tracing when it isn t being + used. This is done by writing an aspect specifically for that tracing + mode, and removing that aspect from the compilation when it is not + needed.</para> + + <para>This ability to concisely implement and reuse debugging + configurations that have proven useful in the past is a direct result + of AspectJ modularizing a crosscutting design element the set of + methods that are appropriate to trace when looking for a given kind of + information.</para> + + <sect3> + <title>Profiling and Logging</title> + <indexterm><primary>logging</primary></indexterm> + <indexterm><primary>profiling</primary></indexterm> + + <para> Our second example shows you how to do some very specific + profiling. Although many sophisticated profiling tools are available, + and these can gather a variety of information and display the results + in useful ways, you may sometimes want to profile or log some very + specific behavior. In these cases, it is often possible to write a + simple aspect similar to the ones above to do the job.</para> + + <para>For example, the following aspect<footnote> + <para>Since aspects are by default singleton aspects, i.e. there is + only one instance of the aspect, fields in a singleton aspect are + similar to static fields in class.</para></footnote> will count + the number of calls to the <function>rotate</function> method on a + <classname>Line</classname> and the number of calls to the + <function>set*</function> methods of a <classname>Point</classname> + that happen within the control flow of those calls to + <function>rotate</function>:</para> + +<programlisting><![CDATA[ +aspect SetsInRotateCounting { + int rotateCount = 0; + int setCount = 0; + + before(): call(void Line.rotate(double)) { + rotateCount++; + } + + before(): call(void Point.set*(int)) && + cflow(call(void Line.rotate(double))) { + setCount++; + } +}]]></programlisting> + + <para>Aspects have an advantage over standard profiling or logging + tools because they can be programmed to ask very specific and complex + questions like, "How many times is the <function>rotate</function> + method defined on <classname>Line</classname> objects called, and how + many times are methods defined on <classname>Point</classname> + objects whose name begins with `<function>set</function>' called in + fulfilling those rotate calls"?</para> + + </sect3> + + </sect2> + + <sect2> + <title>Pre- and Post-Conditions</title> + + <indexterm><primary>pre-condition</primary></indexterm> + <indexterm><primary>post-condition</primary></indexterm> + <indexterm><primary>assertion</primary></indexterm> + + <para>Many programmers use the "Design by Contract" style popularized by + Bertand Meyer in <citetitle>Object-Oriented Software Construction, + 2/e</citetitle>. In this style of programming, explicit + pre-conditions test that callers of a method call it properly and + explicit post-conditions test that methods properly do the work they + are supposed to.</para> + + <para> + AspectJ makes it possible to implement pre- and post-condition testing + in modular form. For example, this code </para> + + + <programlisting><![CDATA[ +aspect PointBoundsChecking { + + pointcut setX(int x): + (call(void FigureElement.setXY(int, int)) && args(x, *)) + || (call(void Point.setX(int)) && args(x)); + + pointcut setY(int y): + (call(void FigureElement.setXY(int, int)) && args(*, y)) + || (call(void Point.setY(int)) && args(y)); + + before(int x): setX(x) { + if ( x < MIN_X || x > MAX_X ) + throw new IllegalArgumentException("x is out of bounds."); + } + + before(int y): setY(y) { + if ( y < MIN_Y || y > MAX_Y ) + throw new IllegalArgumentException("y is out of bounds."); + } +} +]]></programlisting> + + <para>implements the bounds checking aspect of pre-condition testing for + operations that move points. Notice that the <function>setX</function> + pointcut refers to all the operations that can set a point's + <literal>x</literal> coordinate; this includes the + <function>setX</function> method, as well as half of the + <function>setXY</function> method. In this sense the + <function>setX</function> pointcut can be seen as involving very + fine-grained crosscutting—it names the the + <function>setX</function> method and half of the + <function>setXY</function> method.</para> + + <para>Even though pre- and post-condition testing aspects can often be + used only during testing, in some cases developers may wish to include + them in the production build as well. Again, because AspectJ makes it + possible to modularize these crosscutting concerns cleanly, it gives + developers good control over this decision.</para> + + </sect2> + + <sect2> + <title>Contract Enforcement</title> + <indexterm><primary>contract enforcement</primary></indexterm> + +<!-- <remark>What is a compelling example of runtime contract enforcement that has --> +<!-- croscutting concerns so that Java 1.4-based assertions won't be --> +<!-- sufficient? --> +<!-- </remark> --> + <para> + The property-based crosscutting mechanisms can be very useful in + defining more sophisticated contract enforcement. One very powerful + use of these mechanisms is to identify method calls that, in a correct + program, should not exist. For example, the following aspect enforces + the constraint that only the well-known factory methods can add an + element to the registry of figure elements. Enforcing this constraint + ensures that no figure element is added to the registry more than + once.</para> + +<programlisting><![CDATA[ +static aspect RegistrationProtection { + + pointcut register(): call(void Registry.register(FigureElement)); + + pointcut canRegister(): withincode(static * FigureElement.make*(..)); + + before(): register() && !canRegister() { + throw new IllegalAccessException("Illegal call " + thisJoinPoint); + } +} +]]></programlisting> + + <para>This aspect uses the withincode primitive pointcut to denote all + join points that occur within the body of the factory methods on + <classname>FigureElement</classname> (the methods with names that begin + with "<literal>make</literal>"). This is a property-based pointcut + because it identifies join points based not on their signature, but + rather on the property that they occur specifically within the code of + another method. The before advice declaration effectively says signal + an error for any calls to register that are not within the factory + methods.</para> + + </sect2> + + <sect2 id="configurationmanagement" xreflabel="Configuration Management"> + <title>Configuration Management</title> + <indexterm> + <primary>configuration management</primary> + </indexterm> + + <para>Configuration management for aspects can be handled using a variety + of make-file like techniques. To work with optional aspects, the + programmer can simply define their make files to either include the + aspect in the call to the AspectJ compiler or not, as desired.</para> + + <para>Developers who want to be certain that no aspects are included in + the production build can do so by configuring their make files so that + they use a traditional Java compiler for production builds. To make it + easy to write such make files, the AspectJ compiler has a command-line + interface that is consistent with ordinary Java compilers.</para> + </sect2> + + </sect1> + + <sect1 id="productionaspects" xreflabel="Production Aspects"> + <title>Production Aspects</title> + <indexterm> + <primary>aspect</primary> + <secondary>production</secondary> + </indexterm> + + <para>This section presents examples of aspects that are inherently + intended to be included in the production builds of an application. + Production aspects tend to add functionality to an application rather + than merely adding more visibility of the internals of a program. Again, + we begin with name-based aspects and follow with property-based aspects. + Name-based production aspects tend to affect only a small number of + methods. For this reason, they are a good next step for projects + adopting AspectJ. But even though they tend to be small and simple, they + can often have a significant effect in terms of making the program easier + to understand and maintain.</para> + + <sect2> + <title>Change Monitoring</title> + <indexterm><primary>change monitoring</primary></indexterm> + + <para>The first example production aspect shows how one might implement + some simple functionality where it is problematic to try and do it + explicitly. It supports the code that refreshes the display. The role + of the aspect is to maintain a dirty bit indicating whether or not an + object has moved since the last time the display was refreshed.</para> + + <para>Implementing this functionality as an aspect is straightforward. + The <function>testAndClear</function> method is called by the display + code to find out whether a figure element has moved recently. This + method returns the current state of the dirty flag and resets it to + false. The pointcut <function>move</function> captures all the method + calls that can move a figure element. The after advice on + <function>move</function> sets the dirty flag whenever an object + moves.</para> + +<programlisting><![CDATA[ +aspect MoveTracking { + + private static boolean dirty = false; + + public static boolean testAndClear() { + boolean result = dirty; + dirty = false; + return result; + } + + pointcut move(): call(void FigureElement.setXY(int, int)) || + call(void Line.setP1(Point)) || + call(void Line.setP2(Point)) || + call(void Point.setX(int)) || + call(void Point.setY(int)); + + after() returning: move() { + dirty = true; + } +} +]]></programlisting> + + <para>Even this simple example serves to illustrate some of the important + benefits of using AspectJ in production code. Consider implementing + this functionality with ordinary Java: there would likely be a helper + class that contained the <literal>dirty</literal> flag, the + <function>testAndClear</function> method, as well as a + <function>setFlag</function> method. Each of the methods that could + move a figure element would include a call to the + <function>setFlag</function> method. Those calls, or rather the concept + that those calls should happen at each move operation, are the + crosscutting concern in this case. </para> + + <para>The AspectJ implementation has several advantages over the standard + implementation:</para> + + <para><emphasis>The structure of the crosscutting concern is captured + explicitly.</emphasis> The moves pointcut clearly states all the + methods involved, so the programmer reading the code sees not just + individual calls to <literal>setFlag</literal>, but instead sees the + real structure of the code. The IDE support included with AspectJ + automatically reminds the programmer that this aspect advises each of + the methods involved. The IDE support also provides commands to jump + to the advice from the method and vice-versa.</para> + + <para><emphasis>Evolution is easier.</emphasis> If, for example, the + aspect needs to be revised to record not just that some figure element + moved, but rather to record exactly which figure elements moved, the + change would be entirely local to the aspect. The pointcut would be + updated to expose the object being moved, and the advice would be + updated to record that object. The paper <citetitle>An Overview of + AspectJ</citetitle>, presented at ECOOP 2001, presents a detailed + discussion of various ways this aspect could be expected to + evolve.)</para> + + <para><emphasis>The functionality is easy to plug in and out.</emphasis> + Just as with development aspects, production aspects may need to be + removed from the system, either because the functionality is no longer + needed at all, or because it is not needed in certain configurations of + a system. Because the functionality is modularized in a single aspect + this is easy to do.</para> + + <para><emphasis>The implementation is more stable.</emphasis> If, for + example, the programmer adds a subclass of <classname>Line</classname> + that overrides the existing methods, this advice in this aspect will + still apply. In the ordinary Java implementation the programmer would + have to remember to add the call to <function>setFlag</function> in the + new overriding method. This benefit is often even more compelling for + property-based aspects (see the section <xref + linkend="consistentbehavior"/>). </para> + </sect2> + + <sect2> + <title>Context Passing</title> + + <para>The crosscutting structure of context passing can be a significant + source of complexity in Java programs. Consider implementing + functionality that would allow a client of the figure editor (a program + client rather than a human) to set the color of any figure elements + that are created. Typically this requires passing a color, or a color + factory, from the client, down through the calls that lead to the + figure element factory. All programmers are familiar with the + inconvenience of adding a first argument to a number of methods just to + pass this kind of context information.</para> + + <para>Using AspectJ, this kind of context passing can be implemented in a + modular way. The following code adds after advice that runs only when + the factory methods of <classname>Figure</classname> are called in the + control flow of a method on a + <classname>ColorControllingClient</classname>. </para> + +<programlisting><![CDATA[ +aspect ColorControl { + + pointcut CCClientCflow(ColorControllingClient client): + cflow(call(* * (..)) && target(client)); + + pointcut make(): call(FigureElement Figure.make*(..)); + + after (ColorControllingClient c) returning (FigureElement fe): + make() && CCClientCflow(c) { + + fe.setColor(c.colorFor(fe)); + } +}]]></programlisting> + + <para>This aspect affects only a small number of methods, but note that + the non-AOP implementation of this functionality might require editing + many more methods, specifically, all the methods in the control flow + from the client to the factory. This is a benefit common to many + property-based aspects while the aspect is short and affects only a + modest number of benefits, the complexity the aspect saves is + potentially much larger.</para> + + </sect2> + + <sect2 id="consistentbehavior" xreflabel="Providing Consistent Behavior"> + <title>Providing Consistent Behavior</title> + + <para>This example shows how a property-based aspect can be used to + provide consistent handling of functionality across a large set of + operations. This aspect ensures that all public methods of the + <literal>com.xerox</literal> package log any errors (a kind of + throwable, different from Exception) they throw to their caller. The + <function>publicMethodCall</function> pointcut captures the public + method calls of the package, and the after advice runs whenever one of + those calls returns throwing an exception. The advice logs the + exception and then the throw resumes.</para> + + <programlisting><![CDATA[ +aspect PublicErrorLogging { + Log log = new Log(); + + pointcut publicMethodCall(): call(public * com.xerox.*.*(..)); + + after() throwing (Error e): publicMethodCall() { log.write(e); } +}]]></programlisting> + + <para>In some cases this aspect can log an exception twice. This happens + if code inside the <literal>com.xerox</literal> package itself calls a + public method of the package. In that case this code will log the error + at both the outermost call into the <literal>com.xerox</literal> + package and the re-entrant call. The <function>cflow</function> + primitive pointcut can be used in a nice way to exclude these + re-entrant calls:</para> + + <programlisting><![CDATA[ +after() throwing (Error e): publicMethodCall() && + !cflow(publicMethodCall()) { + log.write(e); +}]]></programlisting> + + + <para>The following aspect is taken from work on the AspectJ compiler. + The aspect advises about 35 methods in the + <classname>JavaParser</classname> class. The individual methods handle + each of the different kinds of elements that must be parsed. They have + names like <function>parseMethodDec</function>, + <function>parseThrows</function>, and + <function>parseExpr</function>.</para> + + <programlisting><![CDATA[ +aspect ContextFilling { + pointcut parse(JavaParser jp): + call(* JavaParser.parse*(..)) + && target(jp) + && !call(Stmt parseVarDec(boolean)); // var decs + // are tricky + + around(JavaParser jp) returns ASTObject: parse(jp) { + Token beginToken = jp.peekToken(); + ASTObject ret = proceed(jp); + if (ret != null) jp.addContext(ret, beginToken); + return ret; + } +}]]></programlisting> + + <para>This example exhibits a property found in many aspects with large + property-based pointcuts. In addition to a general property based + pattern <literal>call(* JavaParser.parse*(..))</literal> it includes an + exception to the pattern <literal>!call(Stmt + parseVarDec(boolean))</literal>. The exclusion of + <function>parseVarDec</function> happens because the parsing of + variable declarations in Java is too complex to fit with the clean + pattern of the other <function>parse*</function> methods. Even with the + explicit exclusion this aspect is a clear expression of a clean + crosscutting modularity. Namely that all <function>parse*</function> + methods that return <classname>ASTObjects</classname>, except for + <function>parseVarDec</function> share a common behavior for + establishing the parse context of their result. </para> + + <para>The process of writing an aspect with a large property-based + pointcut, and of developing the appropriate exceptions can clarify the + structure of the system. This is especially true, as in this case, when + refactoring existing code to use aspects. When we first looked at the + code for this aspect, we were able to use the IDE support provided in + AJDE for JBuilder to see what methods the aspect was advising compared + to our manual coding. We quickly discovered that there were a dozen + places where the aspect advice was in effect but we had not manually + inserted the required functionality. Two of these were bugs in our + prior non-AOP implementation of the parser. The other ten were needless + performance optimizations. So, here, refactoring the code to express + the crosscutting structure of the aspect explicitly made the code more + concise and eliminated latent bugs.</para> + + </sect2> + + </sect1> + + <sect1> + <title>Static Crosscutting: Introduction</title> + <indexterm><primary>introduction</primary></indexterm> + + <para>Up until now we have only seen constructs that allow us to + implement dynamic crosscutting, crosscutting that changes the way a + program executes. AspectJ also allows us to implement static + crosscutting, crosscutting that affects the static structure of our + progams. This is done using forms called introduction.</para> + + <para>An <emphasis>introduction</emphasis> is a member of an aspect, but + it defines or modifies a member of another type (class). With + introduction we can</para> + <itemizedlist> + <listitem> + <para>add methods to an existing class</para> + </listitem> + <listitem> + <para>add fields to an existing class</para> + </listitem> + <listitem> + <para>extend an existing class with another</para> + </listitem> + <listitem> + <para>implement an interface in an existing class</para> + </listitem> + <listitem> + <para>convert checked exceptions into unchecked exceptions</para> + </listitem> + </itemizedlist> + + <para>Suppose we want to change the class + <classname>Point</classname> to support cloning. By using introduction, + we can add that capability. The class itself doesn't change, but its + users (here the method <function>main</function>) may. In the example + below, the aspect <classname>CloneablePoint</classname> does three + things: </para> + <orderedlist> + <listitem> + <para>declares that the class + <classname>Point</classname> implements the interface + <classname>Cloneable</classname>,</para> + </listitem> + <listitem> + <para>declares that the methods in <classname>Point</classname> whose + signature matches <literal>Object clone()</literal> should have + their checked exceptions converted into unchecked exceptions, + and</para> + </listitem> + <listitem> + <para>adds a method that overrides the method + <function>clone</function> in <classname>Point</classname>, which + was inherited from <classname>Object</classname>.</para> + </listitem> + </orderedlist> + + <programlisting> +class Point { + private int x, y; + + Point(int x, int y) { this.x = x; this.y = y; } + + int getX() { return this.x; } + int getY() { return this.y; } + + void setX(int x) { this.x = x; } + void setY(int y) { this.y = y; } + + public static void main(String[] args) { + + Point p = new Point(3,4); + Point q = (Point) p.clone(); + } +} + +aspect CloneablePoint { + declare parents: Point implements Cloneable; + + declare soft: CloneNotSupportedException: execution(Object clone()); + + Object Point.clone() { return super.clone(); } +}</programlisting> + + <para>Introduction is a powerful mechanism for capturing crosscutting + concerns because it not only changes the behavior of components in an + application, but also changes their relationship.</para> + + </sect1> + + <sect1> + <title>Conclusion</title> + + <para>AspectJ is a simple and practical aspect-oriented extension to + Java. With just a few new constructs, AspectJ provides support for modular + implementation of a range of crosscutting concerns.</para> + + <para> Adoption of AspectJ into an existing Java development project can be + a straightforward and incremental task. One path is to begin by + using only development aspects, going on to using production aspects and + then reusable aspects after building up experience with AspectJ. Adoption + can follow other paths as well. For example, some developers will + benefit from using production aspects right away. Others may be able to + write clean reusable aspects almost right away.</para> + + <para>AspectJ enables both name-based and property based crosscutting. + Aspects that use name-based crosscutting tend to affect a small number of + other classes. But despite their small scale, they can often eliminate + significant complexity compared to an ordinary Java implementation. + Aspects that use property-based crosscutting can have small or large + scale.</para> + + <para>Using AspectJ results in clean well-modularized implementations of + crosscutting concerns. When written as an AspectJ aspect the structure + of a crosscutting concern is explicit and easy to understand. Aspects + are also highly modular, making it possible to develop plug-and-play + implementations of crosscutting functionality.</para> + + <para>AspectJ provides more functionality than was covered by this short + introduction. The next chapter, <xref linkend="aspectjlanguage"/>, covers + in detail all the features of the AspectJ language. The following + chapter, <xref linkend="examples"/>, then presents some carefully chosen + examples that show you how AspectJ might be used. We recommend that you + read the next two chapters carefully before deciding to adopt AspectJ + into a project. + </para> + + </sect1> + +</chapter> + +<!-- +Local variables: +compile-command: "build.sh" +fill-column: 79 +sgml-local-ecat-files: progguide.ced +sgml-parent-document:("progguide.xml" "book" "chapter") +End: +--> diff --git a/docs/progGuideDB/glossary.xml b/docs/progGuideDB/glossary.xml new file mode 100644 index 000000000..4516ce2bd --- /dev/null +++ b/docs/progGuideDB/glossary.xml @@ -0,0 +1,192 @@ +<appendix id="glossary" xreflabel="Glossary"> + + <title>Glossary</title> + + <glosslist> + +<!-- + <glossentry><glossterm> +</glossterm> + <glossdef> + <para></para> + </glossdef> + </glossentry> + +--> + + <glossentry><glossterm> +advice</glossterm> + <glossdef> + <para>Code, similar to a method, that is executed when a join + point<emphasis></emphasis> is reached. There are three kinds of + advice: before advice that runs when a join point is reached, but + before the method in question executes, after advice that executes + after the method body executes, but before control returns to the + caller, and around advice that runs before and after the method in + question runs, and also has explicit control over whether the method + is run at all.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +AOP</glossterm> + <glossdef> + <para>See <emphasis>aspect-oriented programming</emphasis>.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +aspect</glossterm> + <glossdef> + <para>A modular unit of crosscutting implementation in + <emphasis>aspect-oriented programming</emphasis>, just as classes are + the modular unit of implementation in object-oriented + programming.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +aspect-oriented programming</glossterm> + <glossdef> + <para>A type or style of programming that explicitly takes into + account <emphasis>crosscutting concerns</emphasis>, just as + object-oriented programming explicitly takes into account classes and + objects. </para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +crosscutting concerns</glossterm> + <glossdef> + <para>Issues or programmer concerns that are not local to the natural + unit of modularity. </para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +dynamic context</glossterm> + <glossdef> + <para>The state of a program while it is executing. Contrast with + <emphasis>lexical context</emphasis>.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +join point</glossterm> + <glossdef> + <para> A well-defined instant in the execution of a program. In + AspectJ, join points are also principled, i.e. not every possible + instance in the execution of a program is a potential join point. + </para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +lexical context</glossterm> + <glossdef> + <para>The state of a program as it is written. Contrast with + <emphasis>dynamic context</emphasis>.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +name-based pointcut designator</glossterm> + <glossdef> + <para>A type of pointcut designator that enumerates and composes + explicitly named join points. For example,</para> + <programlisting> +pointcut move(): + call(void FigureElement.setXY(int,int)) || + call(void Point.setX(int)) || + call(void Point.setY(int)) || + call(void Line.setP1(Point)) || + call(void Line.setP2(Point));</programlisting> + <para>is a pointcut designator that explicitly names five join + points. See also <emphasis>property-based pointcut + designator</emphasis>. + </para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +pointcut</glossterm> + <glossdef> + <para>A collection of join points.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +pointcut designator</glossterm> + <glossdef> + <para>The name of a pointcut, or an expression which identifies a + pointcut. Pointcut designators can be primitive or composite. + Composite pointcut designators are primitive pointcut designators + composed using the operators <literal>||</literal>, + <literal>&&<literal>, and </literal>!</literal>. See also + <emphasis>name-based pointcut designator</emphasis> and + <emphasis>property-based pointcut sesignator</emphasis>. </para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +post-condition</glossterm> + <glossdef> + <para>A test or assertion that must be true after a method has + executed.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +pre-condition</glossterm> + <glossdef> + <para>A test or assertion that must be true when a method is + called.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +property-based pointcut designator</glossterm> + <glossdef> + <para>A type of pointcut designator that specifies pointcuts in terms + of the properties of methods rather than just their names. For + example,</para> + <programlisting> +call(public * Figure.*(..))</programlisting> + <para>specifies all the public methods in the class + <classname>Figure</classname> regardless of the type and number of + their arguments or return type. See also <emphasis>name-based + pointcut designator</emphasis>.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +reusable aspect</glossterm> + <glossdef> + <para>An aspect that can be extended or inherited from.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +signature</glossterm> + <glossdef> + <para>The number, order and type of the arguments to a method.</para> + </glossdef> + </glossentry> + + <glossentry><glossterm> +<literal>thisJoinPoint</literal></glossterm> + <glossdef> + <para>The special variable that identifies the current join point + when a non-static join point is reached.</para> + </glossdef> + </glossentry> + + </glosslist> + +</appendix> + +<!-- Local variables: --> +<!-- fill-column: 79 --> +<!-- sgml-local-ecat-files: progguide.ced --> +<!-- sgml-parent-document:("progguide.sgml" "book" "appendix") --> +<!-- End: --> diff --git a/docs/progGuideDB/idioms.xml b/docs/progGuideDB/idioms.xml new file mode 100644 index 000000000..5898dbd9e --- /dev/null +++ b/docs/progGuideDB/idioms.xml @@ -0,0 +1,104 @@ +<chapter id="idioms" xreflabel="Idioms"> + <title>Idioms</title> + + <sect1><!-- About this Chapter --> + <title>About this Chapter</title> + + <para>This chapter consists of very short snippets of AspectJ code, + typically pointcuts, that are particularly evocative or useful. + This section is a work in progress. + </para> + + <para> Here's an example of how to enfore a rule that code in the java.sql + package can only be used from one particular package in your system. This + doesn't require any access to code in the java.sql package. + </para> + +<programlisting><![CDATA[ +/* Any call to methods or constructors in java.sql */ +pointcut restrictedCall(): + call(* java.sql.*.*(..)) || call(java.sql.*.new(..)); + +/* Any code in my system not in the sqlAccess package */ +pointcut illegalSource(): + within(com.foo..*) && !within(com.foo.sqlAccess.*); + +declare error: restrictedCall() && illegalSource(): + "java.sql package can only be accessed from com.foo.sqlAccess"; +]]></programlisting> + + <para>Any call to an instance of a subtype of AbstractFacade whose class is + not exactly equal to AbstractFacade:</para> + +<programlisting><![CDATA[ +pointcut nonAbstract(AbstractFacade af): + call(* *(..)) + && target(af) + && !if(af.getClass() == AbstractFacade.class); +]]></programlisting> + + <para> If AbstractFacade is an abstract class or an interface, then every + instance must be of a subtype and you can replace this with: </para> + +<programlisting><![CDATA[ +pointcut nonAbstract(AbstractFacade af): + call(* *(..)) + && target(af); +]]></programlisting> + + <para> Any call to a method which is defined by a subtype of + AbstractFacade, but which isn't defined by the type AbstractFacade itself: + </para> + +<programlisting><![CDATA[ +pointcut callToUndefinedMethod(): + call(* AbstractFacade+.*(..)) + && !call(* AbstractFacade.*(..)); +]]></programlisting> + + <para> The execution of a method that is defined in the source code for a + type that is a subtype of AbstractFacade but not in AbstractFacade itself: + </para> + +<programlisting><![CDATA[ +pointcut executionOfUndefinedMethod(): + execution(* *(..)) + && within(AbstractFacade+) + && !within(AbstractFacade) +]]></programlisting> + + <para>To use a per-class variable declared on many classes, + you can defer initialization until you are in a non-static instance context + so you can refer to the particular class member. If you want to use + it from advice (without knowing the particular class at compile-time), + you can declare a method on the type. + </para> + +<programlisting><![CDATA[ +aspect Logging { + + //... + + /** per-Loggable-class reference to per-class Logger */ + static private Logger Loggable+.staticLogger; + + /** instance getter for static logger (lazy construction) */ + public Logger Loggable+.getLogger() { // XXX make private to aspect? + if (null == staticLogger) { + staticLogger = Logger.getLoggerFor(getClass()); + } + return staticLogger; + } + + /** when logging and logger enabled, log the target and join point */ + before(Loggable loggable) : target(loggable) && logging() { + Logger logger = loggable.getLogger(); + if (logger.enabled()) { + logger.log(loggable + " at " + thisJoinPoint); + } + } +} +]]></programlisting> + + </sect1> +</chapter> diff --git a/docs/progGuideDB/language.xml b/docs/progGuideDB/language.xml new file mode 100644 index 000000000..0f5e23561 --- /dev/null +++ b/docs/progGuideDB/language.xml @@ -0,0 +1,1226 @@ +<chapter id="aspectjlanguage" xreflabel="The AspectJ Language"> + + <title>The AspectJ Language</title> + + <sect1> + <title>Introduction</title> + + <para>The previous chapter, <xref linkend="gettingstarted"/>, was a brief + overview of the AspectJ language. You should read this chapter to + understand AspectJ's syntax and semantics. It covers the same material as + the previous chapter, but more completely and in much more detail. + </para> + + <para>We will start out by looking at an example aspect that we'll build + out of a pointcut, an introduction, and two pieces of advice. This + example aspect will gives us something concrete to talk about.</para> + + </sect1> + + <sect1 id="AnatomyOfAnAspect"> + <title>The Anatomy of an Aspect</title> + + <para> + This lesson explains the parts of AspectJ's aspects. By reading this + lesson you will have an overview of what's in an aspect and you will be + exposed to the new terminology introduced by AspectJ. + </para> + + <sect2> + <title>An Example Aspect</title> + + <para> + Here's an example of an aspect definition in AspectJ: + </para> + + <programlisting><![CDATA[ + 1 aspect FaultHandler { + 2 + 3 private boolean Server.disabled = false; + 4 + 5 private void reportFault() { + 6 System.out.println("Failure! Please fix it."); + 7 } + 8 + 9 public static void fixServer(Server s) { +10 s.disabled = false; +11 } +12 +13 pointcut services(Server s): target(s) && call(public * *(..)); +14 +15 before(Server s): services(s) { +16 if (s.disabled) throw new DisabledException(); +17 } +18 +19 after(Server s) throwing (FaultException e): services(s) { +20 s.disabled = true; +21 reportFault(); +22 } +23 } +]]></programlisting> + + <para> + The <literal>FaultHandler</literal> consists of one variable introduced + onto <literal>Server</literal> (line 03), two methods (lines 05-07 + and 09-11), one pointcut (line 13), and two pieces of advice (lines + 15-17 and 19-22). + </para> + + <para> + This covers the basics of what aspects can contain. In general, aspects + consist of an association with other program entities, ordinary + variables and methods, pointcuts, introductions, and advice, where + advice may be before, after or around advice. The remainder of this + lesson focuses on those crosscut-related constructs. + </para> + </sect2> + + <sect2> + <title>Pointcuts</title> + + <para> + AspectJ's pointcuts define collections of events, i.e. interesting + points in the execution of a program. These events, or points in the + execution, can be method or constructor invocations and executions, + handling of exceptions, field assignments and accesses, etc. Take, for + example, the pointcut declaration in line 13: + </para> + +<programlisting><![CDATA[ +pointcut services(Server s): target(s) && call(public * *(..)) +]]></programlisting> + + <para> + This pointcut, named <literal>services</literal>, picks out those points + in the execution of the program when instances of the + <literal>Server</literal> class have their public methods called. + </para> + + <para> + The idea behind this pointcut in the <literal>FaultHandler</literal> + aspect is that fault-handling-related behavior must be triggered on the + calls to public methods. For example, the server may be unable to + proceed with the request because of some fault. The calls of those + methods are, therefore, interesting events for this aspect, in the + sense that certain fault-related things will happen when these events + occur. + </para> + + <para> + Part of the context in which the events occur is exposed by the formal + parameters of the pointcut. In this case, that consists of objects of + type server. That formal parameter is then being used on the right + hand side of the declaration in order to identify which events the + pointcut refers to. In this case, a pointcut picking out join points + where a Server is the target of some operation (target(s)) is being + composed (<literal><![CDATA[&&]]></literal>, meaning and) with a + pointcut picking out call join points (call(...)). The calls are + identified by signatures that can include wild cards. In this case, + there are wild cards in the return type position (first *), in the name + position (second *) and in the argument list position (..); the only + concrete information is given by the qualifier public. + </para> + + <sect3> + <title>What else?</title> + + <para> + Pointcuts define arbitrarily large sets of points in the execution + of a program. But they use only a finite number of + <emphasis>kinds</emphasis> of points. Those kinds of points + correspond to some of the most important concepts in Java. Here is + an incomplete list: method invocation, method execution, exception + handling, instantiation, constructor execution. Each of these has a + specific syntax that you will learn about in other parts of this + guide. + </para> + </sect3> + </sect2> + + <sect2> + <title>Advice</title> + + <para> + Advice defines pieces of aspect implementation that execute at join + points picked out by a pointcut. For example, the advice in lines 15-17 + specifies that the following piece of code + </para> + +<programlisting><![CDATA[ +{ + if (s.disabled) throw new DisabledException(); +} +]]></programlisting> + + <para> + is executed when instances of the Server class have their public + methods called, as specified by the pointcut services. More + specifically, it runs when those calls are made, just before the + corresponding methods are executed. + </para> + + <para> + The advice in lines 19-22 defines another piece of implementation + that is executed on the same pointcut: + </para> + +<programlisting><![CDATA[ +{ + s.disabled = true; + reportFault(); +} +]]></programlisting> + + <para> + But this second method executes whenever those operations throw + exception of type <literal>FaultException</literal>. + </para> + + <sect3> + <title>What else?</title> + <para> + There are two other variations of after advice: upon successful + return and upon return, either successful or with an exception. + There is also a third kind of advice called around. You will see + those in other parts of this guide. + </para> + </sect3> + </sect2> + + </sect1> + + <sect1> + <title>Join Points and Pointcuts</title> + + <para> + Consider the following Java class: + </para> + +<programlisting><![CDATA[ +class Point { + private int x, y; + + Point(int x, int y) { this.x = x; this.y = y; } + + void setX(int x) { this.x = x; } + void setY(int y) { this.y = y; } + + int getX() { return x; } + int getY() { return y; } +} +]]></programlisting> + + <para> + In order to get an intuitive understanding of AspectJ's pointcuts, let's + go back to some of the basic principles of Java. Consider the following a + method declaration in class Point: + </para> + +<programlisting><![CDATA[ +void setX(int x) { this.x = x; } +]]></programlisting> + + <para> + What this piece of program states is that when an object of type Point + has a method called setX with an integer as the argument called on it, + then the method body { this.x = x; } is executed. Similarly, the + constructor given in that class states that when an object of type Point + is instantiated through a constructor with two integers as arguments, + then the constructor body { this.x = x; this.y = y; } is executed. + </para> + + <para> + One pattern that emerges from these descriptions is when something + happens, then something gets executed. In object-oriented programs, there + are several kinds of "things that happen" that are determined by the + language. We call these the join points of Java. Join points comprised + method calls, method executions, instantiations, constructor executions, + field references and handler executions. (See the quick reference for + complete listing.) + </para> + + <para> + Pointcuts pick out these join points. For example, the pointcut + </para> + +<programlisting><![CDATA[ +pointcut setter(): target(Point) && + (call(void setX(int)) || + call(void setY(int))); +]]></programlisting> + + <para> + describes the calls to <literal>setX(int)</literal> or + <literal>setY(int)</literal> methods of any instance of Point. Here's + another example: + </para> + +<programlisting><![CDATA[ +pointcut ioHandler(): within(MyClass) && handler(IOException); +]]></programlisting> + + <para> + This pointcut picks out the join points at which exceptions of type + IOException are handled inside the code defined by class MyClass. + </para> + + <para> + Pointcuts consist of a left-hand side and a right-hand side, separated by + a colon. The left-hand side defines the pointcut name and the pointcut + parameters (i.e. the data available when the events happen). The + right-hand side defines the events in the pointcut. + </para> + + <para> + Pointcuts can then be used to define aspect code in advice, as we will + see later. But first let's see what types of events can be captured and + how they are described in AspectJ. + </para> + + <sect2> + <title>Designators</title> + + <para> + Here are examples of designators of + </para> + <glosslist> + + <glossentry> + <glossterm>when a particular method body executes</glossterm> + <glossdef> + <para> + <literal>execution(void Point.setX(int))</literal> + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>when a method is called</glossterm> + <glossdef> + <para> + <literal>call(void Point.setX(int))</literal> + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>when an exception handler executes</glossterm> + <glossdef> + <para> + <literal>handler(ArrayOutOfBoundsException)</literal> + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>when the object currently executing + (i.e. <literal>this</literal>) is of type <literal>SomeType</literal></glossterm> + <glossdef> + <para> + <literal>this(SomeType)</literal> + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>when the target object is of type + <literal>SomeType</literal></glossterm> + <glossdef> + <para> + <literal>target(SomeType)</literal> + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>when the executing code belongs to + class <literal>MyClass</literal></glossterm> + <glossdef> + <para> + <literal>within(MyClass)</literal> + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>when the join point is in the control flow of a call to a + <literal>Test</literal>'s no-argument <literal>main</literal> method + </glossterm> + <glossdef> + <para> + <literal>cflow(void Test.main())</literal> + </para> + </glossdef> + </glossentry> + + + </glosslist> + + <para> + Designators compose through the operations <literal>or</literal> + ("<literal>||</literal>"), <literal>and</literal> + ("<literal><![CDATA[&&]]></literal>") and <literal>not</literal> + ("<literal>!</literal>"). + </para> + + <itemizedlist> + <listitem> + <para> + It is possible to use wildcards. So + <orderedlist> + <listitem> + <para> + <literal>execution(* *(..))</literal> + </para> + </listitem> + + <listitem> + <para> + <literal>call(* set(..))</literal> + </para> + </listitem> + </orderedlist> + means (1) all the executions of methods with any return and + parameter types and (2) method calls of set methods with any + return and parameter types -- in case of overloading there may be + more than one; this designator picks out all of them. + </para> + </listitem> + + <listitem> + <para> + You can select elements based on types. For example, + <orderedlist> + <listitem> + <para> + <literal>execution(int *())</literal> + </para> + </listitem> + + <listitem> + <para> + <literal>call(* setY(long))</literal> + </para> + </listitem> + + <listitem> + <para> + <literal>call(* Point.setY(int))</literal> + </para> + </listitem> + + <listitem> + <para> + <literal>call(*.new(int, int))</literal> + </para> + </listitem> + + </orderedlist> + means (1) all executions of methods with no parameters, returning + an <literal>int</literal> (2) the calls of + <literal>setY</literal> methods that take a + <literal>long</literal> as an argument, regardless of their return + type or defining type, (3) the calls of class + <literal>Point</literal>'s <literal>setY</literal> methods that + take an <literal>int</literal> as an argument, regardless of the + return type, and (4) the calls of all classes' constructors that + take two <literal>int</literal>s as arguments. + </para> + </listitem> + + <listitem> + <para> + You can compose designators. For example, + <orderedlist> + <listitem> + <para> + <literal>target(Point) <![CDATA[&&]]> call(int *())</literal> + </para> + </listitem> + + <listitem> + <para> + <literal>call(* *(..)) <![CDATA[&&]]> (within(Line) || within(Point))</literal> + </para> + </listitem> + + <listitem> + <para> + <literal>within(*) <![CDATA[&&]]> execution(*.new(int))</literal> + </para> + </listitem> + + <listitem> + <para> + <literal>this(*) <![CDATA[&&]]> !this(Point) <![CDATA[&&]]> + call(int *(..))</literal> + </para> + </listitem> + </orderedlist> + + means (1) all calls to methods received by instances of class + <literal>Point</literal>, with no parameters, returning an + <literal>int</literal>, (2) calls to any method where the call is + made from the code in <literal>Point</literal>'s or + <literal>Line</literal>'s type declaration, (3) executions of + constructors of all classes, that take an <literal>int</literal> as + an argument, and + (4) all method calls of any method returning an + <literal>int</literal>, from all objects except + <literal>Point</literal> objects to any other objects. + + </para> + </listitem> + + <listitem> + <para> + You can select methods and constructors based on their modifiers + and on negations of modifiers. For example, you can say: + <orderedlist> + <listitem> + <para> + <literal>call(public * *(..))</literal> + </para> + </listitem> + + <listitem> + <para> + <literal>execution(!static * *(..))</literal> + </para> + </listitem> + + <listitem> + <para> + <literal> execution(public !static * *(..))</literal> + </para> + </listitem> + + </orderedlist> + which means (1) all invocation of public methods, (2) all + executions of non-static methods, and (3) all signatures of + the public, non-static methods. + </para> + </listitem> + + <listitem> + <para> + Designators can also deal with interfaces. For example, given the + interface </para> + + <programlisting><![CDATA[ +interface MyInterface { ... }]]></programlisting> + + <para> the designator <literal>call(* MyInterface.*(..))</literal> + picks out the call join points for methods defined by the interface + <literal>MyInterface</literal> (or its superinterfaces). + </para> + </listitem> + + </itemizedlist> + </sect2> + + <sect2> + <title>call vs. execution</title> + + <para> + When methods and constructors run, there are two interesting times + associated with them. That is when they are called, and when they + actually execute. + </para> + + <para> + AspectJ exposes these times as call and execution join points, + respectively, and allows them to be picked out specifically by call and + execution pointcuts. + </para> + + <para> + So what's the difference between these times? Well, there are a number + of differences: + </para> + + <para> + Firstly, the lexical pointcut declarations <literal>within</literal> + and <literal>withincode</literal> match differently. At a call join + point, the enclosing text is that of the call site. This means that + This means that <literal>call(void m()) <![CDATA[&&]]> within(void m())</literal> + will only capture recursive calls, for example. At an execution join + point, however, the control is already executing the method. + </para> + + <para> + Secondly, the call join point does not capture super calls to + non-static methods. This is because such super calls are different in + Java, since they don't behave via dynamic dispatch like other calls to + non-static methods. + </para> + + <para> + The rule of thumb is that if you want to pick a join point that runs + when an actual piece of code runs, pick an execution, but if you want + to pick one that runs when a particular signature is called, pick a + call. + </para> + </sect2> + + + + <sect2> + <title>Pointcut composition</title> + + <para>Pointcuts are put together with the operators and (spelled + <literal>&&</literal>), or (spelled <literal>||</literal>), and + not (spelled <literal>!</literal>). This allows the creation of very + powerful pointcuts from the simple building blocks of primitive + pointcuts. This composition can be somewhat confusing when used with + primitive pointcuts like cflow and cflowbelow. Here's an example: + </para> + + <para> <literal>cflow(<replaceable>P</replaceable>)</literal> picks out + the join points in the control flow of the join points picked out by + <replaceable>P</replaceable>. So, pictorially: + </para> + +<programlisting> + P --------------------- + \ + \ cflow of P + \ +</programlisting> + + + <para>What does <literal>cflow(<replaceable>P</replaceable>) && + cflow(<replaceable>Q</replaceable>)</literal> pick out? Well, it picks + out those join points that are in both the control flow of + <replaceable>P</replaceable> and in the control flow of + <replaceable>Q</replaceable>. So... + </para> + +<programlisting> + P --------------------- + \ + \ cflow of P + \ + \ + \ + Q -------------\------- + \ \ + \ cflow of Q \ cflow(P) && cflow(Q) + \ \ +</programlisting> + + <para>Note that <replaceable>P</replaceable> and <replaceable>Q</replaceable> might + not have any join points in common... but their control flows might have join + points in common. + </para> + + <para>But what does <literal>cflow(<replaceable>P</replaceable> + && <replaceable>Q</replaceable>)</literal> mean? Well, it means + the control flow of those join points that are both picked out by + <replaceable>P</replaceable> picked out by <replaceable>Q</replaceable>. + </para> + +<programlisting> + P && Q ------------------- + \ + \ cflow of (P && Q) + \ +</programlisting> + + <para>and if there are <emphasis>no</emphasis> join points that are both picked by + <replaceable>P</replaceable> and picked out by <replaceable>Q</replaceable>, + then there's no chance that there are any join points in the control flow of + <literal>(<replaceable>P</replaceable> && + <replaceable>Q</replaceable>)</literal>. + </para> + + <para>Here's some code that expresses this. + </para> + +<programlisting><![CDATA[ +public class Test { + public static void main(String[] args) { + foo(); + } + static void foo() { + goo(); + } + static void goo() { + System.out.println("hi"); + } +} + +aspect A { + + pointcut fooPC(): execution(void Test.foo()); + pointcut gooPC(): execution(void Test.goo()); + pointcut printPC(): call(void java.io.PrintStream.println(String)); + + before(): cflow(fooPC()) && cflow(gooPC()) && printPC() { + System.out.println("should occur"); + } + + before(): cflow(fooPC() && gooPC()) && printPC() { + System.out.println("should not occur"); + } + +} +]]></programlisting> + + </sect2> + + <sect2> + <title>Pointcut Parameters</title> + + <para> + Consider, for example, the first pointcut you've seen here, + </para> + +<programlisting><![CDATA[ + pointcut setter(): target(Point) && + (call(void setX(int)) || + call(void setY(int))); +]]></programlisting> + + <para> + As we've seen before, the right-hand side of the pointcut picks out the + calls to <literal>setX(int)</literal> or <literal>setY(int)</literal> + methods where the target is any object of type + <literal>Point</literal>. On the left-hand side, the pointcut is given + the name "setters" and no parameters. An empty parameter list means + that when those events happen no context is immediately available. But + consider this other version of the same pointcut: + </para> + +<programlisting><![CDATA[ + pointcut setter(Point p): target(p) && + (call(void setX(int)) || + call(void setY(int))); +]]></programlisting> + + <para> + This version picks out exactly the same calls. But in this version, the + pointcut has one parameter of type <literal>Point</literal>. This means + that when the events described on the right-hand side happen, a + <literal>Point</literal> object, named by a parameter named "p", is + available. According to the right-hand side of the pointcut, that + <literal>Point</literal> object in the pointcut parameters is the + object that receives the calls. + </para> + + <para> + Here's another example that illustrates the flexible mechanism for + defining pointcut parameters: + </para> + +<programlisting><![CDATA[ + pointcut testEquality(Point p): target(Point) && + args(p) && + call(boolean equals(Object)); +]]></programlisting> + + <para> + This pointcut also has a parameter of type <literal>Point</literal>. + Similarly to the "setters" pointcut, this means that when the events + described on the right-hand side happen, a <literal>Point</literal> + object, named by a parameter named "p", is available. But in this case, + looking at the right-hand side, we find that the object named in the + parameters is not the target <literal>Point</literal> object that receives the + call; it's the argument (of type Point) passed to the "equals" method on some other + target Point object. If we wanted access to both objects, then the pointcut + definition that would define target <literal>Point p1</literal> + and argument <literal>Point p2</literal> would be + </para> + +<programlisting><![CDATA[ + pointcut testEquality(Point p1, Point p2): target(p1) && + args(p2) && + call(boolean equals(Object)); +]]></programlisting> + + <para> + Let's look at another variation of the "setters" pointcut: + </para> + +<programlisting><![CDATA[ +pointcut setter(Point p, int newval): target(p) && + args(newval) && + (call(void setX(int)) || + call(void setY(int))); +]]></programlisting> + + <para> + In this case, a <literal>Point</literal> object and an integer value + are available when the calls happen. Looking at the events definition + on the right-hand side, we find that the <literal>Point</literal> + object is the object receiving the call, and the integer + value is the argument of the method . + </para> + + <para> + The definition of pointcut parameters is relatively flexible. The most + important rule is that when each of those events defined in the + right-hand side happen, all the pointcut parameters must be bound to + some value. So, for example, the following pointcut definition will + result in a compilation error: + </para> + +<programlisting><![CDATA[ + pointcut xcut(Point p1, Point p2): + (target(p1) && call(void setX(int))) || + (target(p2) && call(void setY(int))); +]]></programlisting> + + <para> + The right-hand side establishes that this pointcut picks out the call + join points consisting of the <literal>setX(int)</literal> method + called on a point object, or the <literal>setY(int)</literal> method + called on a point object. This is fine. The problem is that the + parameters definition tries to get access to two point objects. But + when <literal>setX(int)</literal> is called on a point object, there is + no other point object to grab! So in that case, the parameter + <literal>p2</literal> is unbound, and hence, the compilation error. + </para> + + </sect2> + + <sect2> + <title>Example: <literal>HandleLiveness</literal></title> + + <para> + The example below consists of two object classes (plus an exception + class) and one aspect. Handle objects delegate their public, non-static + operations to their <literal>Partner</literal> objects. The aspect + <literal>HandleLiveness</literal> ensures that, before the delegations, + the partner exists and is alive, or else it throws an exception.</para> + +<programlisting><![CDATA[ + class Handle { + Partner partner = new Partner(); + + public void foo() { partner.foo(); } + public void bar(int x) { partner.bar(x); } + + public static void main(String[] args) { + Handle h1 = new Handle(); + h1.foo(); + h1.bar(2); + } + } + + class Partner { + boolean isAlive() { return true; } + void foo() { System.out.println("foo"); } + void bar(int x) { System.out.println("bar " + x); } + } + + aspect HandleLiveness { + before(Handle handle): target(handle) && call(public * *(..)) { + if ( handle.partner == null || !handle.partner.isAlive() ) { + throw new DeadPartnerException(); + } + } + } + + class DeadPartnerException extends RuntimeException {} +]]></programlisting> + + </sect2> + + </sect1> + + <sect1> + <title>Advice</title> + + <para> + Advice defines pieces of aspect implementation that execute at + well-defined points in the execution of the program. Those points can be + given either by named pointcuts (like the ones you've seen above) or by + anonymous pointcuts. Here is an example of an advice on a named pointcut: + </para> + +<programlisting><![CDATA[ + pointcut setter(Point p1, int newval): target(p1) && args(newval) + (call(void setX(int) || + call(void setY(int))); + + before(Point p1, int newval): setter(p1, newval) { + System.out.println("About to set something in " + p1 + + " to the new value " + newval); + } +]]></programlisting> + + <para> + And here is exactly the same example, but using an anonymous + pointcut: + </para> + +<programlisting><![CDATA[ + before(Point p1, int newval): target(p1) && args(newval) + (call(void setX(int)) || + call(void setY(int))) { + System.out.println("About to set something in " + p1 + + " to the new value " + newval); + } +]]></programlisting> + + <para> + Here are examples of the different advice: + </para> + +<programlisting><![CDATA[ + before(Point p, int x): target(p) && args(x) && call(void setX(int)) { + if (!p.assertX(x)) return; + } +]]></programlisting> + + <para> + This before advice runs just before the execution of the actions + associated with the events in the (anonymous) pointcut. + </para> + +<programlisting><![CDATA[ + after(Point p, int x): target(p) && args(x) && call(void setX(int)) { + if (!p.assertX(x)) throw new PostConditionViolation(); + } +]]></programlisting> + + <para> + This after advice runs just after each join point picked out by the + (anonymous) pointcut, regardless of whether it returns normally or throws + an exception. + </para> + +<programlisting><![CDATA[ + after(Point p) returning(int x): target(p) && call(int getX()) { + System.out.println("Returning int value " + x + " for p = " + p); + } +]]></programlisting> + + <para> + This after returning advice runs just after each join point picked out by + the (anonymous) pointcut, but only if it returns normally. The return + value can be accessed, and is named <literal>x</literal> here. After the + advice runs, the return value is returned. + </para> + +<programlisting><![CDATA[ + after() throwing(Exception e): target(Point) && call(void setX(int)) { + System.out.println(e); + } +]]></programlisting> + + <para> + This after throwing advice runs just after each join point picked out by + the (anonymous) pointcut, but only when it throws an exception of type + <literal>Exception</literal>. Here the exception value can be accessed + with the name <literal>e</literal>. The advice re-raises the exception + after it's done. + </para> + +<programlisting><![CDATA[ +void around(Point p, int x): target(p) + && args(x) + && call(void setX(int)) { + if (p.assertX(x)) proceed(p, x); + p.releaseResources(); +} +]]></programlisting> + + <para> + This around advice traps the execution of the join point; it runs + <emphasis>instead</emphasis> of the join point. The original action + associated with the join point can be invoked through the special + <literal>proceed</literal> call. + </para> + + </sect1> + + <sect1> + <title>Introduction</title> + + <para> + Introduction declarations add whole new elements in the given types, and + so change the type hierarchy. Here are examples of introduction + declarations: + </para> + +<programlisting><![CDATA[ + private boolean Server.disabled = false; +]]></programlisting> + + <para> + This privately introduces a field named <literal>disabled</literal> in + <literal>Server</literal> and initializes it to + <literal>false</literal>. Because it is declared + <literal>private</literal>, only code defined in the aspect can access + the field. + </para> + +<programlisting><![CDATA[ + public int Point.getX() { return x; } +]]></programlisting> + + <para> + This publicly introduces a method named <literal>getX</literal> in + <literal>Point</literal>; the method returns an <literal>int</literal>, + it has no arguments, and its body is return <literal>x</literal>. + Because it is defined publically, any code can call it. + </para> + +<programlisting><![CDATA[ + public Point.new(int x, int y) { this.x = x; this.y = y; } +]]></programlisting> + + <para> + This publicly introduces a constructor in Point; the constructor has + two arguments of type int, and its body is this.x = x; this.y = y; + </para> + +<programlisting><![CDATA[ + public int Point.x = 0; +]]></programlisting> + + <para> + This publicly introduces a field named x of type int in Point; the + field is initialized to 0. + </para> + +<programlisting><![CDATA[ + declare parents: Point implements Comparable; +]]></programlisting> + + <para> + This declares that the <literal>Point</literal> class now implements the + <literal>Comparable</literal> interface. Of course, this will be an error + unless <literal>Point</literal> defines the methods of + <literal>Comparable</literal>. + </para> + +<programlisting><![CDATA[ + declare parents: Point extends GeometricObject; +]]></programlisting> + + <para> + This declares that the <literal>Point</literal> class now extends the + <literal>GeometricObject</literal> class. + </para> + + <para> + An aspect can introduce several elements in at the same time. For + example, the following declaration + </para> + +<programlisting><![CDATA[ + public String Point.name; + public void Point.setName(String name) { this.name = name; } +]]></programlisting> + + <para> + publicly introduces both a field and a method into class + <literal>Point</literal>. Note that the identifier "name" in the body of + the method is bound to the "name" field in <literal>Point</literal>, even + if the aspect defined another field called "name". + </para> + + <para> + One declaration can introduce several elements in several classes as + well. For example, + </para> + +<programlisting><![CDATA[ + public String (Point || Line || Square).getName() { return name; } +]]></programlisting> + + <para> + publicly introduces three methods, one in <literal>Point</literal>, + another in Line and another in <literal>Square</literal>. The three + methods have the same name (getName), no parameters, return a String, and + have the same body (return name;). The purpose of introducing several + elements in one single declaration is that their bodies are the same. The + introduction is an error if any of <literal>Point</literal>, + <literal>Line</literal>, or <literal>Square</literal> do not have a + "name" field. + </para> + + <para> + An aspect can introduce fields and methods (even with bodies) onto + interfaces as well as classes. + </para> + + <sect2> + <title>Introduction Scope</title> + + <para> + AspectJ allows private and package-protected (default) introduction in + addition to public introduction. Private introduction means private in + relation to the aspect, not necessarily the target type. So, if an + aspect makes a private introduction of a field on a type + </para> + +<programlisting><![CDATA[ + private int Foo.x; +]]></programlisting> + + <para> + Then code in the aspect can refer to Foo's x field, but nobody else + can. Similarly, if an aspect makes a package-protected + introduction, + </para> + +<programlisting><![CDATA[ + int Foo.x; +]]></programlisting> + + <para> + then everything in the aspect's package (which may not be Foo's + package) can access x. + </para> + </sect2> + + <sect2> + <title>Example: <literal>PointAssertions</literal></title> + <para> + The example below consists of one class and one aspect. The aspect + introduces all implementation that is related with assertions of the + class. It privately introduces two methods in the class Point, namely + assertX and assertY. It also advises the two set methods of Point with + before declarations that assert the validity of the given values. The + introductions are made privately because other parts of the program + have no business accessing the assert methods. Only the code inside of + the aspect can call those methods. + </para> + +<programlisting><![CDATA[ + class Point { + int x, y; + + public void setX(int x) { this.x = x; } + public void setY(int y) { this.y = y; } + + public static void main(String[] args) { + Point p = new Point(); + p.setX(3); p.setY(333); + } + } + + aspect PointAssertions { + + private boolean Point.assertX(int x) { + return (x <= 100 && x >= 0); + } + private boolean Point.assertY(int y) { + return (y <= 100 && y >= 0); + } + + before(Point p, int x): target(p) && args(x) && call(void setX(int)) { + if (!p.assertX(x)) { + System.out.println("Illegal value for x"); return; + } + } + before(Point p, int y): target(p) && args(y) && call(void setY(int)) { + if (!p.assertY(y)) { + System.out.println("Illegal value for y"); return; + } + } + } +]]></programlisting> + + </sect2> + </sect1> + +<!-- ================================================== --> + + <sect1> + <title>Reflection</title> + + <para> + AspectJ provides a special reference variable, thisJoinPoint, that + contains reflective information about the current join point for the + advice to use. The thisJoinPoint variable can only be used in the context + of advice, just like this can only be used in the context of non-static + methods and variable initializers. In advice, thisJoinPoint is an object + of type JoinPoint. + </para> + + <para> + One way to use it is simply to print it out. Like all Java objects, + thisJoinPoint has a toString() method that makes quick-and-dirty tracing + easy. + </para> + +<programlisting><![CDATA[ + class TraceNonStaticMethods { + before(Point p): target(p) && call(* *(..)) { + System.out.println("Entering " + thisJoinPoint + " in " + p); + } + } +]]></programlisting> + + <para> + The type of thisJoinPoint includes a rich reflective class hierarchy of + signatures, and can be used to access both static and dynamic information + about join points. If, however, only the static information about the + join point (such as the Signature) is desired, a lightweight join-point + object is available from the thisJoinPointStaticPart special variable. + This object is the same object you would get from + </para> + + +<programlisting><![CDATA[ + thisJoinPoint.getStaticPart() +]]></programlisting> + + <para> + The static part of a join point does not include dynamic information, + such as the arguments, which can be accessed with + </para> + +<programlisting><![CDATA[ + thisJoinPoint.getArgs() +]]></programlisting> + + <para> + But it has the performance benefit that repeated execution of the code + containing <literal>thisJoinPointStaticPart</literal> (through, for + example, separate method calls) will not result in repeated construction + of the reflective object. + </para> + + <para>It is always the case that + </para> + +<programlisting><![CDATA[ + thisJoinPointStaticPart == thisJoinPoint.getStaticPart() + + thisJoinPoint.getKind() == thisJoinPointStaticPart.getKind() + thisJoinPoint.getSignature() == thisJoinPointStaticPart.getSignature() + thisJoinPoint.getSourceLocation() == thisJoinPointStaticPart.getSourceLocation() +]]></programlisting> + + <para> + One more reflective variable is available: + <literal>thisEnclosingJoinPointStaticPart</literal>. This, like + <literal>thisJoinPointStaticPart</literal>, only holds the static part of + a join point, but it is not the current but the enclosing join point. + So, for example, it is possible to print out the calling source location + (if available) with + </para> + + +<programlisting><![CDATA[ + before() : execution (* *(..)) { + System.err.println(thisEnclosingJoinPointStaticPart.getSourceLocation()) + } +]]></programlisting> + + </sect1> + +</chapter> + +<!-- Local variables: --> +<!-- fill-column: 79 --> +<!-- compile-command: "ant -quiet prog-html" --> +<!-- sgml-local-ecat-files: progguide.ced --> +<!-- sgml-parent-document:("progguide.xml" "book" "chapter") --> +<!-- End: --> diff --git a/docs/progGuideDB/limitations.xml b/docs/progGuideDB/limitations.xml new file mode 100644 index 000000000..41e10db45 --- /dev/null +++ b/docs/progGuideDB/limitations.xml @@ -0,0 +1,123 @@ +<appendix id="limitations" xreflabel="Implementation Limitations"> + + <title>Implementation Limitations</title> + + <para> + Certain elements of AspectJ's semantics are difficult to implement without + making modifications to the virtual machine. One way to deal with this + problem would be to specify only the behavior that is easiest to implement. + We have chosen a somewhat different approach, which is to specify an ideal + language semantics, as well as a clearly defined way in which + implementations are allowed to deviate from that semantics. This makes it + possible to develop conforming AspectJ implementations today, while still + making it clear what later, and presumably better, implementations should do + tomorrow. + </para> + + <para> + According to the AspectJ language semantics, the declaration + </para> + +<programlisting><![CDATA[ +before(): get(int Point.x) { System.out.println("got x"); } +]]></programlisting> + + <para> + should advise all accesses of a field of type int and name x from instances + of type (or subtype of) Point. It should do this regardless of whether all + the source code performing the access was available at the time the aspect + containing this advice was compiled, whether changes were made later, etc. + </para> + + <para> + But AspectJ implementations are permitted to deviate from this in a + well-defined way -- they are permitted to advise only accesses in + <emphasis>code the implementation controls</emphasis>. Each implementation + is free within certain bounds to provide its own definition of what it means + to control code. + </para> + + <para> + In the current AspectJ compiler, ajc, control of the code means having + source code for any aspects and all the code they should affect available + during the compile. This means that if some class Client contains code with + the expression <literal>new Point().x</literal> (which results in a field + get join point at runtime), the current AspectJ compiler will fail to advise + that access unless Client.java is compiled at the same the aspect is + compiled. It also means that join points associated with code in precompiled + libraries (such as java.lang), and join points associated with code in + native methods (including their execution join points), can not be advised. + </para> + + <para> + Different join points have different requirements. Method call join points + can be advised only if ajc controls <emphasis>either</emphasis> the code for + the caller or the code for the receiver, and some call pointcut designators + may require caller context (what the static type of the receiver is, for + example) to pick out join points. Constructor call join points can be + advised only if ajc controls the code for the caller. Field reference or + assignment join points can be advised only if ajc controls the code for the + "caller", the code actually making the reference or assignment. + Initialization join points can be advised only if ajc controls the code of + the type being initialized, and execution join points can be advised only if + ajc controls the code for the method or constructor body in question. + </para> + + <para> + Aspects that are defined <literal>perthis</literal> or + <literal>pertarget</literal> also have restrictions based on control of the + code. In particular, at a join point where the source code for the + currently executing object is not available, an aspect defined + <literal>perthis</literal> of that join point will not be associated. So + aspects defined <literal>perthis(Object)</literal> will not create aspect + instances for every object, just those whose class the compiler controls. + Similar restrictions apply to <literal>pertarget</literal> aspects. + </para> + + <para> + Inter-type declarations such as <literal>declare parents</literal> also have + restrictions based on control of the code. If the code for the target of an + inter-type declaration is not available, then the inter-type declaration is + not made on that target. So, <literal>declare parents : String implements + MyInterface</literal> will not work for + <literal>java.lang.String</literal>. + </para> + + <para> + Other AspectJ implementations, indeed, future versions of ajc, may define + <emphasis>code the implementation controls</emphasis> more liberally. + </para> + + <para> + Control may mean that classes need only be available in classfile or jarfile + format. So, even if Client.java and Point.java were precompiled, their join + points could still be advised. In such a system, though, it might still be + the case that join points from code of system libraries such as java.lang + could not be advised. + </para> + + <para> + Or control could even include system libraries, thus allowing a call join + point from java.util.Hashmap to java.lang.Object to be advised. + </para> + + <para> + All AspectJ implementations are required to control the code of the + files that the compiler compiles itself. + </para> + + <para> + The important thing to remember is that core concepts of AspectJ, + such as the join point, are unchanged, regardless of which + implementation is used. During your development, you will have to + be aware of the limitations of the ajc compiler you're using, but + these limitations should not drive the design of your aspects. + </para> + +</appendix> + +<!-- Local variables: --> +<!-- fill-column: 79 --> +<!-- sgml-local-ecat-files: progguide.ced --> +<!-- sgml-parent-document:("progguide.sgml" "book" "appendix") --> +<!-- End: --> diff --git a/docs/progGuideDB/overview.gif b/docs/progGuideDB/overview.gif Binary files differnew file mode 100644 index 000000000..7b1d6c8d6 --- /dev/null +++ b/docs/progGuideDB/overview.gif diff --git a/docs/progGuideDB/pitfalls.xml b/docs/progGuideDB/pitfalls.xml new file mode 100644 index 000000000..5379d5daa --- /dev/null +++ b/docs/progGuideDB/pitfalls.xml @@ -0,0 +1,103 @@ +<chapter id="pitfalls" xreflabel="Pitfalls"> + <title>Pitfalls</title> + + <sect1><!-- About this Chapter --> + <title>About this Chapter</title> + + <para>This chapter consists of aspectj programs that may lead to surprising + behaviour and how to understand them. + </para> + + </sect1> + + <sect1> + <title>Infinite loops</title> + + <para>Here is a Java program with peculiar behavior </para> + +<programlisting><![CDATA[ +public class Main { + public static void main(String[] args) { + foo(); + System.out.println("done with call to foo"); + } + + static void foo() { + try { + foo(); + } finally { + foo(); + } + } +} +]]></programlisting> + + <para>This program will never reach the println call, but when it aborts + will have no stack trace. </para> + + <para>This silence is caused by multiple StackOverflowExceptions. First + the infinite loop in the body of the method generates one, which the + finally clause tries to handle. But this finally clause also generates an + infinite loop which the current JVMs can't handle gracefully leading to the + completely silent abort. </para> + + <para> The following short aspect will also generate this behavior: + </para> + +<programlisting><![CDATA[ +aspect A { + before(): call(* *(..)) { System.out.println("before"); } + after(): call(* *(..)) { System.out.println("after"); } +} +]]></programlisting> + + <para>Why? Because the call to println is also a call matched by the + pointcut <literal>call (* *(..))</literal>. We get no output because we + used simple after() advice. If the aspect were changed to</para> + +<programlisting><![CDATA[ +aspect A { + before(): call(* *(..)) { System.out.println("before"); } + after() returning: call(* *(..)) { System.out.println("after"); } +} +]]></programlisting> + + <para>Then at least a StackOverflowException with a stack trace would be + seen. In both cases, though, the overall problem is advice applying within + its own body. </para> + + <para>There's a simple idiom to use if you ever have a worry that your + advice might apply in this way. Just restrict the advice from occurring in + join points caused within the aspect. So: </para> + +<programlisting><![CDATA[ +aspect A { + before(): call(* *(..)) && !within(A) { System.out.println("before"); } + after() returning: call(* *(..)) && !within(A) { System.out.println("after"); } +} +]]></programlisting> + + <para>Other solutions might be to more closely restrict the pointcut in + other ways, for example: </para> + +<programlisting><![CDATA[ +aspect A { + before(): call(* MyObject.*(..)) { System.out.println("before"); } + after() returning: call(* MyObject.*(..)) { System.out.println("after"); } +} +]]></programlisting> + + <para>The moral of the story is that unrestricted generic pointcuts can + pick out more join points than intended. </para> + + </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: +--> diff --git a/docs/progGuideDB/preface.xml b/docs/progGuideDB/preface.xml new file mode 100644 index 000000000..4f5575fcf --- /dev/null +++ b/docs/progGuideDB/preface.xml @@ -0,0 +1,52 @@ +<preface> + <title>Preface</title> + + <para> + This user's guide does three things. It + <itemizedlist spacing="compact"> + <listitem> + <para>introduces the AspectJ language</para> + </listitem> + + <listitem> + <para> + defines each of AspectJ's constructs and their semantics, and</para> + </listitem> + + <listitem> + <para> + provides examples of their use.</para> + </listitem> + </itemizedlist> + Three appendices give a quick reference, a more formal definition of + AspectJ, and a glossary. + </para> + + <para>The first section, <xref linkend="gettingstarted" />, provides a gentle + overview of writing AspectJ programs. It also shows how one can introduce + AspectJ into an existing development effort in stages, reducing the + associated risk. You should read this section if this is your first + exposure to AspectJ and you want to get a sense of what AspectJ is all + about.</para> + + <para>The second section, <xref linkend="aspectjlanguage" />, covers the + features of the language in more detail, using code snippets as examples. + The entire language is covered, and after reading this section, you should + be able to use all the features of the language correctly.</para> + + <para>The next section, <xref linkend="examples" />, comprises a set of + complete programs that not only show the features being used, but also try + to illustrate recommended practice. You should read this section after you + are familiar with the elements of AspectJ.</para> + + <para>The back matter contains several appendices that cover AspectJ's + semantics, a quick reference to the language, a glossary of terms and the + index.</para> + +</preface> + +<!-- Local variables: --> +<!-- sgml-local-ecat-files: progguide.ced --> +<!-- sgml-parent-document:("progguide.sgml" "book" "preface") --> +<!-- End: --> + diff --git a/docs/progGuideDB/progguide.html.xsl b/docs/progGuideDB/progguide.html.xsl new file mode 100644 index 000000000..4683e404f --- /dev/null +++ b/docs/progGuideDB/progguide.html.xsl @@ -0,0 +1,9 @@ +<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:import href="../../../aspectj-external-lib/docbook/docbook-xsl/html/chunk.xsl"/>
+
+<xsl:param name="base.dir" select="'html/'"/>
+<xsl:param name="html.ext" select="'.html'"/>
+
+</xsl:stylesheet>
diff --git a/docs/progGuideDB/progguide.xml b/docs/progGuideDB/progguide.xml new file mode 100644 index 000000000..0128b3490 --- /dev/null +++ b/docs/progGuideDB/progguide.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> + +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "../../lib/docbook/docbook-dtd/docbookx.dtd" +[ + +<!ENTITY preface SYSTEM "preface.xml"> +<!ENTITY gettingstarted SYSTEM "gettingstarted.xml"> +<!ENTITY language SYSTEM "language.xml"> +<!ENTITY examples SYSTEM "examples.xml"> +<!ENTITY idioms SYSTEM "idioms.xml"> +<!ENTITY pitfalls SYSTEM "pitfalls.xml"> +<!ENTITY quickreference SYSTEM "quickreference.xml"> +<!ENTITY semantics SYSTEM "semantics.xml"> +<!ENTITY limitations SYSTEM "limitations.xml"> +<!ENTITY glossary SYSTEM "glossary.xml"> +<!ENTITY bibliography SYSTEM "bibliography.xml"> +<!ENTITY index SYSTEM "index.xml"> + +<!ENTITY % early "ignore"> + +]> + +<book> + <bookinfo> + <title>The AspectJ<superscript>TM</superscript> Programming Guide</title> + + <authorgroup> + <author> + <othername>the AspectJ Team</othername> + </author> + </authorgroup> + + <legalnotice> + <para>Copyright (c) 1998-2001 Xerox Corporation, + 2002 Palo Alto Research Center, Incorporated. + All rights reserved. + </para> + </legalnotice> + + <abstract> + <para> + This programming guide describes the AspectJ language. A + companion guide describes the tools which are part of the + AspectJ development environment. + </para> + + <para> + If you are completely new to AspectJ, you should first read + <xref linkend="gettingstarted"/> for a broad overview of programming + in AspectJ. If you are already familiar with AspectJ, but want a deeper + understanding, you should read <xref linkend="aspectjlanguage"/> and + look at the examples in the chapter. If you want a more formal + definition of AspectJ, you should read <xref linkend="semantics"/>. + </para> + </abstract> + </bookinfo> + + &preface; + &gettingstarted; + &language; + &examples; + &idioms; + &pitfalls; + &quickreference; + &semantics; + &limitations; + &glossary; + &bibliography; +<!-- &index; --> + + + +</book> + +<!-- +Local Variables: +compile-command: "java com.icl.saxon.StyleSheet -w0 progguide.xml progguide.html.xsl" +fill-column: 79 +sgml-indent-step: 3 +sgml-local-ecat-files: "progguide.ced" +End: +--> diff --git a/docs/progGuideDB/quickreference.xml b/docs/progGuideDB/quickreference.xml new file mode 100644 index 000000000..2b0c98f14 --- /dev/null +++ b/docs/progGuideDB/quickreference.xml @@ -0,0 +1,658 @@ +<appendix id="quickreference" xreflabel="AspectJ Quick Reference"> + + <title>AspectJ Quick Reference</title> + <indexterm><primary>AspectJ</primary><secondary>semantics</secondary> + <tertiary>quick reference</tertiary> + </indexterm> + + <sect1> + <title>Pointcut Designators</title> + + <table frame="all" id="qrpointcutdesignators"> + <title>Pointcut Designators</title> + + <tgroup cols="2" align="left"> + <colspec colname="c1"/> + <colspec colname="c2"/> + <spanspec spanname="hspan" namest="c1" nameend="c2" align="left"/> + + <tbody valign="middle"> + + <row> + <entry spanname="hspan"> + <emphasis role="bold">Methods and Constructors</emphasis> + </entry> + </row> + + <row> + <entry> + <literal>call(<replaceable>Signature</replaceable>)</literal> + </entry> + <entry> + Method or constructor call join points when the signature + matches <replaceable>Signature</replaceable> + </entry> + </row> + + <row> + <entry> + <literal>execution(<replaceable>Signature</replaceable>)</literal> + </entry> + <entry> + Method or constructor execution join points when the + signature matches + <replaceable>Signature</replaceable> + </entry> + </row> + + <row> + <entry> + <literal>initialization(<replaceable>Signature</replaceable>)</literal> + </entry> + <entry> + Object initialization join point when the first + constructor called in the type matches + <replaceable>Signature</replaceable> + </entry> + </row> + + <row> + <entry spanname="hspan"> + <emphasis role="bold">Exception Handlers</emphasis> + </entry> + </row> + + <row rowsep="1"> + <entry> + <literal>handler(<replaceable>TypePattern</replaceable>)</literal> + </entry> + <entry> + Exception handler execution join points when + try handlers for the throwable types in + <replaceable>TypePattern</replaceable> are executed. + The exception object can be accessed with an + <literal>args</literal> pointcut. + </entry> + </row> + + <row> + <entry spanname="hspan"> + <emphasis role="bold">Fields</emphasis> + </entry> + </row> + + <row> + <entry> + <literal>get(<replaceable>Signature</replaceable>)</literal> + </entry> + <entry> + Field reference join points when the field matches + <replaceable>Signature</replaceable> + </entry> + </row> + + <row> + <entry> + <literal>set(<replaceable>Signature</replaceable>)</literal> + </entry> + <entry> + Field assignment join points when the field matches + <replaceable>Signature</replaceable>. The new value + can be accessed with an <literal>args</literal> + pointcut. + </entry> + </row> + + <row> + <entry spanname="hspan"> + <emphasis role="bold">Static Initializers</emphasis> + </entry> + </row> + + <row rowsep="1"> + <entry> + <literal>staticinitialization(<replaceable>TypePattern</replaceable>)</literal> + </entry> + <entry> + Static initializer execution join points for the types in + <replaceable>TypePattern</replaceable>. + </entry> + </row> + + <row> + <entry spanname="hspan"> + <emphasis role="bold">Objects</emphasis> + </entry> + </row> + + <row> + <entry> + <literal>this(<replaceable>TypePattern</replaceable>)</literal> + </entry> + <entry> + Join points when the currently executing object is an + instance of a type in <replaceable>TypePattern</replaceable> + </entry> + </row> + + <row> + <entry> + <literal>target(<replaceable>TypePattern</replaceable>)</literal> + </entry> + <entry> + Join points when the target object is an instance + of a type in <replaceable>TypePattern</replaceable> + </entry> + </row> + + <row> + <entry> + <literal>args(<replaceable>TypePattern</replaceable>, ...)</literal> + </entry> + <entry> + Join points when the argument objects are instances of + the <replaceable>TypePattern</replaceable>s + </entry> + </row> + +<!-- + <row rowsep="1"> + <entry> + <literal>hasaspect(<replaceable>TypePattern</replaceable>)</literal> + </entry> + <entry> + Join points where an aspect instance of a type in + <replaceable>TypePattern</replaceable> is associated + with the join point + </entry> + </row> +--> + <row> + <entry spanname="hspan"> + <emphasis role="bold">Lexical Extents</emphasis> + </entry> + </row> + + <row> + <entry> + <literal>within(<replaceable>TypePattern</replaceable>)</literal> + </entry> + <entry> + Join points when the code executing is defined in the + types in <replaceable>TypePattern</replaceable> + </entry> + </row> + + <row> + <entry> + <literal>withincode(<replaceable>Signature</replaceable>)</literal> + </entry> + <entry> + Join points when the code executing is defined in the + method or constructor with signature + <replaceable>Signature</replaceable> + </entry> + </row> + + <row> + <entry spanname="hspan"> + <emphasis role="bold">Control Flow</emphasis> + </entry> + </row> + + <row> + <entry> + <literal>cflow(<replaceable>Pointcut</replaceable>)</literal> + </entry> + <entry> + Join points in the control flow of the join points + specified by <replaceable>Pointcut</replaceable> + </entry> + </row> + + <row> + <entry> + <literal>cflowbelow(<replaceable>Pointcut</replaceable>)</literal> + </entry> + <entry> + Join points in the control flow below the join points + specified by <replaceable>Pointcut</replaceable> + </entry> + </row> + + <row> + <entry spanname="hspan"> + <emphasis role="bold">Conditional</emphasis> + </entry> + </row> + + <row> + <entry> + <literal>if(<replaceable>Expression</replaceable>)</literal> + </entry> + <entry> + Join points when the boolean + <replaceable>Expression</replaceable> evaluates + to <literal>true</literal> + </entry> + </row> + + <row> + <entry spanname="hspan"> + <emphasis role="bold">Combination</emphasis> + </entry> + </row> + + <row> + <entry> + <literal>! <replaceable>Pointcut</replaceable></literal> + </entry> + <entry> + Join points that are not picked out by + <replaceable>Pointcut</replaceable> + </entry> + </row> + + <row> + <entry> + <literal><replaceable>Pointcut0</replaceable> <![CDATA[&&]]> <replaceable>Pointcut1</replaceable></literal> + </entry> + <entry> + Join points that are picked out by both + <replaceable>Pointcut0</replaceable> and + <replaceable>Pointcut1</replaceable> + </entry> + </row> + + <row> + <entry> + <literal><replaceable>Pointcut0</replaceable> || <replaceable>Pointcut1</replaceable></literal> + </entry> + <entry> + Join points that are picked out by either + <replaceable>Pointcut0</replaceable> or + <replaceable>Pointcut1</replaceable> + </entry> + </row> + + <row> + <entry> + <literal>( <replaceable>Pointcut</replaceable> )</literal> + </entry> + <entry> + Join points that are picked out by the parenthesized + <replaceable>Pointcut</replaceable> + </entry> + </row> + + </tbody> + </tgroup> + + </table> + + </sect1> + + <sect1> + <title>Type Patterns</title> + <para> + </para> + + <table frame="all" id="qrtypenamepatterns"> + <title>Type Name Patterns</title> + <tgroup cols="2" colsep="1" rowsep="0"> + <tbody> + <row> + <entry><literal>*</literal> alone</entry> + <entry>all types</entry> + </row> + <row> + <entry><literal>*</literal> in an identifier</entry> + <entry>any sequence of characters, not including "."</entry> + </row> + <row> + <entry><literal>..</literal> in an identifier</entry> + <entry>any sequence of characters starting and ending + with "."</entry> + </row> + </tbody> + </tgroup> + </table> + + <para> + The + wildcard can be appended to a type name pattern to + indicate all subtypes. + </para> + + <para> + Any number of []s can be put on a type name or subtype pattern + to indicate array types. + </para> + + <table frame="all" id="qrtypepatterns"> + <title>Type Patterns</title> + <tgroup cols="2" colsep="1" rowsep="0"> + <tbody> + <row> + <entry><replaceable>TypeNamePattern</replaceable></entry> + <entry>all types in <replaceable>TypeNamePattern</replaceable></entry> + </row> + <row> + <entry><replaceable>SubtypePattern</replaceable></entry> + <entry>all types in <replaceable>SubtypePattern</replaceable>, a + pattern with a +. </entry> + </row> + <row> + <entry><replaceable>ArrayTypePattern</replaceable></entry> + <entry>all types in <replaceable>ArrayTypePattern</replaceable>, + a pattern with one or more []s. </entry> + </row> + <row> + <entry><literal>!<replaceable>TypePattern</replaceable></literal></entry> + <entry>all types not in <replaceable>TypePattern</replaceable></entry> + </row> + <row> + <entry><literal><replaceable>TypePattern0</replaceable> + <![CDATA[&&]]> <replaceable>TypePattern1</replaceable></literal></entry> + <entry>all types in both + <replaceable>TypePattern0</replaceable> and <replaceable>TypePattern1</replaceable></entry> + </row> + <row> + <entry><literal><replaceable>TypePattern0</replaceable> || <replaceable>TypePattern1</replaceable></literal></entry> + <entry>all types in either + <replaceable>TypePattern0</replaceable> or <replaceable>TypePattern1</replaceable></entry> + </row> + <row> + <entry><literal>( <replaceable>TypePattern</replaceable> )</literal></entry> + <entry>all types in <replaceable>TypePattern</replaceable></entry> + </row> + </tbody> + </tgroup> + </table> + + </sect1> + + <sect1> + <title>Advice</title> + + <para></para> + <table frame="all" id="qradvice"> + <title>Advice</title> + <tgroup cols="2" colsep="1" rowsep="0"> + <tbody> + + <row> + <entry> + <literal>before(<replaceable>Formals</replaceable>) : </literal> + </entry> + <entry> + Run before the join point. + </entry> + </row> + + + <row> + <entry> + <literal>after(<replaceable>Formals</replaceable>) returning + [ (<replaceable>Formal</replaceable>) ] : </literal> + </entry> + <entry> + Run after the join point if it returns normally. The + optional formal gives access to the returned value. + </entry> + </row> + + <row> + <entry> + <literal>after(<replaceable>Formals</replaceable>) throwing [ + (<replaceable>Formal</replaceable>) ] : </literal> + </entry> + <entry> + Run after the join point if it throws an exception. The + optional formal gives access to the + <literal>Throwable</literal> exception value. + </entry> + </row> + + <row> + <entry> + <literal>after(<replaceable>Formals</replaceable>) : </literal> + </entry> + <entry> + Run after the join point both when it returns normally and + when it throws an exception. + </entry> + </row> + + <row> + <entry> + <literal><replaceable>Type</replaceable> + around(<replaceable>Formals</replaceable>) [ throws + <replaceable>TypeList</replaceable> ] :</literal> + </entry> + <entry> + Run instead of the join point. The join point can be + executed by calling <literal>proceed</literal>. + </entry> + </row> + + </tbody> + </tgroup> + </table> + </sect1> + + <sect1> + <title>Static Crosscutting</title> + + <para></para> + + <table frame="all" id="qrintroduction"> + <title>Introduction</title> + + <tgroup cols="2" colsep="1" rowsep="0"> + + <tbody> + + <row> + <entry> + <replaceable>Modifiers Type TypePattern.Id(Formals) { Body }</replaceable> + </entry> + <entry> + Defines a method on the types in <replaceable>TypePattern</replaceable>. + </entry> + </row> + + <row> + <entry> + <literal>abstract <replaceable>Modifiers Type TypePattern.Id(Formals)</replaceable>;</literal> + </entry> + <entry> + Defines an abstract method on the types in <replaceable>TypePattern</replaceable>. + </entry> + </row> + + <row> + <entry> + <literal><replaceable>Modifiers TypePattern</replaceable>.new<replaceable>(Formals) { Body }</replaceable></literal> + </entry> + <entry> + Defines a a constructor on the types in <replaceable>TypePattern</replaceable>. + </entry> + </row> + + <row> + <entry> + <replaceable>Modifiers Type TypePattern.Id [ = Expression ];</replaceable> + </entry> + <entry> + Defines a field on the types in <replaceable>TypePattern</replaceable>. + </entry> + </row> + </tbody> + </tgroup> + </table> + + <table frame="all" id="qrotherdeclarations"> + <title>Other declarations</title> + + <tgroup cols="2" colsep="1" rowsep="0"> + + <tbody> + + <row> + <entry> + <literal>declare parents: <replaceable>TypePattern</replaceable> extends <replaceable>TypeList</replaceable>;</literal> + </entry> + <entry> + Declares that the types in <replaceable>TypePattern</replaceable> extend the types of <replaceable>TypeList</replaceable>. + </entry> + </row> + + <row> + <entry> + <literal>declare parents: <replaceable>TypePattern</replaceable> implements <replaceable>TypeList</replaceable>;</literal> + </entry> + <entry> + Declares that the types in <replaceable>TypePattern</replaceable> implement the types of <replaceable>TypeList</replaceable>. + </entry> + </row> + + <row> + <entry> + <literal>declare warning: <replaceable>Pointcut</replaceable>: <replaceable>String</replaceable>;</literal> + </entry> + <entry> + Declares that if any of the join points in + <replaceable>Pointcut</replaceable> possibly exist in + the program, the compiler should emit a warning of + <replaceable>String</replaceable>. + </entry> + </row> + + <row> + <entry> + <literal>declare error: <replaceable>Pointcut</replaceable>: <replaceable>String</replaceable>;</literal> + </entry> + <entry> + Declares that if any of the join points in + <replaceable>Pointcut</replaceable> possibly exist in + the program, the compiler should emit an error of + <replaceable>String</replaceable>. + </entry> + </row> + + <row> + <entry> + <literal>declare soft: + <replaceable>TypePattern</replaceable>: + <replaceable>Pointcut</replaceable>; </literal> + </entry> + <entry> + Declares that any exception of a type in + <replaceable>TypePattern</replaceable> that gets + thrown at any join point picked out by + <replaceable>Pointcut</replaceable> will be wrapped in + <literal>org.aspectj.lang.SoftException</literal>. + </entry> + </row> + + </tbody> + </tgroup> + </table> + + </sect1> + + <sect1> + <title>Aspect Associations</title> + <para> + </para> + + <table frame="all" id="qrassociations"> + <title>Associations</title> + <tgroup cols="3" align="left" colsep="1" rowsep="1"> + <thead> + <row> + <entry>modifier</entry> + <entry>Description</entry> + <entry>Accessor</entry> + </row> + </thead> + + <tbody> + + <row> + <entry> + [ <literal>issingleton</literal> ] + </entry> + <entry> + One instance of the aspect is made. This is + the default. + </entry> + <entry> + <literal>aspectOf()</literal> at all join points + </entry> + </row> + + <row> + <entry> + <literal>perthis(<replaceable>Pointcut</replaceable>)</literal> + </entry> + <entry> + An instance is associated with each object that is the + currently executing object at any join point in + <replaceable>Pointcut</replaceable>. + </entry> + <entry> + <literal>aspectOf(Object)</literal> at all join points</entry> + </row> + + <row> + <entry> + <literal>pertarget(<replaceable>Pointcut</replaceable>)</literal> + </entry> + <entry> + An instance is associated with each object that is the + target object at any join point in + <replaceable>Pointcut</replaceable>. + </entry> + <entry> + <literal>aspectOf(Object)</literal> at all join points</entry> + </row> + + <row> + <entry> + <literal>percflow(<replaceable>Pointcut</replaceable>)</literal> + </entry> + <entry> + The aspect is defined for each entrance to the control flow of + the join points defined by <replaceable>Pointcut</replaceable>. </entry> + <entry> + <literal>aspectOf()</literal> at join points in + <literal>cflow(<replaceable>Pointcut</replaceable>)</literal> + </entry> + </row> + + <row> + <entry> + <literal>percflowbelow(<replaceable>Pointcut</replaceable>)</literal> + </entry> + <entry> + The aspect is defined for each entrance to the control flow + below the join points defined by <replaceable>Pointcut</replaceable>. + </entry> + <entry> + <literal>aspectOf()</literal> at join points in + <literal>cflowbelow(<replaceable>Pointcut</replaceable>)</literal> + </entry> + </row> + </tbody> + + </tgroup> + </table> + </sect1> +</appendix> + +<!-- Local variables: --> +<!-- fill-column: 79 --> +<!-- sgml-local-ecat-files: progguide.ced --> +<!-- sgml-parent-document:("progguide.sgml" "book" "appendix") --> +<!-- End: --> diff --git a/docs/progGuideDB/semantics.xml b/docs/progGuideDB/semantics.xml new file mode 100644 index 000000000..cf77a23ed --- /dev/null +++ b/docs/progGuideDB/semantics.xml @@ -0,0 +1,2361 @@ +<appendix id="semantics" xreflabel="Semantics"> + + <title>Language Semantics</title> + + <para> + AspectJ extends Java by overlaying a concept of join points onto the + existing Java semantics and by adding adds four kinds of program elements + to Java: + </para> + + <para> + Join points are well-defined points in the execution of a program. These + include method and constructor calls, field accesses and others described + below. + </para> + + <para> + A pointcut picks out join points, and exposes some of the values in the + execution context of those join points. There are several primitive + pointcut designators, new named pointcuts can be defined by the + <literal>pointcut</literal> declaration. + </para> + + <para> + Advice is code that executes at each join point in a pointcut. Advice has + access to the values exposed by the pointcut. Advice is defined by + <literal>before</literal>, <literal>after</literal>, and + <literal>around</literal> declarations. + </para> + + <para> + Introduction and declaration form AspectJ's static crosscutting features, + that is, is code that may change the type structure of a program, by adding + to or extending interfaces and classes with new fields, constructors, or + methods. Introductions are defined through an extension of usual method, + field, and constructor declarations, and other declarations are made with a + new <literal>declare</literal> keyword. + </para> + + <para> + An aspect is a crosscutting type, that encapsulates pointcuts, advice, and + static crosscutting features. By type, we mean Java's notion: a modular + unit of code, with a well-defined interface, about which it is possible to + do reasoning at compile time. Aspects are defined by the + <literal>aspect</literal> declaration. + </para> + + <sect1> + <title>Join Points</title> + + <para> + While aspects do define crosscutting types, the AspectJ system does not + allow completely arbitrary crosscutting. Rather, aspects define types that + cut across principled points in a program's execution. These principled + points are called join points. + </para> + + + <para> + A join point is a well-defined point in the execution of a program. The + join points defined by AspectJ are: + </para> + + <glosslist> + + <glossentry> + <glossterm>Method call</glossterm> + <glossdef> + <para> + When a method is called, not including super calls of non-static + methods. + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>Method execution</glossterm> + <glossdef> + <para> + When the body of code for an actual method executes. + </para> + </glossdef> + </glossentry> + + + <glossentry> + <glossterm>Constructor call</glossterm> + <glossdef> + <para> + When an object is built and a constructor is called, not including + this or super constructor calls. The object being constructed is + returned at a constructor call join point, so it may be accessed + with <literal>after returning</literal> advice. + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>Initializer execution</glossterm> + <glossdef> + <para> + When the non-static initializers of a class run. + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>Constructor execution</glossterm> + <glossdef> + <para> + When the body of code for an actual constructor executes, after its + this or super constructor call. The object being constructed is + the currently executing object, and so may be accessed with the + <literal>this</literal> pointcut. No value is returned from + constructor execution join points. + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>Static initializer execution</glossterm> + <glossdef> + <para> + When the static initializer for a class executes. + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>Object pre-initialization</glossterm> + <glossdef> + <para> + Before the object initialization code for a particular class runs. + This encompasses the time between the start of its first called + constructor and the start of its parent's constructor. Thus, the + execution of these join points encompass the join points from the + code found in <literal>this()</literal> and + <literal>super()</literal> constructor calls. + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>Object initialization</glossterm> + <glossdef> + <para> + When the object initialization code for a particular class runs. + This encompasses the time between the return of its parent's + constructor and the return of its first called constructor. It + includes all the dynamic initializers and constructors used to + create the object. The object being constructed is + the currently executing object, and so may be accessed with the + <literal>this</literal> pointcut. No value is returned from + constructor execution join points. + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>Field reference</glossterm> + <glossdef> + <para> + When a non-final field is referenced. + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>Field assignment</glossterm> + <glossdef> + <para> + When a field is assigned to. + </para> + </glossdef> + </glossentry> + + <glossentry> + <glossterm>Handler execution</glossterm> + <glossdef> + <para> + When an exception handler executes. + </para> + </glossdef> + </glossentry> + </glosslist> + + + + </sect1> + + <sect1> + <title>Pointcuts</title> + + <para> + A pointcut is a program element that picks out join points, as well as + data from the execution context of the join points. Pointcuts are used + primarily by advice. They can be composed with boolean operators to + build up other pointcuts. So a pointcut is defined by one of + </para> + + <variablelist> + <varlistentry> + <term><literal>call(<replaceable>Signature</replaceable>)</literal></term> + <listitem> + <para>Picks out a method or constructor call join point based on the + static signature at the caller side. </para> + </listitem> + </varlistentry> + <varlistentry> + <term><literal>execution(<replaceable>Signature</replaceable>)</literal></term> + <listitem> + <para>Picks out a method or constructor execution join point based on + the static signature at the callee side. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>get(<replaceable>Signature</replaceable>)</literal></term> + <listitem> + <para>Picks out a field get join point based on the static + signature. Note that references to constant fields (static final + fields bound to a constant string object or primitive value) are not + get join points, since Java requires them to be inlined. </para> + </listitem> + </varlistentry> + <varlistentry> + <term><literal>set(<replaceable>Signature</replaceable>)</literal></term> + <listitem> + <para>Picks out a field set join point based on the static + signature. Note that the initializations of constant fields (static + final fields where the initializer is a constant string object or + primitive value) are not set join points, since Java requires their + references to be inlined.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>handler(<replaceable>TypePattern</replaceable>)</literal></term> + <listitem> + <para>Picks out an exception handler of any of the Throwable types + of the type pattern. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>initialization(<replaceable>Signature</replaceable>)</literal></term> + <listitem> + <para>Picks out an object initialization join point based on the + static signature of the starting constructor. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>staticinitialization(<replaceable>TypePattern</replaceable>)</literal></term> + <listitem> + <para>Picks out a static initializer execution join point of any of the types + of the type pattern. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>within(<replaceable>TypePattern</replaceable>)</literal></term> + <listitem> + <para>Picks out all join points where the executing code is defined + in any of the classes of the type pattern. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>withincode(<replaceable>Signature</replaceable>)</literal></term> + <listitem> + <para>Picks out all join points where the executing code is defined + in the method or constructor of the appropriate signature. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>cflow(<replaceable>Pointcut</replaceable>)</literal></term> + <listitem> + <para>Picks out all join points in the control flow of the join + points picked out by the pointcut, including pointcut's join points + themselves. </para> + </listitem> + </varlistentry> + <varlistentry> + <term><literal>cflowbelow(<replaceable>Pointcut</replaceable>)</literal></term> + <listitem> + <para>Picks out all join points in the control flow below the join + points picked out by the pointcut. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>this(<replaceable>TypePattern</replaceable> or <replaceable>Id</replaceable>)</literal></term> + <listitem> + <para>Picks out all join points where the currently executing object + (the object bound to <literal>this</literal>) is an instance of a + type of the type pattern, or of the type of the identifier. + Will not match any join points from static methods. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>target(<replaceable>TypePattern</replaceable> or <replaceable>Id</replaceable>)</literal></term> + <listitem> + <para>Picks out all join points where the target object (the object + on which a call or field operation is applied to) is an instance of a + type of the type pattern, or of the type of the + identifier. Will not match any calls, gets, or sets to static + members. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>args(<replaceable>TypePattern</replaceable> or <replaceable>Id</replaceable>, ...)</literal></term> + <listitem> + <para>Picks out all join points where the arguments are instances of + a type of the appropriate type pattern or identifier. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal><replaceable>PointcutId</replaceable>(<replaceable>TypePattern</replaceable> or <replaceable>Id</replaceable>, ...)</literal></term> + <listitem> + <para>Picks out all join points that are picked out by the + user-defined pointcut designator named by + <replaceable>PointcutId</replaceable>. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>if(<replaceable>BooleanExpression</replaceable>)</literal></term> + <listitem> + <para>Picks out all join points where the boolean expression + evaluates to <literal>true</literal>. The boolean expression used + can only access static members, variables exposed by teh enclosing + pointcut or advice, and <literal>thisJoinPoint</literal> forms. In + particular, it cannot call non-static methods on the aspect. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>! <replaceable>Pointcut</replaceable></literal></term> + <listitem> + <para>Picks out all join points that are not picked out by the + pointcut. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal><replaceable>Pointcut0</replaceable> <![CDATA[&&]]> <replaceable>Pointcut1</replaceable></literal></term> + <listitem> + <para>Picks out all join points that are picked out by both of the + pointcuts. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal><replaceable>Pointcut0</replaceable> || <replaceable>Pointcut1</replaceable></literal></term> + <listitem> + <para>Picks out all join points that are picked out by either of the + pointcuts. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>( <replaceable>Pointcut</replaceable> )</literal></term> + <listitem> + <para>Picks out all join points that are picked out by the + parenthesized pointcut. </para> + </listitem> + </varlistentry> + </variablelist> + + <sect2> + <title>Pointcut naming + </title> + + <para> + A named pointcut is defined with the <literal>pointcut</literal> + declaration. + </para> + + +<programlisting> +pointcut publicIntCall(int i): + call(public * *(int)) <![CDATA[&&]]> args(i); +</programlisting> + + <para> + A named pointcut may be defined in either a class or aspect, and is + treated as a member of the class or aspect where it is found. As a + member, it may have an access modifier such as + <literal>public</literal> or <literal>private</literal>. + </para> + +<programlisting> +class C { + pointcut publicCall(int i): + call(public * *(int)) <![CDATA[&&]]> args(i); +} + +class D { + pointcut myPublicCall(int i): + C.publicCall(i) <![CDATA[&&]]> within(SomeType); +} +</programlisting> + + <para> + Pointcuts that are not final may be declared abstract, and defined + without a body. Abstract pointcuts may only be declared within + abstract aspects. + </para> + +<programlisting> +abstract aspect A { + abstract pointcut publicCall(int i); +} +</programlisting> + + <para> + In such a case, an extending aspect may override the abstract + pointcut. + </para> + +<programlisting> +aspect B extends A { + pointcut publicCall(int i): call(public Foo.m(int)) <![CDATA[&&]]> args(i); +} +</programlisting> + + <para>For completeness, a pointcut with a declaration may be declared + <literal>final</literal>. </para> + + <para> + Though named pointcut declarations appear somewhat like method + declarations, and can be overridden in subaspects, they cannot be + overloaded. It is an error for two pointcuts to be named with the same + name in the same class or aspect declaration. + </para> + + <para> + The scope of a named pointcut is the enclosing class declaration. This + is different than the scope of other members; the scope of other + members is the enclosing class <emphasis>body</emphasis>. This means + that the following code is legal: + </para> + +<programlisting> +aspect B percflow(publicCall()) { + pointcut publicCall(): call(public Foo.m(int)); +} +</programlisting> + + </sect2> + + <sect2> + <title>Context exposure</title> + + <para> + Pointcuts have an interface; they expose some parts of the execution + context of the join points they pick out. For example, the PublicIntCall + above exposes the first argument from the receptions of all public + unary integer methods. This context is exposed by providing typed + formal parameters to named pointcuts and advice, like the formal + parameters of a Java method. These formal parameters are bound by name + matching. + </para> + + <para> + On the right-hand side of advice or pointcut declarations, a regular + Java identifier is allowed in certain pointcut designators in place of + a type or collection of types. + There are four primitive pointcut designators where this is allowed: + <literal>this</literal>, <literal>target</literal>, and + <literal>args</literal><!-- and hasaspect -->. In all such + cases, using an identifier rather than a type is as if the type + selected was the type of the formal parameter, so that the pointcut + </para> + +<programlisting> +pointcut intArg(int i): args(i); +</programlisting> + + <para> + picks out join points where an <literal>int</literal> is being passed + as an argument, but furthermore allows advice access to that argument. + </para> + + <para> + Values can be exposed from named pointcuts as well, so + </para> + +<programlisting> +pointcut publicCall(int x): call(public *.*(int)) <![CDATA[&&]]> intArg(x); +pointcut intArg(int i): args(i); +</programlisting> + + <para> + is a legal way to pick out all calls to public methods accepting an int + argument, and exposing that argument. + </para> + + <para> + There is one special case for this kind of exposure. Exposing an + argument of type Object will also match primitive typed arguments, and + expose a "boxed" version of the primitive. So, + </para> + +<programlisting> +pointcut publicCall(): call(public *.*(..)) <![CDATA[&&]]> args(Object); +</programlisting> + + <para> + will pick out all unary methods that take, as their only argument, + subtypes of Object (i.e., not primitive types like + <literal>int</literal>), but + </para> + +<programlisting> +pointcut publicCall(Object o): call(public *.*(..)) <![CDATA[&&]]> args(o); +</programlisting> + + <para> + will pick out all unary methods that take any argument: And if the + argument was an <literal>int</literal>, then the value passed to advice + will be of type <literal>java.lang.Integer</literal>. + </para> + </sect2> + + <sect2> + <title>Primitive pointcuts</title> + + <bridgehead>Method-related pointcuts</bridgehead> + + <para>AspectJ provides two primitive pointcut designators designed to + capture method call and execution join points. </para> + + <simplelist> + <member><literal>call(<replaceable>Signature</replaceable>)</literal></member> + <member><literal>execution(<replaceable>Signature</replaceable>)</literal></member> + </simplelist> + + <para>These two pointcuts also pick out constructor call end execution + join points. </para> + + <bridgehead>Field-related pointcuts</bridgehead> + + <para> + AspectJ provides two primitive pointcut designators designed to + capture field reference and assignment join points: + </para> + + <simplelist> + <member><literal>get(<replaceable>Signature</replaceable>)</literal></member> + <member><literal>set(<replaceable>Signature</replaceable>)</literal></member> + </simplelist> + + <para> + All set join points are treated as having one argument, the value the + field is being set to, so at a set join point, that value can be + accessed with an <literal>args</literal> pointcut. So an aspect + guarding an integer variable x declared in type T might be written as + </para> + +<programlisting><![CDATA[ +aspect GuardedX { + static final int MAX_CHANGE = 100; + before(int newval): set(int T.x) && args(newval) { + if (Math.abs(newval - T.x) > MAX_CHANGE) + throw new RuntimeException(); + } +}]]></programlisting> + + <bridgehead>Object creation-related pointcuts</bridgehead> + + <para> + AspectJ provides three primitive pointcut designators designed to + capture the initializer execution join points of objects. + </para> + + <simplelist> + <member><literal>call(<replaceable>Signature</replaceable>)</literal></member> + <member><literal>initialization(<replaceable>Signature</replaceable>)</literal></member> + <member><literal>execution(<replaceable>Signature</replaceable>)</literal></member> + </simplelist> + + <bridgehead>Class initialization-related pointcuts</bridgehead> + + <para> + AspectJ provides one primitive pointcut designator to pick out + static initializer execution join points. + </para> + + <simplelist> + <member><literal>staticinitialization(<replaceable>TypePattern</replaceable>)</literal></member> + </simplelist> + + <bridgehead>Exception handler execution-related pointcuts</bridgehead> + + <para> + AspectJ provides one primitive pointcut designator to capture + execution of exception handlers: + </para> + + <simplelist> + <member><literal>handler(<replaceable>TypePattern</replaceable>)</literal></member> + </simplelist> + + <para> + All handler join points are treated as having one argument, the value + of the exception being handled, so at a handler join point, that + value can be accessed with an <literal>args</literal> pointcut. So + an aspect used to put FooException objects into some normal form + before they are handled could be written as + </para> + +<programlisting> +aspect NormalizeFooException { + before(FooException e): handler(FooException) <![CDATA[&&]]> args(e) { + e.normalize(); + } +} +</programlisting> + + <bridgehead>State-based pointcuts</bridgehead> + + <para> + Many concerns cut across the dynamic times when an object of a + particular type is executing, being operated on, or being passed + around. AspectJ provides primitive pointcuts that capture join + points at these times. These pointcuts use the dynamic types of + their objects to discriminate, or pick out, join points. They may + also be used to expose to advice the objects used for + discrimination. + </para> + + <simplelist> + <member><literal>this(<replaceable>TypePattern</replaceable> or <replaceable>Id</replaceable>)</literal></member> + <member><literal>target(<replaceable>TypePattern</replaceable> or <replaceable>Id</replaceable>)</literal></member> +<!-- <member><literal>hasaspect(<replaceable>TypePattern</replaceable> or <replaceable>Id</replaceable>)</literal></member> --> + </simplelist> + + <para> + The this pointcut picks out all join points where the currently + executing object (the object bound to <literal>this</literal>) is an + instance of a particular type. The target pointcut picks out all + join points where the target object (the object on which a method is + called or a field is accessed) is an instance of a particular type. +<!-- The hasaspect pointcut picks out all join points where there is an + associated aspect instance of a particular type. --> + </para> + + <simplelist> + <member><literal>args(<replaceable>TypePattern</replaceable> or <replaceable>Id</replaceable> or "..", ...)</literal></member> + </simplelist> + + <para> + The args pointcut picks out all join points where the arguments are + instances of some types. Each element in the comma-separated list is + one of three things. If it is a type pattern, then the argument + in that position must be an instance of a type of the type name. If + it is an identifier, then the argument in that position must be an + instance of the type of the identifier (or of any type if the + identifier is typed to Object). If it is the special wildcard "..", + then any number of arguments will match, just like in signatures. So + the pointcut + </para> + +<programlisting> +args(int, .., String) +</programlisting> + + <para> + will pick out all join points where the first argument is an + <literal>int</literal> and the last is a <literal>String</literal>. + </para> + + + <bridgehead>Control flow-based pointcuts</bridgehead> + + <para> + Some concerns cut across the control flow of the program. The cflow + and cflowbelow primitive pointcut designators capture join points + based on control flow. + </para> + + <simplelist> + <member><literal>cflow(<replaceable>Pointcut</replaceable>)</literal></member> + <member><literal>cflowbelow(<replaceable>Pointcut</replaceable>)</literal></member> + </simplelist> + + <para> + The cflow pointcut picks out all join points that occur between the start and the + end of each of the pointcut's join points. + </para> + + <para> + The cflowbelow pointcut picks out all join points that occur between + the start and the end of each of the pointcut's join points, but + not including the initial join point of the control flow itself. + </para> + + <bridgehead>Program text-based pointcuts</bridgehead> + + <para> + While many concerns cut across the runtime structure of the program, + some must deal with the actual lexical structure. AspectJ allows + aspects to pick out join points based on where their associated code + is defined. + </para> + + <simplelist> + <member><literal>within(<replaceable>TypePattern</replaceable>)</literal></member> + <member><literal>withincode(<replaceable>Signature</replaceable>)</literal></member> + </simplelist> + + <para> + The within pointcut picks out all join points where the code + executing is defined in the declaration of one of the types in + <replaceable>TypePattern</replaceable>. This includes the class + initialization, object initialization, and method and constructor + execution join points for the type, as well as any join points + associated with the statements and expressions of the type. It also + includes any join points that are associated with code within any of + the type's nested types. + </para> + + <para> + The withincode pointcut picks out all join points where the code + executing is defined in the declaration of a particular method or + constructor. This includes the method or constructor execution join + point as well as any join points associated with the statements and + expressions of the method or constructor. It also includes any join + points that are associated with code within any of the method or + constructor's local or anonymous types. + </para> + + <bridgehead>Dynamic property-based pointcuts</bridgehead> + + <simplelist> + <member><literal>if(<replaceable>BooleanExpression</replaceable>)</literal></member> + </simplelist> + + <para> + The if pointcut picks out join points based on a dynamic property. + It's syntax takes an expression, which must evaluate to a boolean + true or false. Within this expression, the + <literal>thisJoinPoint</literal> object is available. So one + (extremely inefficient) way of picking out all call join points would + be to use the pointcut + </para> + +<programlisting> +if(thisJoinPoint.getKind().equals("call")) +</programlisting> + + </sect2> + + <sect2> + <title>Signatures</title> + + <para> + One very important property of a join point is its signature, which is + used by many of AspectJ's pointcut designators to select particular + join points. + </para> + + <para> + At a method call join point, the signature is composed of the type used + to access the method, the name of the method, and the the types of the called + method's formal parameters and return value (if any). + </para> + + <para> + At a method execution join point, the signature is composed of the type + defining the method, the name of the method, and the the types of the executing + method's formal parameters and return value (if any). + </para> + + + <para> + At a constructor call join point, the signature is composed of the type + of the object to be constructed and the types of the + called constructor's formal parameters. + </para> + + <para> + At a constructor execution join point, the signature is composed of the + type defining the constructor and the types of the executing + constructor's formal parameters. + </para> + + <para> + At an object initialization join point, the signature is composed of + the type being initialized and the types of the formal parameters of + the first constructor entered during the initialization of this type. + </para> + + <para> + At an object pre-initialization join point, the signature is composed + of the type being initialized and the types of the formal parameters of + the first constructor entered during the initialization of this type. + </para> + + <para> + At a field reference or assignment join point, the signature is + composed of the type used to access or assign to the field, the name of + the field, and the type of the field. + </para> + + <para> + At a handler execution join point, the signature is composed of the + exception type that the handler handles. + </para> + + <para> + The <literal>withincode</literal>, <literal>call</literal>, + <literal>execution</literal>, <literal>get</literal>, and + <literal>set</literal> primitive pointcut designators all use signature + patterns to determine the join points they describe. A signature + pattern is an abstract description of one or more join-point + signatures. Signature patterns are intended to match very closely the + same kind of things one would write when defining individual methods + and constructors. + </para> + + <para> + Method definitions in Java include method names, method parameters, + return types, modifiers like static or private, and throws clauses, + while constructor definitions omit the return type and replace the + method name with the class name. The start of a particular method + definition, in class <literal>Test</literal>, for example, might be + </para> + + +<programlisting> +class C { + public final void foo() throws ArrayOutOfBoundsException { ... } +} +</programlisting> + + <para> + In AspectJ, method signature patterns have all these, but most elements + can be replaced by wildcards. So + </para> + + +<programlisting> +call(public final void C.foo() throws ArrayOutOfBoundsException) +</programlisting> + + <para> + picks out call join points to that method, and the pointcut + </para> + +<programlisting> +call(public final void *.*() throws ArrayOutOfBoundsException) +</programlisting> + + + <para> + picks out all call join points to methods, regardless of their name + name or which class they are defined on, so long as they take no + arguments, return no value, are both <literal>public</literal> and + <literal>final</literal>, and are declared to throw + <literal>ArrayOutOfBounds</literal> exceptions. + </para> + + <para> + The defining type name, if not present, defaults to *, so another way + of writing that pointcut would be + </para> + +<programlisting> +call(public final void *() throws ArrayOutOfBoundsException) +</programlisting> + + <para> + Formal parameter lists can use the wildcard <literal>..</literal> to + indicate zero or more arguments, so + </para> + +<programlisting> +execution(void m(..)) +</programlisting> + + <para> + picks out execution join points for void methods named + <literal>m</literal>, of any number of arguments, while + </para> + +<programlisting> +execution(void m(.., int)) +</programlisting> + + + <para> + picks out execution join points for void methods named + <literal>m</literal> whose last parameter is of type + <literal>int</literal>. + </para> + + <para> + The modifiers also form part of the signature pattern. If an AspectJ + signature pattern should match methods without a particular modifier, + such as all non-public methods, the appropriate modifier should be + negated with the <literal>!</literal> operator. So, + </para> + +<programlisting> +withincode(!public void foo()) +</programlisting> + + <para> + picks out all join points associated with code in null non-public + void methods named <literal>foo</literal>, while + </para> + +<programlisting> +withincode(void foo()) +</programlisting> + + <para> + picks out all join points associated with code in null void methods + named <literal>foo</literal>, regardless of access modifier. + </para> + + <para> + Method names may contain the * wildcard, indicating any number of + characters in the method name. So + </para> + +<programlisting> +call(int *()) +</programlisting> + + <para> + picks out all call join points to <literal>int</literal> methods + regardless of name, but + </para> + +<programlisting> +call(int get*()) +</programlisting> + + <para> + picks out all call join points to <literal>int</literal> methods + where the method name starts with the characters "get". + </para> + + <para> + AspectJ uses the <literal>new</literal> keyword for constructor + signature patterns rather than using a particular class name. So the + execution join points of private null constructor of a class C + defined to throw an ArithmeticException can be picked out with + </para> + +<programlisting> +execution(private C.new() throws ArithmeticException) +</programlisting> + </sect2> + + <sect2> + <title>Type patterns</title> + + <para> + Type patterns are a way to pick out collections of types and use them + in places where you would otherwise use only one type. The rules for + using type patterns are simple. + </para> + + <bridgehead>Type name patterns</bridgehead> + + <para> + First, all type names are also type patterns. So + <literal>Object</literal>, <literal>java.util.HashMap</literal>, + <literal>Map.Entry</literal>, <literal>int</literal> are all type + patterns. + </para> + + <para> + There is a special type name, *, which is also a type pattern. * picks out all + types, including primitive types. So + </para> + +<programlisting> +call(void foo(*)) +</programlisting> + + <para> + picks out all call join points to void methods named foo, taking one + argument of any type. + </para> + + <para> + Type names that contain the two wildcards "*" and + "<literal>..</literal>" are also type patterns. The * wildcard matches + zero or more characters characters except for ".", so it can be used + when types have a certain naming convention. So + </para> + +<programlisting> +handler(java.util.*Map) +</programlisting> + + <para> + picks out the types java.util.Map and java.util.java.util.HashMap, + among others, and + </para> + +<programlisting> +handler(java.util.*) +</programlisting> + + <para> + picks out all types that start with "<literal>java.util.</literal>" and + don't have any more "."s, that is, the types in the + <literal>java.util</literal> package, but not inner types + (such as java.util.Map.Entry). + </para> + + <para> + The "<literal>..</literal>" wildcard matches any sequence of + characters that start and end with a ".", so it can be used + to pick out all types in any subpackage, or all inner types. So + </para> + +<programlisting> +target(com.xerox..*) +</programlisting> + + <para> + picks out all join points where the target object is an instance of + defined in any type beginning with "<literal>com.xerox.</literal>". + </para> + + <bridgehead>Subtype patterns</bridgehead> + + <para> + It is possible to pick out all subtypes of a type (or a collection of + types) with the "+" wildcard. The "+" wildcard follows immediately a + type name pattern. So, while + </para> + +<programlisting> +call(Foo.new()) +</programlisting> + + <para> + picks out all constructor call join points where an instance of exactly + type Foo is constructed, + </para> + +<programlisting> +call(Foo+.new()) +</programlisting> + + <para> + picks out all constructor call join points where an instance of any + subtype of Foo (including Foo itself) is constructed, and the unlikely + </para> + +<programlisting> +call(*Handler+.new()) +</programlisting> + + <para> + picks out all constructor call join points where an instance of any + subtype of any type whose name ends in "Handler" is constructed. + </para> + + <bridgehead>Array type patterns</bridgehead> + + <para> + A type name pattern or subtype pattern can be followed by one or more + sets of square brackets to make array type patterns. So + <literal>Object[]</literal> is an array type pattern, and so is + <literal>com.xerox..*[][]</literal>, and so is + <literal>Object+[]</literal>. + </para> + + <bridgehead>Type patterns</bridgehead> + + <para> + Type patterns are built up out of type name patterns, subtype patterns, + and array type patterns, and constructed with boolean operators + <literal><![CDATA[&&]]></literal>, <literal>||</literal>, and + <literal>!</literal>. So + </para> + +<programlisting> +staticinitialization(Foo || Bar) +</programlisting> + + <para> + picks out the static initializer execution join points of either Foo or Bar, + and + </para> + +<programlisting> +call((Foo+ <![CDATA[&&]]> ! Foo).new(..)) +</programlisting> + + <para> + picks out the constructor call join points when a subtype of Foo, but + not Foo itself, is constructed. + </para> + </sect2> + +<!-- ============================== --> + + <sect2> + <title>Pointcuts and Join Points</title> + + <para>It is possible to pick out every different kind of join point with + pointcuts, but some of the less common ones require pointcut + combination. </para> + + <sect3> + <title>Method call </title> <!-- add chain up --> + +<programlisting> +aspect A { + after() returning: call(void foo()) { + System.err.println(thisJoinPoint.getKind()); // should be "method-call" + } +} +</programlisting> + </sect3> + + <sect3> + <title>Method execution</title> + +<programlisting> +aspect A { + after() returning: execution(void foo()) { + System.err.println(thisJoinPoint.getKind()); // should be "method-execution" + } +} +</programlisting> + </sect3> + + <sect3> + <title>Constructor call</title> <!-- add chain up --> + +<programlisting> +aspect A { + after() returning: call(Foo.new()) { + System.err.println(thisJoinPoint.getKind()); // should be "constructor-call" + } +} +</programlisting> + </sect3> + + <sect3> + <title>Constructor execution<!-- [add chain up] --></title> + +<programlisting> +aspect A { + after() returning: execution(Foo.new()) { + System.err.println(thisJoinPoint.getKind()); // should be "constructor-execution" + } +} +</programlisting> + </sect3> + + <sect3> + <title>Static initializer execution<!-- [add chain up] --></title> + +<programlisting> +aspect A { + after() returning: staticinitializer(Foo) { + System.err.println(thisJoinPoint.getKind()); // should be "static-initializar" + } +} +</programlisting> + </sect3> + + <sect3> + <title>Object pre-initialization<!-- [add chain up] --></title> + + <para>This join point will most commonly be seen as the enclosing + execution join point of a particular call, since it cannot be simply + picked out by AspectJ's primitive pointcuts.</para> + +<programlisting> +aspect A { + after() returning: call(Foo) { + System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "pre-initialization" + } +} +</programlisting> + </sect3> + + <sect3> + <title>Object initialization<!-- [add chain up] --></title> + + +<programlisting> +aspect A { + after() returning: initialization(Foo.new()) { + System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "initialization" + } +} +</programlisting> + </sect3> + + <sect3> + <title>Field Reference <!-- [add chain up] --></title> + + +<programlisting> +aspect A { + after() returning: get(Foo.x) { + System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "field-get" + } +} +</programlisting> + </sect3> + + <sect3> + <title>Field Assignment <!-- [add chain up] --></title> + + +<programlisting> +aspect A { + after() returning: set(Foo.x) { + System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "field-set" + } +} +</programlisting> + </sect3> + + + <sect3> + <title>Handler Execution <!-- [add chain up] --></title> + + +<programlisting> +aspect A { + after() returning: handler(FooExn) { + System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "handler" + } +} +</programlisting> + </sect3> + + </sect2> + </sect1> + + <sect1> + <title>Advice</title> + + <simplelist> + <member><literal>before(<replaceable>Formals</replaceable>): <replaceable>Pointcut</replaceable> { <replaceable>Body</replaceable> }</literal></member> + <member><literal>after(<replaceable>Formals</replaceable>) returning [ (<replaceable>Formal</replaceable>) ]: <replaceable>Pointcut</replaceable> { <replaceable>Body</replaceable> }</literal></member> + <member><literal>after(<replaceable>Formals</replaceable>) throwing [ (<replaceable>Formal</replaceable>) ]: <replaceable>Pointcut</replaceable> { <replaceable>Body</replaceable> }</literal></member> + <member><literal>after(<replaceable>Formals</replaceable>) : <replaceable>Pointcut</replaceable> { <replaceable>Body</replaceable> }</literal></member> + <member><literal><replaceable>Type</replaceable> around(<replaceable>Formals</replaceable>) [ throws <replaceable>TypeList</replaceable> ] : <replaceable>Pointcut</replaceable> { <replaceable>Body</replaceable> }</literal></member> + </simplelist> + + <para> + Advice defines crosscutting behavior. It is defined in terms of + pointcuts. The code of a piece of advice runs at every join point picked + out by its pointcut. Exactly how the code runs depends on the kind of + advice. + </para> + + <para> + AspectJ supports three kinds of advice. The kind of advice determines how + it interacts with the join points it is defined over. Thus AspectJ + divides advice into that which runs before its join points, that which + runs after its join points, and that which runs in place of (or "around") + its join points. + </para> + + <para> + While before advice is relatively unproblematic, there can be three + interpretations of after advice: After the execution of a join point + completes normally, after it throws an exception, or after it does either + one. AspectJ allows after advice for any of these situations. + </para> + +<programlisting> +aspect A { + pointcut publicCall(): call(public Object *(..)); + after() returning (Object o): publicCall() { + System.out.println("Returned normally with " + o); + } + after() throwing (Exception e): publicCall() { + System.out.println("Threw an exception: " + e); + } + after(): publicCall(){ + System.out.println("Returned or threw an Exception"); + } +} +</programlisting> + + <para> + After returning advice may not care about its returned object, in which + case it may be written + </para> + +<programlisting> +after() returning: call(public Object *(..)) { + System.out.println("Returned normally"); +} +</programlisting> + + <para> + It is an error to try to put after returning advice on a join point that + does not return the correct type. For example, + </para> + +<programlisting> +after() returning (byte b): call(int String.length()) { + // this is an error +} +</programlisting> + + <para> + is not allowed. But if no return value is exposed, or the exposed return + value is typed to <literal>Object</literal>, then it may be applied to + any join point. If the exposed value is typed to + <literal>Object</literal>, then the actual return value is converted to + an object type for the body of the advice: <literal>int</literal> values + are represented as <literal>java.lang.Integer</literal> objects, etc, and + no value (from void methods, for example) is represented as + <literal>null</literal>. + </para> + + <para> + Around advice runs in place of the join point it operates over, rather + than before or after it. Because around is allowed to return a value, it + must be declared with a return type, like a method. A piece of around + advice may be declared <literal>void</literal>, in which case it is not + allowed to return a value, and instead whatever value the join point + returned will be returned by the around advice (unless the around advice + throws an exception of its own). + </para> + + <para> + Thus, a simple use of around advice is to make a particular method + constant: + </para> + +<programlisting> +aspect A { + int around(): call(int C.foo()) { + return 3; + } +} +</programlisting> + + <para> + Within the body of around advice, though, the computation of the original + join point can be executed with the special syntax + </para> + +<programlisting> +proceed( ... ) +</programlisting> + + <para> + The proceed form takes as arguments the context exposed by the around's + pointcut, and returns whatever the around is declared to return. So the + following around advice will double the second argument to + <literal>foo</literal> whenever it is called, and then halve its result: + </para> + + +<programlisting> +aspect A { + int around(int i): call(int C.foo(Object, int)) <![CDATA[&&]]> args(i) { + int newi = proceed(i*2) + return newi/2; + } +} +</programlisting> + + <para> + If the return value of around advice is typed to + <literal>Object</literal>, then the result of proceed is converted to an + object representation, even if it is originally a primitive value. And + when the advice returns an Object value, that value is converted back to + whatever representation it was originally. So another way to write the + doubling and halving advice is: + </para> + +<programlisting> +aspect A { + Object around(int i): call(int C.foo(Object, int)) <![CDATA[&&]]> args(i) { + Integer newi = (Integer) proceed(i*2) + return new Integer(newi.intValue() / 2); + } +} +</programlisting> + + <para> + In all kinds of advice, the parameters of the advice behave exactly like + method parameters. In particular, assigning to any parameter affects + only the value of the parameter, not the value that it came from. This + means that + </para> + +<programlisting> +aspect A { + after() returning (int i): call(int C.foo()) { + i = i * 2; + } +} +</programlisting> + + <para> + will <emphasis>not</emphasis> double the returned value of the advice. + Rather, it will double the local parameter. Changing the values of + parameters or return values of join points can be done by using around + advice. + </para> + + <sect2> + <title>Advice modifiers</title> + + <para> + The <literal>strictfp</literal> modifier is the only modifier allowed + on advice, and it has the effect of making all floating-point + expressions within the advice be FP-strict. + </para> + </sect2> + + <sect2> + <title>Advice and checked exceptions</title> + + <para> + An advice declaration must include a <literal>throws</literal> clause + listing the checked exceptions the body may throw. This list of + checked exceptions must be compatible with each target join point + of the advice, or an error is signalled by the compiler. + </para> + + <para> + For example, in the following declarations: + </para> + +<programlisting> +import java.io.FileNotFoundException; + +class C { + int i; + + int getI() { return i; } +} + +aspect A { + before(): get(int C.i) { + throw new FileNotFoundException(); + } + before() throws FileNotFoundException: get(int C.i) { + throw new FileNotFoundException(); + } +} +</programlisting> + + <para> + both pieces of advice are illegal. The first because the body throws + an undeclared checked exception, and the second because field get join + points cannot throw <literal>FileNotFoundException</literal>s. + </para> + + <para> The exceptions that each kind of join point in AspectJ may throw are: + </para> + + <variablelist> + <varlistentry> + <term>method call and execution</term> + <listitem> + <para>the checked exceptions declared by the target method's + <literal>throws</literal> clause.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>constructor call and execution</term> + <listitem> + <para>the checked exceptions declared by the target constructor's + <literal>throws</literal> clause.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>field get and set</term> + <listitem> + <para>no checked exceptions can be thrown from these join points. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>exception handler execution</term> + <listitem> + <para>the exceptions that can be thrown by the target exception handler.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>static initializer execution</term> + <listitem> + <para>no checked exceptions can be thrown from these join points. </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>initializer execution, pre-initialization, and initialization</term> + <listitem> + <para>any exception that is in the throws clause of + <emphasis>all</emphasis> constructors of the initialized class. </para> + </listitem> + </varlistentry> + + </variablelist> + + </sect2> + + + <sect2> + <title>Advice precedence</title> + + <para> + Multiple pieces of advice may apply to the same join point. In such + cases, the resolution order of the advice is based on advice + precedence. + </para> + + <sect3> + <title>Determining precedence</title> + + <para>There are a number of rules that determine whether a particular + piece of advice has precedence over another when they advise the same + join point. </para> + + <para>If the two pieces of advice are defined in different aspects, + then there are three cases: </para> + + <simplelist> + <member>If aspect A is declared such that it <literal>dominates</literal> + aspect B, then all advice defined in A has precedence over all advice + defined in + B. </member> + + <member> + Otherwise, if aspect A is a subaspect of aspect B, then all advice + defined in A has precedence over all advice defined in + B. So, unless otherwise specified with a + <literal>dominates</literal> keyword, advice in a subaspect + dominates advice in a superaspect. + </member> + + <member> + Otherwise, if two pieces of advice are defined in two different + aspects, it is undefined which one has precedence. + </member> + + </simplelist> + + <para>If the two pieces of advice are defined in the same aspect, then + there are two cases: </para> + + <simplelist> + <member>If either are <literal>after</literal> advice, then the one that + appears later in the aspect has precedence over the one that appears + earlier. </member> + + <member>Otherwise, then the one that appears earlier in the aspect + has precedence over the one that appears later. + </member> + + </simplelist> + + <para>These rules can lead to circularity, such as</para> + +<programlisting> +aspect A { + before(): execution(void main(String[] args)) {} + after(): execution(void main(String[] args)) {} + before(): execution(void main(String[] args)) {} +} +</programlisting> + + <para>such circularities will result in errors signalled by the compiler. </para> + + </sect3> + + <sect3> + <title>Effects of precedence</title> + + <para>At a particular join point, advice is ordered by precedence.</para> + + <para>A piece of <literal>around</literal> advice controls whether + advice of lower precedence will run by calling + <literal>proceed</literal>. The call to <literal>proceed</literal> + will run the advice with next precedence, or the computation under the + join point if there is no further advice. </para> + + <para>A piece of <literal>before</literal> advice can prevent advice of + lower precedence from running by throwing an exception. If it returns + normally, however, then the advice of the next precedence, or the + computation under the join pint if there is no further advice, will run. + </para> + + <para>Running <literal>after returning</literal> advice will run the + advice of next precedence, or the computation under the join point if + there is no further advice. Then, if that computation returned + normally, the body of the advice will run. </para> + + <para>Running <literal>after throwing</literal> advice will run the + advice of next precedence, or the computation under the join + point if there is no further advice. Then, if that computation threw + an exception of an appropriate type, the body of the advice will + run. </para> + + <para>Running <literal>after</literal> advice will run the advice of + next precedence, or the computation under the join point if + there is no further advice. Then the body of the advice will + run. </para> + </sect3> + + </sect2> + + <sect2> + <title>Reflective access to the join point</title> + + <para> + Three special variables are visible within bodies of advice: + <literal>thisJoinPoint</literal>, + <literal>thisJoinPointStaticPart</literal>, and + <literal>thisEnclosingJoinPointStaticPart</literal>. Each is bound to + an object that encapsulates some of the context of the advice's current + or enclosing join point. These variables exist because some pointcuts + may pick out very large collections of join points. For example, the + pointcut + </para> + + +<programlisting> +pointcut publicCall(): call(public * *(..)); +</programlisting> + + + <para> + picks out calls to many methods. Yet the body of advice over this + pointcut may wish to have access to the method name or parameters of a + particular join point. + </para> + + <para> + <literal>thisJoinPoint</literal> is bound to a complete join point + object, while <literal>thisJoinPointStaticPart</literal> is bound to a + part of the join point object that includes less information, + but for which no memory allocation is required on each execution of the + advice. + </para> + + <para> + <literal>thisEnclosingJoinPointStaticPart</literal> is bound to the + static part of the join point enclosing the current join point. Only + the static part of this enclosing join point is available through this + mechanism. + </para> + + <para> + Like standard Java reflection, which uses objects from the + <literal>java.lang.reflect</literal> hierarchy, join point objects have + types in a type hierarchy. The type of objects bound to + <literal>thisJoinPoint</literal> is + <literal>org.aspectj.lang.JoinPoint</literal>, while + <literal>thisStaticJoinPoint</literal> is bound to objects of interface + type <literal>org.aspectj.lang.JoinPoint.StaticPart</literal>. + </para> + </sect2> + + </sect1> + + <sect1> + <title>Static crosscutting</title> + + <para> + Advice declarations change the behavior of classes they crosscut, but do + not change their static type structure. For crosscutting concerns that do + operate over the static structure of type hierarchies, AspectJ provides + forms of introduction. + </para> + + <para> + Each introduction form is a member of the aspect defining it, but defines + a new member of another type. + </para> + + <sect2> + <title>Member introduction</title> + + <para> + A method introduction looks like + </para> + + <simplelist> + <member><literal><replaceable>Modifiers</replaceable> + <replaceable>Type</replaceable> <replaceable>TypePattern</replaceable> + . + <replaceable>Id</replaceable>(<replaceable>Formals</replaceable>) + { <replaceable>Body</replaceable> }</literal></member> + + <member><literal>abstract <replaceable>Modifiers</replaceable> + <replaceable>Type</replaceable> <replaceable>TypePattern</replaceable> + . <replaceable>Id</replaceable>(<replaceable>Formals</replaceable>); + </literal></member> + </simplelist> + + <para> + The effect of such an introduction is to make all the types in TypePattern + support the new method. Interfaces in TypePattern will support the new method + as well, even if the method is neither public nor abstract, so the + following is legal AspectJ code: + </para> + +<programlisting> +interface Iface {} + +aspect A { + private void Iface.m() { + System.err.println("I'm a private method on an interface"); + } + void worksOnI(Iface iface) { + // calling a private method on an interface + iface.m(); + } +} +</programlisting> + + <para> + A constructor introduction looks like + </para> + + <simplelist> + <member><literal><replaceable>Modifiers</replaceable> <replaceable>TypePattern</replaceable>.new(<replaceable>Formals</replaceable>) + { <replaceable>Body</replaceable> }</literal></member> + </simplelist> + + <para> + The effect of such an introduction is to make all the types in + TypePattern support the new constructor. You cannot introduce a + constructor onto an interface, so if TypePattern includes an interface + type it is an error. + </para> + + <para> + A field introduction looks like one of + </para> + + <simplelist> + <member><literal><replaceable>Modifiers</replaceable> + <replaceable>Type</replaceable> <replaceable>TypePattern</replaceable>.<replaceable>Id</replaceable> = <replaceable>Expression</replaceable>;</literal></member> + + <member><literal><replaceable>Modifiers</replaceable> + <replaceable>Type</replaceable> <replaceable>TypePattern</replaceable>.<replaceable>Id</replaceable>;</literal></member> + </simplelist> + + <para> + The effect of such an introduction is to make all the types in + TypePattern support the new field. Interfaces in TypePattern will + support the new field as well, even if the field is neither public, + nor static, nor final. + </para> + </sect2> + + <para> + Any occurrence of the identifier <literal>this</literal> in the body of + the constructor or method introduction, or in the initializer of a + field introduction, refers to the target type from the + <replaceable>TypePattern</replaceable> rather than to the aspect type. + </para> + + + <sect2> + <title>Access modifiers</title> + + <para> + Members may be introduced with access modifiers public or private, or + the default package-protected (protected introduction is not + supported). + </para> + + <para> + The access modifier applies in relation to the aspect, not in relation + to the target type. So a member that is privately introduced is visible + only from code that is defined within the aspect introducing it. One + that is package-protectedly introduced is visible only from code that + is defined within the introducing aspect's package. + </para> + + <para> + Note that privately introducing a method (which AspectJ supports) is + very different from introducing a private method (which AspectJ + previously supported). AspectJ does not allow the introduction of the + private method "void writeObject(ObjectOutputStream)" required to + implement the interface java.io.Serializable. + </para> + </sect2> + + <sect2> + <title>Conflicts</title> + + <para> + Introduction may cause conflicts among introduced members and between + introduced members and defined members. + </para> + + + <para> + Assuming <literal>otherPackage</literal> is not the package defining + the aspect <classname>A</classname>, the code + </para> + +<programlisting> +aspect A { + private Registry otherPackage.*.r; + public void otherPackage.*.register(Registry r) { + r.register(this); + this.r = r; + } +} +</programlisting> + + <para> + adds a field "<literal>r</literal>" to every type in otherPackage. This + field is only accessible from the code inside of aspect + <literal>A</literal>. The aspect also adds a + "<literal>register</literal>" method to every type in + <literal>otherPackage</literal>. This method is accessible + everywhere. + </para> + + <para> + If any type in <literal>otherPackage</literal> already defines a + private or package-protected field "<literal>r</literal>", there is no + conflict: The aspect cannot see such a field, and no code in + <literal>otherPackage</literal> can see the introduced + "<literal>r</literal>". + </para> + + <para> + If any type in <literal>otherPackage</literal> defines a public field + "<literal>r</literal>", there is a conflict: The expression + </para> + +<programlisting> +this.r = r +</programlisting> + + <para> + is an error, since it is ambiguous whether the introduced + "<literal>r</literal>" or the public "<literal>r</literal>" should be + used. + </para> + + <para> + If any type in <literal>otherPackage</literal> defines any method + "<literal>register(Registry)</literal>" there is a conflict, since it + would be ambiguous to any code that could see such a defined method + which "<literal>register(Registry)</literal>" method was applicable. + </para> + + <para> + Conflicts are resolved as much as possible as per Java's conflict + resolution rules: + </para> + + <simplelist> + <member>A subclass can inherit multiple <emphasis>fields</emphasis> from its superclasses, + all with the same name and type. However, it is an error to have an ambiguous + <emphasis>reference</emphasis> to a field.</member> + + <member>A subclass can only inherit multiple + <emphasis>methods</emphasis> with the same name and argument types from + its superclasses if only zero or one of them is concrete (i.e., all but + one is abstract, or all are abstract). + </member> + </simplelist> + + <para> + Given a potential conflict between inter-type member declarations in + different aspects, if one aspect dominates the other its declaration will + take effect without any conflict notice from compiler. This is true both + when the domination is declared explicitly in a "dominates" clause and + when sub-aspects implicitly dominate their corresponding super-aspect. + </para> + + </sect2> + + <sect2> + <title>Extension and Implementation</title> + + <para> + An aspect may introduce a superclass or superinterface onto a type, + with the declarations + </para> + + <simplelist> + <member><literal>declare parents: <replaceable>TypePattern</replaceable> extends <replaceable>TypeList</replaceable>;</literal></member> + <member><literal>declare parents: <replaceable>TypePattern</replaceable> implements <replaceable>TypeList</replaceable>;</literal></member> + </simplelist> + + <para> + For example, if an aspect wished to make a particular class runnable, + it might add an appropriate <literal>void run()</literal> method, but + it should also change the type of the class to specify that it fulfills + the <literal>Runnable</literal> interface. In order to implement the + methods in the <literal>Runnable</literal> interface, the + <literal>run()</literal> method must be publically introduced: + </para> + +<programlisting> +aspect A { + declare parents: SomeClass implements Runnable; + public void SomeClass.run() { ... } +} +</programlisting> + + </sect2> + + <sect2> + <title>Interfaces with members</title> + + <para> + Through the use of introduction, interfaces may now carry + (non-public-static-final) fields and (non-public-abstract) methods that + classes can inherit. Conflicts may occur from ambiguously inheriting + members from a superclass and multiple superinterfaces. + </para> + + <para> + Because interfaces may carry non-static initializers, the order of + super-interface instantiation is observable. We fix this order with the + following three properties: A supertype is initialized before a + subtype, that initialized code runs only once, and initializers for + supertypes run in left-to-right order. Consider the following hierarchy + where {<literal>Object</literal>, <literal>C</literal>, + <literal>D</literal>, <literal>E</literal>} are classes, + {<literal>M</literal>, <literal>N</literal>, <literal>O</literal>, + <literal>P</literal>, <literal>Q</literal>} are interfaces. + </para> + +<programlisting> + Object M O + \ / \ / + C N Q + \ / / + D P + \ / + E +</programlisting> + + <para> + when a new <literal>E</literal> is instantiated, the initializers run in this order: + </para> + +<programlisting> + Object M C O N D Q P E +</programlisting> + + </sect2> + + <sect2> + <title>Warnings and Errors</title> + + <para>An aspect may specify that a particular join point should never be + reached. </para> + + <simplelist> + <member><literal>declare error: <replaceable>Pointcut</replaceable>: <replaceable>String</replaceable>;</literal></member> + <member><literal>declare warning: <replaceable>Pointcut</replaceable>: <replaceable>String</replaceable>;</literal></member> + </simplelist> + + <para>If the compiler determines that a join point in + <replaceable>Pointcut</replaceable> could possibly be reached, then it + will signal either an error or warning, as declared, using the + <replaceable>String</replaceable> for its message. </para> + + </sect2> + + <sect2> + <title>Softened exceptions</title> + + <para>An aspect may specify that a particular kind of exception, if + thrown at a join point, should bypass Java's usual static exception + checking system and instead be thrown as a + <literal>org.aspectj.lang.SoftException</literal>, which is subtype of + <literal>RuntimeException</literal> and thus does not need to be + declared. </para> + + <simplelist> + <member><literal>declare soft: <replaceable>TypePattern</replaceable>: <replaceable>Pointcut</replaceable>;</literal></member> + </simplelist> + + <para>For example, the aspect</para> + +<programlisting> +aspect A { + declare soft: Exception: execution(void main(String[] args)); +} +</programlisting> + + <para>Would, at the execution join point, catch any + <literal>Exception</literal> and rethrow a + <literal>org.aspectj.lang.SoftException</literal> containing + original exception. </para> + + <para>This is similar to what the following advice would do</para> + +<programlisting> +aspect A { + void around() execution(void main(String[] args)) { + try { proceed(); } + catch (Exception e) { + throw new org.aspectj.lang.SoftException(e); + } + } +} +</programlisting> + + <para>except, in addition to wrapping the exception, it also affects + Java's static exception checking mechanism. </para> + + </sect2> + + <sect2> + <title>Statically determinable pointcuts</title> + + <para>Pointcuts that appear inside of <literal>declare</literal> forms + have certain restrictions. Like other pointcuts, these pick out join + points, but they do so in a way that is statically determinable. </para> + + <para>Consequently, such pointcuts may not include, directly or + indirectly (through user-defined pointcut declarations) pointcuts that + discriminate based on dynamic (runtime) context. Therefore, such + pointcuts may not be defined in terms of</para> + + <simplelist> + <member>cflow</member> + <member>cflowbelow</member> + <member>this</member> + <member>target</member> + <member>args</member> + <member>if</member> + </simplelist> + + <para> all of which can discriminate on runtime information. </para> + </sect2> + </sect1> + + <sect1> + <title>Aspects</title> + + <para> + An aspect is a crosscutting type defined by the aspect declaration. The + aspect declaration is similar to the class declaration in that it defines + a type and an implementation for that type. It differs in that the type + and implementation can cut across other types (including those defined by + other aspect declarations), and that it may not be directly instantiated + with a new expression, with cloning, or with serialization. Aspects may + have one constructor definition, but if so it must be of a constructor + taking no arguments and throwing no checked exceptions. + </para> + + <para> + Aspects may be defined either at the package level, or as a static nested + aspect, that is, a static member of a class, interface, or aspect. If it + is not at the package level, the aspect <emphasis>must</emphasis> be + defined with the static keyword. Local and anonymous aspects are not + allowed. + </para> + + <sect2> + <title>Aspect Extension</title> + + <para> + To support abstraction and composition of crosscutting concerns, + aspects can be extended in much the same way that classes can. Aspect + extension adds some new rules, though. + </para> + + <sect3> + <title>Aspects may extend classes and implement interfaces</title> + + <para> + An aspect, abstract or concrete, may extend a class and may implement + a set of interfaces. Extending a class does not provide the ability + to instantiate the aspect with a new expression: The aspect may still + only define a null constructor. + </para> + </sect3> + + <sect3> + <title>Classes may not extend aspects</title> + + <para> + It is an error for a class to extend or implement an aspect. + </para> + </sect3> + + <sect3> + <title>Aspects extending aspects + </title> + <para> + Aspects may extend other aspects, in which case not only are fields + and methods inherited but so are pointcuts. However, aspects may only + extend abstract aspects. It is an error for a concrete aspect to + extend another concrete aspect. + </para> + </sect3> + </sect2> + + <sect2> + <title>Aspect instantiation</title> + + <para> + Unlike class expressions, aspects are not instantiated with + <literal>new</literal> expressions. Rather, aspect instances are + automatically created to cut across programs. + </para> + + <para> + Because advice only runs in the context of an aspect instance, aspect + instantiation indirectly controls when advice runs. + </para> + + <para> + The criteria used to determine how an aspect is instantiated + is inherited from its parent aspect. If the aspect has no parent + aspect, then by default the aspect is a singleton aspect. + </para> + + <sect3> + <title>Singleton Aspects</title> + + <simplelist> + <member><literal>aspect <replaceable>Id</replaceable> { ... }</literal></member> + <member><literal>aspect <replaceable>Id</replaceable> issingleton { ... }</literal></member> + </simplelist> + + <para> + By default, or by using the modifier <literal>issingleton</literal>, an + aspect has exactly one instance that cuts across the entire program. + That instance is available at any time during program execution with + the static method <literal>aspectOf()</literal> defined on the aspect + -- so, in the above examples, <literal>A.aspectOf()</literal> will + return A's instance. This aspect instance is created as the aspect's + classfile is loaded. + </para> + + <para> + Because the an instance of the aspect exists at all join points in + the running of a program (once its class is loaded), its advice will + have a chance to run at all such join points. + </para> + </sect3> + + <sect3> + <title>Per-object aspects</title> + + <simplelist> + <member><literal>aspect <replaceable>Id</replaceable> perthis(<replaceable>Pointcut</replaceable>) { ... }</literal></member> + <member><literal>aspect <replaceable>Id</replaceable> pertarget(<replaceable>Pointcut</replaceable>) { ... }</literal></member> + </simplelist> + + <para> + If an aspect A is defined + <literal>perthis(<replaceable>Pointcut</replaceable>)</literal>, then + one object of type A is created for every object that is the + executing object (i.e., "this") at any of the join points picked out + by <replaceable>Pointcut</replaceable>. + The advice defined in A may then run at any join point where the + currently executing object has been associated with an instance of + A. + </para> + + <para> Similarly, if an aspect A is defined + <literal>pertarget(<replaceable>Pointcut</replaceable>)</literal>, + then one object of type A is created for every object that is the + target object of the join points picked out by + <replaceable>Pointcut</replaceable>. + The advice defined in A may then run at any join point where the + target object has been associated with an instance of + A. + </para> + + <para> + In either case, the static method call + <literal>A.aspectOf(Object)</literal> can be used to get the aspect + instance (of type A) registered with the object. Each aspect + instance is created as early as possible, but not before reaching a + join point picked out by <replaceable>Pointcut</replaceable> where + there is no associated aspect of type A. + </para> + + <para> Both <literal>perthis</literal> and <literal>pertarget</literal> + aspects may be affected by code the AspectJ compiler controls, as + discussed in the <xref linkend="limitations"/> appendix. </para> + + </sect3> + + <sect3> + <title>Per-control-flow aspects</title> + + <simplelist> + <member><literal>aspect <replaceable>Id</replaceable> percflow(<replaceable>Pointcut</replaceable>) { ... }</literal></member> + <member><literal>aspect <replaceable>Id</replaceable> percflowbelow(<replaceable>Pointcut</replaceable>) { ... }</literal></member> + </simplelist> + + <para> + If an aspect A is defined + <literal>percflow(<replaceable>Pointcut</replaceable>)</literal> or + <literal>percflowbelow(<replaceable>Pointcut</replaceable>)</literal>, + then one object of type A is created for each flow of control of the + join points picked out by <replaceable>Pointcut</replaceable>, either + as the flow of control is entered, or below the flow of control, + respectively. The advice defined in A may run at any join point in + or under that control flow. During each such flow of control, the + static method <literal>A.aspectOf()</literal> will return an object + of type + A. An instance of the aspect is created upon entry into each such + control flow. + </para> + </sect3> + </sect2> + + <sect2> + <title>Aspect privilege</title> + + <simplelist> + <member><literal>privileged aspect <replaceable>Id</replaceable> { ... }</literal></member> + </simplelist> + + <para> + Code written in aspects is subject to the same access control rules as + Java code when referring to members of classes or aspects. So, for + example, code written in an aspect may not refer to members with + default (package-protected) visibility unless the aspect is defined in + the same package. + </para> + + <para> + While these restrictions are suitable for many aspects, there may be + some aspects in which advice or introductions needs to access private + or protected resources of other types. To allow this, aspects may be + declared <literal>privileged</literal>. Code in priviliged aspects has + access to all members, even private ones. + </para> + + +<programlisting> +class C { + private int i = 0; + void incI(int x) { i = i+x; } +} +privileged aspect A { + static final int MAX = 1000; + before(int x, C c): call(void C.incI(int)) <![CDATA[&&]]> target(c) <![CDATA[&&]]> args(x) { + if (c.i+x > MAX) throw new RuntimeException(); + } +} +</programlisting> + + <para> + In this case, if A had not been declared privileged, the field reference + c.i would have resulted in an error signalled by the compiler. + </para> + + <para> + If a privileged aspect can access multiple versions of a particular + member, then those that it could see if it were not privileged take + precedence. For example, in the code + </para> + +<programlisting> +class C { + private int i = 0; + void foo() { } +} +privileged aspect A { + private int C.i = 999; + before(C c): call(void C.foo()) target(c) { + System.out.println(c.i); + } +} +</programlisting> + + <para> + A's introduced private field C.i, initially bound to 999, will be + referenced in the body of the advice in preference to C's privately + declared field, since the A would have access to fields it introduces + even if it were not privileged. + </para> + + </sect2> + + + <sect2> + <title>Aspect domination</title> + + <simplelist> + <member><literal>aspect <replaceable>Id</replaceable> dominates <replaceable>TypePattern</replaceable> { ... }</literal></member> + </simplelist> + + <para> + An aspect may declare that the advice in it dominates the advice in + some other aspect. Such declarations are like the + <literal>strictfp</literal> keyword in Java; it applies to the advice + declarations inside of the respective aspects, and states that the + advice declared in the current aspect has more precedence than the + advice in the aspects from <replaceable>TypePattern</replaceable>. + </para> + + <para> + For example, the CountEntry aspect might want to count the entry to + methods in the current package accepting a Type object as its first + argument. However, it should count all entries, even those that the + aspect DisallowNulls causes to throw exceptions. This can be + accomplished by stating that CountEntry dominates DisallowNulls. + </para> + + +<programlisting> +aspect DisallowNulls { + pointcut allTypeMethods(Type obj): call(* *(..)) <![CDATA[&&]]> args(obj, ..); + before(Type obj): allTypeMethods(obj) { + if (obj == null) throw new RuntimeException(); + } +} +aspect CountEntry dominates DisallowNulls { + pointcut allTypeMethods(Type obj): call(* *(..)) <![CDATA[&&]]> args(obj, ..); + static int count = 0; + before(): allTypeMethods(Type) { + count++; + } +} +</programlisting> + + </sect2> + </sect1> + +</appendix> + +<!-- +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.sgml" "book" "appendix") +End: +--> diff --git a/docs/progGuideDB/telecom.gif b/docs/progGuideDB/telecom.gif Binary files differnew file mode 100644 index 000000000..89a7207f3 --- /dev/null +++ b/docs/progGuideDB/telecom.gif |