diff options
author | Alexander Kriegisch <Alexander@Kriegisch.name> | 2024-01-04 08:13:04 +0700 |
---|---|---|
committer | Alexander Kriegisch <Alexander@Kriegisch.name> | 2024-01-06 10:09:11 +0100 |
commit | 0065b755292708d6fd27c067564ecef2b10ede04 (patch) | |
tree | 2a88188271fe2910fd26c5b8536f39fabe111168 /docs/progguide | |
parent | ba6058a4007f937c3d32a6022446edaa149a0d1d (diff) | |
download | aspectj-0065b755292708d6fd27c067564ecef2b10ede04.tar.gz aspectj-0065b755292708d6fd27c067564ecef2b10ede04.zip |
Delete 50+ XML DocBook resource files
in favour of the already existing asciidoc ones.
Signed-off-by: Alexander Kriegisch <Alexander@Kriegisch.name>
Diffstat (limited to 'docs/progguide')
-rw-r--r-- | docs/progguide/aspectj-docs.css | 89 | ||||
-rw-r--r-- | docs/progguide/aspectjdoc.dsl | 124 | ||||
-rw-r--r-- | docs/progguide/build.sh | 79 | ||||
-rw-r--r-- | docs/progguide/examples.xml | 2443 | ||||
-rw-r--r-- | docs/progguide/gettingstarted.xml | 1310 | ||||
-rw-r--r-- | docs/progguide/idioms.xml | 74 | ||||
-rw-r--r-- | docs/progguide/implementation.xml | 377 | ||||
-rw-r--r-- | docs/progguide/language.xml | 1354 | ||||
-rw-r--r-- | docs/progguide/pitfalls.xml | 112 | ||||
-rw-r--r-- | docs/progguide/preface.xml | 66 | ||||
-rw-r--r-- | docs/progguide/progguide.html.xsl | 9 | ||||
-rw-r--r-- | docs/progguide/progguide.xml | 63 | ||||
-rw-r--r-- | docs/progguide/quickreference.xml | 773 | ||||
-rw-r--r-- | docs/progguide/semantics.xml | 3271 |
14 files changed, 0 insertions, 10144 deletions
diff --git a/docs/progguide/aspectj-docs.css b/docs/progguide/aspectj-docs.css deleted file mode 100644 index 9c2f5d4fc..000000000 --- a/docs/progguide/aspectj-docs.css +++ /dev/null @@ -1,89 +0,0 @@ -body { - font-family: "Lucida Grande", "Trebuchet MS", sans-serif; - line-height: 1.1em; - } - -h1 { - margin-bottom: 3px; - padding-bottom: 0px; - line-height: 1.1em; -} - -h2 { - font-size: 130%; - font-weight: bold ; - line-height: 16px; - color: #FFFFFF; - background-color: #0080C0; - padding: 5px; -} - -h3 { - font-size: 110%; - font-weight: bold ; - line-height: 14px; - color: #FFFFFF; - background-color: orange; - padding: 5px; -} - -tt { - font-size: 120%; - color: #00AAF0; - } - -tt tt { - font-size: 100%; - } - -.programlisting { - padding-top: 5px; - border: 2px solid #ccc; - background: #eee; - font-size: 120%; - color: #111199; - - } - -.term { - color: #111199; - } - -.variablelist dd { - margin-left: 18px; - padding-left: 20px; - background: url(dd_arrow.gif) no-repeat 0 2px; - } - -.toc dt { - font-size: 110%; - padding-bottom: 0px; - margin-bottom: 5px; - } - -.toc dl dd dt { - font-size: 100%; - } - -.toc dt { - font-size: 100% - margin-bottom: 0; - } - -.informaltable table { - margin-left: 5%; - } - -.informaltable th { - background-color: orange; - padding: 1px; - } - -ul li { - line-height: 1.2em; - } - -.keyword { - font-weight: bold; - color: purple; - }
\ No newline at end of file diff --git a/docs/progguide/aspectjdoc.dsl b/docs/progguide/aspectjdoc.dsl deleted file mode 100644 index 4db3b678e..000000000 --- a/docs/progguide/aspectjdoc.dsl +++ /dev/null @@ -1,124 +0,0 @@ -<!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/progguide/build.sh b/docs/progguide/build.sh deleted file mode 100644 index 19499ff3b..000000000 --- a/docs/progguide/build.sh +++ /dev/null @@ -1,79 +0,0 @@ -#/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/progguide/examples.xml b/docs/progguide/examples.xml deleted file mode 100644 index 05645ab04..000000000 --- a/docs/progguide/examples.xml +++ /dev/null @@ -1,2443 +0,0 @@ -<chapter id="examples" xreflabel="Examples"> - <title>Examples</title> - - <sect1 id="examples-intro"> - <title>Introduction</title> - - <para> - This chapter consists entirely of examples of AspectJ use. - </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 id="examples-howto"> - <title>Obtaining, Compiling and Running the Examples</title> - - <para> - The examples source code is part of the AspectJ distribution which may be - downloaded from the AspectJ project page ( <ulink - url="https://eclipse.org/aspectj" /> ). - </para> - - <para> - Compiling most examples is straightforward. Go the - <filename><replaceable>InstallDir</replaceable>/examples</filename> - directory, and look for a <filename>.lst</filename> file in one of - the example subdirectories. Use the <literal>-arglist</literal> - option to <literal>ajc</literal> to compile the example. For - instance, to compile the telecom example with billing, type - </para> - -<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 id="examples-basic"> - <title>Basic Techniques</title> - - <para> - This section presents two basic techniques of using AspectJ, one each - from the two fundamental ways of capturing crosscutting concerns: - with dynamic join points and advice, and with static - introduction. Advice changes an application's behavior. Introduction - changes both an application's behavior and its structure. - </para> - - <para> - The first example, <xref linkend="examples-joinPoints" />, is about - gathering and using information about the join point that has - triggered some advice. The second example, <xref - linkend="examples-roles" />, concerns a crosscutting view of an - existing class hierarchy. </para> - -<!-- ======================================== --> - - <sect2 id="examples-joinPoints"> - <title>Join Points and <literal>thisJoinPoint</literal></title> - - <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 program reaches a join - point, advice on that join point may run in addition to (or instead - of) the join point itself. - </para> - - <para> - When using a pointcut that picks out join points of a single kind - by name, typicaly the the advice will know exactly what kind of - join point it is associated with. The pointcut may even publish - context about the join point. Here, for example, since the only - join points picked out by the pointcut are calls of a certain - method, we can get the target value and one of the argument values - of the method calls directly. - </para> - -<programlisting><![CDATA[ -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 shape of the join point is not so clear. For - instance, suppose a complex application is being debugged, and we - want to trace when any method of some class is executed. The - pointcut - </para> - -<programlisting><![CDATA[ -pointcut execsInProblemClass(): within(ProblemClass) - && execution(* *(..)); -]]></programlisting> - - <para> - will pick out each execution join point of every method defined - within <classname>ProblemClass</classname>. Since advice executes - at each join point picked out by the pointcut, we can reasonably - ask which join point was reached. - </para> - - <para> - Information about the join point that was matched is available to - advice through the special variable - <varname>thisJoinPoint</varname>, of type <ulink - url="../api/org/aspectj/lang/JoinPoint.html"><classname>org.aspectj.lang.JoinPoint</classname></ulink>. - Through this object we can access information such as</para> - - <itemizedlist spacing="compact"> - <listitem> - the kind of join point that was matched - </listitem> - <listitem> - the source location of the code associated with the join point - </listitem> - <listitem> - normal, short and long string representations of the - current join point - </listitem> - <listitem> - the actual argument values of the join point - </listitem> - <listitem> - the signature of the member associated with the join point - </listitem> - <listitem>the currently executing object</listitem> - <listitem>the target object</listitem> - <listitem> - an object encapsulating the static information about the join - point. This is also available through the special variable - <varname>thisJoinPointStaticPart</varname>.</listitem> - </itemizedlist> - - <sect3> - <title>The <classname>Demo</classname> class</title> - - <para>The class <classname>tjp.Demo</classname> in - <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 <literal>GetInfo</literal> aspect</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> - -<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> - <title>Defining the scope of a pointcut</title> - - <para>The pointcut <function>goCut</function> is defined as - -<programlisting><![CDATA[ -cflow(this(Demo)) && execution(void go()) -]]></programlisting> - - so that only executions made in the control flow of - <literal>Demo.go</literal> are intercepted. The control flow - from the method <literal>go</literal> includes the execution of - <literal>go</literal> itself, so the definition of the around - advice includes <literal>!execution(* go())</literal> to - exclude it from the set of executions advised. </para> - </sect4> - - <sect4> - <title>Printing the class and method name</title> - - <para> - The name of the method and that method's defining class are - available as parts of the <ulink - url="../api/org/aspectj/lang/Signature.html">org.aspectj.lang.Signature</ulink> - object returned by calling <literal>getSignature()</literal> on - either <literal>thisJoinPoint</literal> or - <literal>thisJoinPointStaticPart</literal>. - </para> - </sect4> - - <sect4> - <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>org.aspectj.lang.reflect.CodeSignature</literal></ulink> - associated with the join point. All execution join points have code - signatures, so the cast to <literal>CodeSignature</literal> - cannot fail. </para> - - <para> - The dynamic portions of the parameter details, the actual - values of the parameters, are accessed directly from the - execution join point object. - </para> - </sect4> - </sect3> - </sect2> - -<!-- ============================== --> - - <sect2 id="examples-roles"> - <title>Roles and Views</title> - - <para> - (The code for this example is in - <filename><replaceable>InstallDir</replaceable>/examples/introduction</filename>.) - </para> - - <para> - Like advice, inter-type declarations are members of an aspect. They - declare members that act as if they were defined on another class. - Unlike advice, inter-type declarations affect not only the behavior - of the application, but also the structural relationship between an - application's classes. - </para> - - <para> - This is crucial: Publically affecting the class structure of an - application makes these modifications available to other components - of the application. - </para> - - <para> - Aspects can declare inter-type - - <itemizedlist spacing="compact"> - <listitem>fields</listitem> - <listitem>methods</listitem> - <listitem>constructors</listitem> - </itemizedlist> - - and can also declare that target types - - <itemizedlist spacing="compact"> - <listitem>implement new interfaces</listitem> - <listitem>extend new classes</listitem> - </itemizedlist> - </para> - - <para> - This example provides three illustrations of the use of inter-type - declarations to encapsulate roles or views of a class. The class - our aspect will be dealing with, <classname>Point</classname>, is a - simple class with rectangular and polar coordinates. Our inter-type - declarations will make the class <classname>Point</classname>, in - turn, cloneable, hashable, and comparable. These facilities are - provided by AspectJ without having to modify the code for the class - <classname>Point</classname>. - </para> - - <sect3> - <title>The <classname>Point</classname> class</title> - - <para>The <classname>Point</classname> class defines geometric points - whose interface includes polar and rectangular coordinates, plus some - simple operations to relocate points. <classname>Point</classname>'s - implementation has attributes for both its polar and rectangular - 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>The <classname>CloneablePoint</classname> aspect</title> - - <para> - This first aspect is responsible for - <classname>Point</classname>'s implementation of the - <classname>Cloneable</classname> interface. It declares that - <literal>Point implements Cloneable</literal> with a - <literal>declare parents</literal> form, and also publically - declares a specialized <literal>Point</literal>'s - <literal>clone()</literal> method. In Java, all objects inherit - the method <literal>clone</literal> from the class - <classname>Object</classname>, but an object is not cloneable - unless its class also implements the interface - <classname>Cloneable</classname>. In addition, classes - frequently have requirements over and above the simple - bit-for-bit copying that <literal>Object.clone</literal> does. In - our case, we want to update a <classname>Point</classname>'s - coordinate systems before we actually clone the - <classname>Point</classname>. So our aspect makes sure that - <literal>Point</literal> overrides - <literal>Object.clone</literal> with a new method that does what - we want. - </para> - - <para> - We also define a test <literal>main</literal> method in the - aspect for convenience. - </para> - -<programlisting><![CDATA[ -public aspect CloneablePoint { - - declare parents: Point implements Cloneable; - - 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> - </sect3> - - <sect3> - <title>The <classname>ComparablePoint</classname> aspect</title> - - <para> - <classname>ComparablePoint</classname> is responsible for - <literal>Point</literal>'s implementation of the - <literal>Comparable</literal> interface. </para> - - <para> - The interface <classname>Comparable</classname> defines the - 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> - <classname>ComparablePoint</classname> uses <literal>declare - parents</literal> to declare that <literal>Point implements - Comparable</literal>, and also publically declares the - appropriate <literal>compareTo(Object)</literal> method: A - <classname>Point</classname> <literal>p1</literal> is said to be - less than another <classname>Point</classname><literal> - p2</literal> if <literal>p1</literal> is closer to the - origin. - </para> - - <para> - We also define a test <literal>main</literal> method in the - aspect for convenience. - </para> - -<programlisting><![CDATA[ -public aspect ComparablePoint { - - declare parents: Point implements Comparable; - - 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>The <classname>HashablePoint</classname> aspect</title> - - <para> - Our third aspect is responsible for <literal>Point</literal>'s - overriding of <literal>Object</literal>'s - <literal>equals</literal> and <literal>hashCode</literal> methods - in order to make <literal>Point</literal>s hashable. - </para> - - <para> - The method <literal>Object.hashCode</literal> returns an - integer, suitable for use as a hash table key. It is not required - that two objects which are not equal (according to the - <literal>equals</literal> method) return different integer - results from <literal>hashCode</literal> but it can - improve performance when the integer is used as a key into a - data structure. However, any two objects which are equal - must return the same integer value from a call to - <literal>hashCode</literal>. Since the default implementation - of <literal>Object.equals</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> - So <classname>HashablePoint</classname> declares - <literal>Point</literal>'s <literal>hashCode</literal> and - <literal>equals</literal> methods, using - <classname>Point</classname>'s rectangular coordinates to - generate a hash code and to test for equality. The - <literal>x</literal> and <literal>y</literal> coordinates are - obtained using the appropriate get methods, which ensure the - rectangular coordinates are up-to-date before returning their - values. - </para> - - <para> - And again, we supply a <literal>main</literal> method in the - aspect for testing. - </para> - -<programlisting><![CDATA[ -public aspect HashablePoint { - - public int Point.hashCode() { - 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> - - </sect3> - </sect2> - </sect1> - -<!-- ============================================================ --> -<!-- ============================================================ --> - - <sect1 id="examples-development"> - <title>Development Aspects</title> - - <sect2 id="tracing-using-aspects" xreflabel="tracing-using-aspects"> - <title>Tracing using aspects</title> - - <para> - (The code for this example is in - <filename><replaceable>InstallDir</replaceable>/examples/tracing</filename>.) - </para> - - <para> - Writing a class that provides tracing functionality is easy: a - couple of functions, a boolean flag for turning tracing on and - off, a choice for an output stream, maybe some code for - formatting the output -- these are all elements that - <classname>Trace</classname> classes have been known to - have. <classname>Trace</classname> classes may be highly - sophisticated, too, if the task of tracing the execution of a - program demands it. - </para> - - <para> - But developing the support for tracing is just one part of the - effort of inserting tracing into a program, and, most likely, not - the biggest part. The other part of the effort is calling the - tracing functions at appropriate times. In large systems, this - interaction with the tracing support can be overwhelming. Plus, - tracing is one of those things that slows the system down, so - these calls should often be pulled out of the system before the - product is shipped. For these reasons, it is not unusual for - developers to write ad-hoc scripting programs that rewrite the - source code by inserting/deleting trace calls before and after - the method bodies. - </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> - <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 - <literal>traceEntry</literal> and <literal>traceExit</literal> as - public operations of this class. You can see that they were - classified as protected. They are supposed to be internal - implementation details of the advice. - </para> - - <para> - The key piece of this aspect is the abstract pointcut classes that - serves as the base for the definition of the pointcuts constructors - and methods. Even though <classname>classes</classname> is - abstract, and therefore no concrete classes are mentioned, we can - put advice on it, as well as on the pointcuts that are based on - it. The idea is "we don't know exactly what the pointcut will be, - but when we do, here's what we want to do with it." In some ways, - abstract pointcuts are similar to abstract methods. Abstract - methods don't provide the implementation, but you know that the - concrete subclasses will, so you can invoke those methods. - </para> - </sect3> - </sect2> - </sect1> - -<!-- ============================================================ --> -<!-- ============================================================ --> - - <sect1 id="examples-production"> - <title>Production Aspects</title> - - <!-- ==================== --> - - <sect2 id="a-bean-aspect" xreflabel="a-bean-aspect"><!-- 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 - Java beans with bound properties. - </para> - - <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> - <title>The <classname>Point</classname> class</title> - - <para> - The <classname>Point</classname> class is a very simple class with - trivial getters and setters, and a simple vector offset method. - </para> - -<programlisting><![CDATA[ -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 <classname>BoundPoint</classname> aspect</title> - - <para> - The <classname>BoundPoint</classname> aspect is responsible for - <literal>Point</literal>'s "beanness". The first thing it does is - privately declare that each <literal>Point</literal> has a - <literal>support</literal> field that holds reference to an - instance of <classname>PropertyChangeSupport</classname>. - -<programlisting><![CDATA[ -private PropertyChangeSupport Point.support = new PropertyChangeSupport(this); -]]></programlisting> - - The property change support object must be constructed with a - reference to the bean for which it is providing support, so it is - initialized by passing it <literal>this</literal>, an instance of - <classname>Point</classname>. Since the <literal>support</literal> - field is private declared in the aspect, only the code in the - aspect can refer to it. - </para> - - <para> - The aspect also declares <literal>Point</literal>'s methods for - registering and managing listeners for property change events, - which delegate the work to the property change support object: - -<programlisting><![CDATA[ -public void Point.addPropertyChangeListener(PropertyChangeListener listener){ - support.addPropertyChangeListener(listener); -} -public void Point.addPropertyChangeListener(String propertyName, - PropertyChangeListener listener){ - - support.addPropertyChangeListener(propertyName, listener); -} -public void Point.removePropertyChangeListener(String propertyName, - PropertyChangeListener listener) { - support.removePropertyChangeListener(propertyName, listener); -} -public void Point.removePropertyChangeListener(PropertyChangeListener listener) { - support.removePropertyChangeListener(listener); -} -public void Point.hasListeners(String propertyName) { - support.hasListeners(propertyName); -} -]]></programlisting> - </para> - - <para> - The aspect is also responsible for making sure - <classname>Point</classname> implements the - <classname>Serializable</classname> interface: - -<programlisting><![CDATA[ -declare parents: Point implements Serializable; -]]></programlisting> - - Implementing this interface in Java does not require any methods to - be implemented. Serialization for <classname>Point</classname> - objects is provided by the default serialization method. - </para> - - <para> - The <function>setters</function> pointcut picks out calls to the - <literal>Point</literal>'s <literal>set</literal> methods: any - method whose name begins with "<literal>set</literal>" and takes - one parameter. The around advice on <literal>setters()</literal> - stores the values of the <literal>X</literal> and - <literal>Y</literal> properties, calls the original - <literal>set</literal> method and then fires the appropriate - property change event according to which set method was - called. - </para> - -<programlisting><![CDATA[ -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 id="the-subject-observer-protocol" xreflabel="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> - - <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> - <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 - declares an inter-type field and two inter-type methods so that - each <literal>Observer</literal> can hold onto its <literal>Subject</literal>. - </para> - </sect3> - - <sect3> - <title>Application Classes</title> - - <para> - <classname>Button</classname> objects extend - <classname>java.awt.Button</classname>, and all they do is make - sure the <literal>void click()</literal> method is called whenever - a button is clicked. - </para> - -<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 assuring that <classname>Button</classname> and - <classname>ColorLabel</classname> implement the appropriate - interfaces, declaring that they implement the methods required by - those interfaces, and providing a definition for the abstract - <literal>stateChanges</literal> pointcut. Now, every time a - <classname>Button</classname> is clicked, all - <classname>ColorLabel</classname> objects observing that button - will <literal>colorCycle</literal>. - </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 id="a-simple-telecom-simulation" xreflabel="a-simple-telecom-simulation"> - <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 <classname>Customer</classname> class</title> - - <para> - <classname>Customer</classname> has methods - <literal>call</literal>, <literal>pickup</literal>, - <literal>hangup</literal> and <literal>merge</literal> for - managing calls. - </para> - -<programlisting><![CDATA[ -public class Customer { - - 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 <classname>Call</classname> class</title> - - <para> - Calls are created with a caller and receiver who are customers. If - the caller and receiver have the same area code then the call can - be established with a <classname>Local</classname> connection (see - below), otherwise a <classname>LongDistance</classname> connection - is required. A call comprises a number of connections between - customers. Initially there is only the connection between the - caller and receiver but additional connections can be added if - calls are merged to form conference calls. - </para> - </sect3> - - <sect3> - <title>The <classname>Connection</classname> class</title> - - <para> - The class <classname>Connection</classname> models the physical - details of establishing a connection between customers. It does - this with a simple state machine (connections are initially - <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 <literal>Local</literal> and <literal>LongDistance</literal> classes</title> - - <para> - The two kinds of connections supported by our simulation are - <literal>Local</literal> and <literal>LongDistance</literal> - connections. - </para> - -<programlisting><![CDATA[ -class Local extends Connection { - Local(Customer a, Customer b) { - super(a, b); - System.out.println("[new local connection from " + - a + " to " + b + "]"); - } -} -]]></programlisting> - -<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>The Timing aspect</title> - - <para> - The <classname>Timing</classname> aspect keeps track of total - connection time for each <classname>Customer</classname> by - starting and stopping a timer associated with each connection. It - uses some helper classes: - </para> - - <sect4> - <title>The <classname>Timer</classname> class</title> - - <para> - A <classname>Timer</classname> object simply records the current - time when it is started and stopped, and returns their difference - when asked for the elapsed time. The aspect - <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 <classname>TimerLog</classname> aspect</title> - - <para> - The <classname>TimerLog</classname> aspect can be included in a - build to get the timer to announce when it is started and - stopped. - </para> - -<programlisting><![CDATA[ -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 <classname>Timing</classname> aspect</title> - - <para> - The <classname>Timing</classname> aspect is declares an - inter-type field <literal>totalConnectTime</literal> for - <classname>Customer</classname> to store the accumulated connection - time per <classname>Customer</classname>. It also declares that - each <classname>Connection</classname> object has a timer. - -<programlisting><![CDATA[ -public long Customer.totalConnectTime = 0; -private Timer Connection.timer = new Timer(); -]]></programlisting> - - Two pieces of after advice ensure that the timer is started when - a connection is completed and and stopped when it is dropped. The - pointcut <literal>endTiming</literal> is defined so that it can - be used by the <classname>Billing</classname> aspect. - </para> - -<programlisting><![CDATA[ -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>The <literal>Billing</literal> aspect</title> - - <para> - The Billing system adds billing functionality to the telecom - application on top of timing. - </para> - - <para> - The <classname>Billing</classname> aspect declares that each - <classname>Connection</classname> has a <literal>payer</literal> - inter-type field to indicate who initiated the call and therefore - who is responsible to pay for it. It also declares the inter-type - method <literal>callRate</literal> of - <classname>Connection</classname> so that local and long distance - calls can be charged differently. The call charge must be - calculated after the timer is stopped; the after advice on pointcut - <literal>Timing.endTiming</literal> does this, and - <classname>Billing</classname> is declared to be more precedent - than <classname>Timing</classname> to make sure that this advice - runs after <classname>Timing</classname>'s advice on the same join - point. Finally, it declares inter-type methods and fields for - <classname>Customer</classname> to handle the - <literal>totalCharge</literal>. - </para> - -<programlisting><![CDATA[ -public aspect Billing { - // precedence required to get advice on endtiming in the right order - declare precedence: Billing, Timing; - - public static final long LOCAL_RATE = 3; - public static final long LONG_DISTANCE_RATE = 10; - - public Customer Connection.payer; - public Customer getPayer(Connection conn) { return conn.payer; } - - 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> - - </sect3> - - <sect3> - <title>Accessing the inter-type state</title> - - <para> - Both the aspects <classname>Timing</classname> and - <classname>Billing</classname> contain the definition of operations - that the rest of the system may want to access. For example, when - running the simulation with one or both aspects, we want to find - out how much time each customer spent on the telephone and how big - their bill is. That information is also stored in the classes, but - they are accessed through static methods of the aspects, since the - state they refer to is private to the aspect. - </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)</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 more precedent than Timing so that Billing's - after advice runs after that of Timing when they are on the - same join point. - </para> - </listitem> - - <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 id="examples-reusable"> - <title>Reusable Aspects</title> - - <sect2 id="tracing-using-aspects-revisited" xreflabel="tracing-using-aspects-revisited"> - <title>Tracing using 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> diff --git a/docs/progguide/gettingstarted.xml b/docs/progguide/gettingstarted.xml deleted file mode 100644 index 6429d017f..000000000 --- a/docs/progguide/gettingstarted.xml +++ /dev/null @@ -1,1310 +0,0 @@ -<chapter id="starting" xreflabel="Getting Started with AspectJ"> - - <title>Getting Started with AspectJ</title> - - <sect1 id="starting-intro"> - <title>Introduction</title> - - <para> - Many software developers are attracted to the idea of aspect-oriented - programming (AOP) 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 more complete examples and supporting material linked from the - AspectJ web site ( <ulink url="https://eclipse.org/aspectj" /> ). - </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="starting-aspectj"/>, we present the core of AspectJ's - features, and in <xref linkend="starting-development"/>, we present - aspects that facilitate tasks such as debugging, testing and - performance tuning of applications. And, in the section following, - <xref linkend="starting-production"/>, 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="language"/>. - </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="starting-aspectj" xreflabel="Introduction to AspectJ"> - <title>Introduction to AspectJ</title> - - <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 features 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 that's - really just a name for an existing Java concept. It adds to Java - only a few new constructs: pointcuts, advice, inter-type declarations - and aspects. Pointcuts and advice dynamically affect program flow, - inter-type declarations statically affects a program's class - hierarchy, and aspects encapsulate these new constructs. - </para> - - <para> - A <emphasis>join point</emphasis> is a well-defined point in the - program flow. A <emphasis>pointcut</emphasis> picks out certain join - points and values at those points. A piece of - <emphasis>advice</emphasis> is code that is executed when a join - point is reached. These are the dynamic parts of AspectJ. - </para> - - <para> - AspectJ also has different kinds of <emphasis>inter-type - declarations</emphasis> that allow the programmer to modify a - program's static structure, namely, the members of its classes and - the relationship between classes. - </para> - - <para> - AspectJ's <emphasis>aspect</emphasis> are the unit of modularity for - crosscutting concerns. They behave somewhat like Java classes, but - may also include pointcuts, advice and inter-type declarations. - </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 use - inter-type declarations to deal with crosscutting concerns of a - program's class structure. - </para> - -<!-- ============================== --> - - <sect2 id="the-dynamic-join-point-model" xreflabel="the-dynamic-join-point-model"> - <title>The Dynamic Join Point Model</title> - - <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. This chapter describes - AspectJ's dynamic join points, in which join points are certain - well-defined points in the execution of the program. - </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 - return (either normally or by throwing an exception). - </para> - - <para> - Each method call at runtime is a different join point, even if it - comes from the same call expression in the program. Many other - join points may run while a method call join point is executing -- - all the join points that happen while executing the method body, - and in those methods called from the body. We say that these join - points execute in the <emphasis>dynamic context</emphasis> of the - original call join point. - </para> - </sect2> - -<!-- ============================== --> - - <sect2 id="pointcuts-starting" xreflabel="pointcuts-starting"> - <title>Pointcuts</title> - - <para> - In AspectJ, <emphasis>pointcuts</emphasis> pick out certain join - points in the program flow. For example, the pointcut - </para> - -<programlisting format="linespecific"> -call(void Point.setX(int)) -</programlisting> - - <para> - picks out each join point that is a call to a method that has the - signature <literal>void Point.setX(int)</literal> - that is, - <classname>Point</classname>'s void <function>setX</function> - method with a single <literal>int</literal> parameter. - </para> - - <para> - A pointcut can be built out of other pointcuts with and, or, and - not (spelled <literal>&&</literal>, <literal>||</literal>, - and <literal>!</literal>). For example: - </para> - -<programlisting format="linespecific"> -call(void Point.setX(int)) || -call(void Point.setY(int)) -</programlisting> - - <para> - picks out each join point that is either a call to - <function>setX</function> or a call to <function>setY</function>. - </para> - - <para> - Pointcuts can identify join points from many different types - - in other words, they can crosscut types. For example, - </para> - -<programlisting format="linespecific"> -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> - picks out each join point that is a call to one of five methods - (the first of which is an interface method, by the way). - </para> - - <para> - In our example system, this pointcut captures all the join points - when a <classname>FigureElement</classname> moves. While this is a - useful way to specify this crosscutting concern, it is a bit of a - mouthful. So AspectJ allows programmers to define their own named - pointcuts with the <literal>pointcut</literal> form. So 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> - and whenever this definition is visible, the programmer can simply - use <literal>move()</literal> to capture this complicated - pointcut. - </para> - - <para> - The previous pointcuts are all based on explicit enumeration of a - set of method signatures. We sometimes 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, the pointcut - </para> - -<programlisting format="linespecific"> -call(void Figure.make*(..)) -</programlisting> - - <para> - picks out each join point that's a call to a void method defined - on <classname>Figure</classname> whose the name begins with - "<literal>make</literal>" regardless of the method's parameters. - In our system, this picks out calls to the factory methods - <function>makePoint</function> and <function>makeLine</function>. - The pointcut - </para> - -<programlisting format="linespecific"> -call(public * Figure.* (..)) -</programlisting> - - <para> - picks out each call to <classname>Figure</classname>'s public - methods. - </para> - - <para> - But wildcards aren't the only properties AspectJ supports. - Another pointcut, <function>cflow</function>, identifies join - points based on whether they occur in the dynamic context of - other join points. So - </para> - -<programlisting format="linespecific"> -cflow(move()) -</programlisting> - - <para> - picks out each join point that occurs in the dynamic context of - the join points picked out by <literal>move()</literal>, our named - pointcut defined above. So this picks out each join points that - occurrs between when a move method is called and when it returns - (either normally or by throwing an exception). - </para> - - </sect2> - -<!-- ============================== --> - - <sect2 id="advice-starting" xreflabel="advice-starting"> - <title>Advice</title> - - <para> - So pointcuts pick out join points. But they don't - <emphasis>do</emphasis> anything apart from picking out join - points. To actually implement crosscutting behavior, we use - advice. Advice brings together a pointcut (to pick out join - points) and a body of code (to run at each of those join points). - </para> - - <para> - AspectJ has several different kinds of advice. <emphasis>Before - advice</emphasis> runs as a join point is reached, before the - program proceeds with the join point. For example, before advice - on a method call join point runs before the actual method starts - running, just after the arguments to the method call are evaluated. - </para> - -<programlisting><![CDATA[ -before(): move() { - System.out.println("about to move"); -} -]]></programlisting> - - <para> - <emphasis>After advice</emphasis> on a particular join point runs - after the program proceeds with that join point. For example, - after advice on a method call join point runs after the method body - has run, just before before control is returned to the caller. - Because Java programs can leave a join point 'normally' or by - throwing an exception, there are three kinds of after advice: - <literal>after returning</literal>, <literal>after - throwing</literal>, and plain <literal>after</literal> (which runs - after returning <emphasis>or</emphasis> throwing, like Java's - <literal>finally</literal>). - </para> - -<programlisting><![CDATA[ -after() returning: move() { - System.out.println("just successfully moved"); -} -]]></programlisting> - - <para> - <emphasis>Around advice</emphasis> on a join point runs as the join - point is reached, and has explicit control over whether the program - proceeds with the join point. Around advice is not discussed in - this section. - </para> - - <sect3> - <title>Exposing Context in Pointcuts</title> - - <para> - Pointcuts not only pick out join points, they 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. - </para> - - <para> - An advice declaration has a parameter list (like a method) that - gives names to all the pieces of context that it uses. For - example, the after advice - </para> - -<programlisting><![CDATA[ -after(FigureElement fe, int x, int y) returning: - ...SomePointcut... { - ...SomeBody... -} -]]></programlisting> - - <para> - uses three pieces of exposed context, a - <literal>FigureElement</literal> named fe, and two - <literal>int</literal>s named x and y. - </para> - - <para> - The body of the advice uses the names just like method - parameters, so - </para> - -<programlisting><![CDATA[ -after(FigureElement fe, int x, int y) returning: - ...SomePointcut... { - System.out.println(fe + " moved to (" + x + ", " + y + ")"); -} -]]></programlisting> - - <para> - The advice's pointcut publishes the values for the advice's - arguments. The three primitive pointcuts - <literal>this</literal>, <literal>target</literal> and - <literal>args</literal> are used to publish these values. So now - we can write the complete piece of advice: - </para> - -<programlisting><![CDATA[ -after(FigureElement fe, int x, int y) returning: - call(void FigureElement.setXY(int, int)) - && target(fe) - && args(x, y) { - System.out.println(fe + " moved to (" + x + ", " + y + ")"); -} -]]></programlisting> - - <para> - The pointcut exposes three values from calls to - <function>setXY</function>: the target - <classname>FigureElement</classname> -- which it publishes as - <literal>fe</literal>, so it becomes the first argument to the - after advice -- and the two int arguments -- which it publishes - as <literal>x</literal> and <literal>y</literal>, so they become - the second and third argument to the after advice. - </para> - - <para> - So the advice 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> - - <para> - A named pointcut may have parameters like a piece of advice. - When the named pointcut is used (by advice, or in another named - pointcut), it publishes its context by name just like the - <literal>this</literal>, <literal>target</literal> and - <literal>args</literal> pointcut. So another way to write the - above advice is - </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) returning: setXY(fe, x, y) { - System.out.println(fe + " moved to (" + x + ", " + y + ")."); -} -]]></programlisting> - - </sect3> - </sect2> - -<!-- ============================== --> - - <sect2 id="inter-type-declarations" xreflabel="inter-type-declarations"> - <title>Inter-type declarations</title> - - <para> - Inter-type declarations in AspectJ are declarations that cut across - classes and their hierarchies. They may declare members that cut - across multiple classes, or change the inheritance relationship - between classes. Unlike advice, which operates primarily - dynamically, introduction operates statically, at compile-time. - </para> - - <para> - Consider the problem of expressing a capability shared by some - existing classes that are already part of a class hierarchy, - 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 express the concern in one place, by using inter-type - declarations. The aspect declares the methods and fields that are - necessary to implement the new capability, and associates the - methods and fields to the existing classes. - </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 writing an aspect declaring that the class Point - <classname>Point</classname> has an instance field, - <varname>observers</varname>, that keeps track of the - <classname>Screen</classname> objects that are observing - <classname>Point</classname>s. - </para> - -<programlisting><![CDATA[ -aspect PointObserving { - private Vector Point.observers = new Vector(); - ... -} -]]></programlisting> - - <para> - The <literal>observers</literal> field is private, so only - <classname>PointObserving</classname> can see it. So observers are - added or removed with the static methods - <function>addObserver</function> and - <function>removeObserver</function> on the 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); - } - ... -} -]]></programlisting> - - <para> - Along with this, we can define a pointcut - <function>changes</function> that defines what we want to observe, - and the after advice defines what we want to do when we observe a - change. - </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> - - <para> - 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> - - </sect2> - -<!-- ============================== --> - - <sect2 id="aspects" xreflabel="aspects"> - <title>Aspects</title> - - <para> - Aspects wrap up pointcuts, advice, and inter-type declarations in a - a modular unit of crosscutting implementation. It is defined very - much like a class, and can have methods, fields, and initializers - in addition to the crosscutting members. Because only aspects may - include these crosscutting members, the declaration of these - effects is localized. - </para> - - <para> - Like classes, aspects may be instantiated, but AspectJ controls how - that instantiation happens -- so you can't use Java's - <literal>new</literal> form to build new aspect instances. By - default, each aspect is a singleton, so one aspect instance is - created. This means that advice may use non-static fields of the - aspect, if it needs to keep state around: - </para> - -<programlisting><![CDATA[ -aspect Logging { - OutputStream logStream = System.err; - - before(): move() { - logStream.println("about to move"); - } -} -]]></programlisting> - - <para> - Aspects may also have more complicated rules for instantiation, but - these will be described in a later chapter. - </para> - - </sect2> - </sect1> - -<!-- ============================== --> - - <sect1 id="starting-development" xreflabel="Development Aspects"> - <title>Development Aspects</title> - - <para> - The next two 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. - </para> - - <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 id="tracing" xreflabel="tracing"> - <title>Tracing</title> - - <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> - </sect2> - - <sect2 id="profiling-and-logging" xreflabel="profiling-and-logging"> - <title>Profiling and Logging</title> - - <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 counts 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> - In effect, this aspect allows the programmer to ask very specific - questions like - - <blockquote> - How many times is the <function>rotate</function> - method defined on <classname>Line</classname> objects called? - </blockquote> - - and - - <blockquote> - How many times are methods defined on - <classname>Point</classname> objects whose name begins with - "<function>set</function>" called in fulfilling those rotate - calls? - </blockquote> - - questions it may be difficult to express using standard - profiling or logging tools. - </para> - - </sect2> - -<!-- ============================== --> - - <sect2 id="pre-and-post-conditions" xreflabel="pre-and-post-conditions"> - <title>Pre- and Post-Conditions</title> - - <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 id="contract-enforcement" xreflabel="contract-enforcement"> - <title>Contract Enforcement</title> - - <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[ -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> - - <para> - This advice throws a runtime exception at certain join points, but - AspectJ can do better. Using the <literal>declare error</literal> - form, we can have the <emphasis>compiler</emphasis> signal the - error. - </para> - -<programlisting><![CDATA[ -aspect RegistrationProtection { - - pointcut register(): call(void Registry.register(FigureElement)); - pointcut canRegister(): withincode(static * FigureElement.make*(..)); - - declare error: register() && !canRegister(): "Illegal call" -} -]]></programlisting> - - <para> - When using this aspect, it is impossible for the compiler to - compile programs with these illegal calls. This early detection is - not always possible. In this case, since we depend only on static - information (the <literal>withincode</literal> pointcut picks out - join points totally based on their code, and the - <literal>call</literal> pointcut here picks out join points - statically). Other enforcement, such as the precondition - enforcement, above, does require dynamic information such as the - runtime value of parameters. - </para> - </sect2> - -<!-- ============================== --> - - <sect2 id="configuration-management" xreflabel="configuration-management"> - <title>Configuration Management</title> - - <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="starting-production" xreflabel="Production Aspects"> - <title>Production Aspects</title> - - <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 id="change-monitoring" xreflabel="change-monitoring"> - <title>Change Monitoring</title> - - <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> (available linked off - of the AspectJ web site -- <ulink - url="https://eclipse.org/aspectj" />), 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="starting-production-consistentBehavior"/>). - </para> - </sect2> - -<!-- ============================== --> - - <sect2 id="context-passing" xreflabel="context-passing"> - <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="starting-production-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.bigboxco</literal> package log any Errors they throw - to their caller (in Java, an Error is like an Exception, but it - indicates that something really bad and usually unrecoverable has - happened). The <function>publicMethodCall</function> pointcut - captures the public method calls of the package, and the after - advice runs whenever one of those calls throws an Error. The advice - logs that Error and then the throw resumes. - </para> - - <programlisting><![CDATA[ -aspect PublicErrorLogging { - Log log = new Log(); - - pointcut publicMethodCall(): - call(public * com.bigboxco.*.*(..)); - - 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.bigboxco</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.bigboxco</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 id="starting-conclusion"> - <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="language"/>, - covers in detail more of 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> diff --git a/docs/progguide/idioms.xml b/docs/progguide/idioms.xml deleted file mode 100644 index c6297c90b..000000000 --- a/docs/progguide/idioms.xml +++ /dev/null @@ -1,74 +0,0 @@ -<chapter id="idioms" xreflabel="Idioms"> - <title>Idioms</title> - - <sect1 id="idioms-intro"> - <title>Introduction</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> - - </sect1> -</chapter> diff --git a/docs/progguide/implementation.xml b/docs/progguide/implementation.xml deleted file mode 100644 index e1fa05f2b..000000000 --- a/docs/progguide/implementation.xml +++ /dev/null @@ -1,377 +0,0 @@ -<appendix id="implementation" xreflabel="Implementation Notes"> - - <title>Implementation Notes</title> - -<sect1> - <title>Compiler Notes</title> - - <para> - The initial implementations of AspectJ have all been - compiler-based implementations. Certain elements of AspectJ's - semantics are difficult to implement without making modifications - to the virtual machine, which a compiler-based implementation - cannot do. 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 bytecode 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 or Client.class is compiled as well. It - also means that join points associated with code in native methods - (including their execution join points) cannot be advised. - </para> - - <para> - Different join points have different requirements. Method and - constructor call join points can be advised only if ajc controls - the bytecode for the caller. Field reference or assignment join - points can be advised only if ajc controls the bytecode for the - "caller", the code actually making the reference or assignment. - Initialization join points can be advised only if ajc controls the - bytecode of the type being initialized, and execution join points - can be advised only if ajc controls the bytecode for the method or - constructor body in question. - The end of an exception handler is underdetermined in bytecode, - so ajc will not implement after or around advice on handler join - points. - Similarly, ajc cannot implement around advice on initialization - or preinitialization join points. - In cases where ajc cannot implement advice, it will emit a - compile-time error noting this as a compiler limitation. - </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 - bytecode 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 unless <literal>Object</literal>is part - of the compile. 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 - bytecode 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> unless - <literal>java.lang.String</literal> is part of the compile. - </para> - <para> - When declaring members on interfaces, the implementation must - control both the interface and the top-level implementors of - that interface (the classes that implement the interface but - do not have a superclass that implements the interface). - You may weave these separately, but be aware that you will get - runtime exceptions if you run the affected top-level classes - without the interface as produced by the same ajc implementation. - Any intertype declaration of an abstract method on an interface - must be specified as public, you will get a compile time error - message indicating this is a compiler limitation if you do not - specify public. A non-abstract method declared on an interface - can use any access modifier except protected. Note that this is - different to normal Java rules where all members declared in - an interface are implicitly public. - Finally, note that one cannot define static fields or methods - on interfaces. - </para> - <para> - When declaring methods on target types, only methods declared - public are recognizable in the bytecode, so methods must be - declared public to be overridden in any subtype or to be called - from code in a later compile using the target type as a library. - </para> - - <para> - Other AspectJ implementations, indeed, future versions of ajc, may - define <emphasis>code the implementation controls</emphasis> more - liberally or restrictively, so long as they comport with the Java - language. For example, the <literal>call</literal> pointcut does - not pick out reflective calls to a method implemented in - <literal>java.lang.reflect.Method.invoke(Object, Object[])</literal>. - Some suggest that the call "happens" and the call pointcut should - pick it out, but the AspectJ language shouldn't anticipate what happens - in code outside the control of the implementation, even when it - is a a well-defined API in a Java standard library. - </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> -</sect1> - -<sect1> - <title>Bytecode Notes</title> - - <sect2 id="the-class-expression-and-string" xreflabel="the-class-expression-and-string"> - <title>The .class expression and String +</title> - - <para> The java language form <literal>Foo.class</literal> is - implemented in bytecode with a call to - <literal>Class.forName</literal> guarded by an exception - handler catching a <literal>ClassNotFoundException</literal>. - </para> - - <para> The java language + operator, when applied to String - arguments, is implemented in bytecode by calls to - <literal>StringBuffer.append</literal>. - </para> - - <para> In both of these cases, the current AspectJ compiler - operates on the bytecode implementation of these language - features; in short, it operates on what is really happening rather - than what was written in source code. This means that there may - be call join points to <literal>Class.forName</literal> or - <literal>StringBuffer.append</literal> from programs that do not, - at first glance, appear to contain such calls: - </para> - -<programlisting><![CDATA[ -class Test { - void main(String[] args) { - System.out.println(Test.class); // calls Class.forName - System.out.println(args[0] + args[1]); // calls StringBuffer.append - } -} -]]></programlisting> - - <para>In short, the join point model of the current AspectJ - compiler considers these as valid join points. - </para> - - </sect2> - - <sect2 id="the-handler-join-point" xreflabel="the-handler-join-point"> - <title>The Handler join point</title> - - - <para>The end of exception handlers cannot reliably be found in Java - bytecode. Instead of removing the handler join point entirely, the - current AspectJ compiler restricts what can be done with the handler - join point: - </para> - - <itemizedlist> - <listitem>After and around advice cannot apply to handler - join points.</listitem> - - <listitem>The control flow of a handler join point cannot be - detected. </listitem> - </itemizedlist> - - <para> - The first of these is relatively straightforward. If any piece of - after advice (returning, throwing, or "finally") would normally - apply to a handler join point, it will not in code output by the - current AspectJ compiler. A compiler warning is generated whenever - this is detected to be the case. Before advice is allowed. - </para> - - <para> The second is that the control flow of a handler join point - is not picked out. For example, the following pointcut - </para> - -<programlisting><![CDATA[ -cflow(call(void foo()) || handler(java.io.IOException)) -]]></programlisting> - - <para> will capture all join points in the control flow of a call to - <literal>void foo()</literal>, but it will <emphasis>not</emphasis> - capture those in the control flow of an - <literal>IOException</literal> handler. It is equivalent to - <literal>cflow(call(void foo()))</literal>. In general, - <literal>cflow(handler(<replaceable>Type</replaceable>))</literal> - will not pick out any join points, the one exception to this is join points - that occur during the execution of any before advice on the handler. - </para> - - <para> This does not restrict programs from placing before advice on - handlers inside <emphasis>other</emphasis> control flows. This - advice, for example, is perfectly fine: - </para> - -<programlisting><![CDATA[ -before(): handler(java.io.IOException) && cflow(void parse()) { - System.out.println("about to handle an exception while parsing"); -} -]]></programlisting> - - <para> - A source-code implementation of AspectJ (such as AspectJ 1.0.6) is - able to detect the endpoint of a handler join point, and as such - will likely have fewer such restrictions. - </para> - - </sect2> - - <sect2 id="initializers-and-inter-type-constructors" xreflabel="initializers-and-inter-type-constructors"> - <title>Initializers and Inter-type Constructors</title> - - <para> - The code for Java initializers, such as the assignment to the - field d in - </para> - -<programlisting><![CDATA[ -class C { - double d = Math.sqrt(2); -} -]]></programlisting> - - <para> - are considered part of constructors by the time AspectJ gets ahold - of bytecode. That is, the assignment of d to the square root of - two happens <emphasis>inside</emphasis> the default constructor of - C. - </para> - - <para> - Thus inter-type constructors will not necessarily run a target - type's initialization code. In particular, if the inter-type - constructor calls a super-constructor (as opposed to a - <literal>this</literal> constructor), the target type's - initialization code will <emphasis>not</emphasis> be run when that - inter-type constructor is called. - </para> - -<programlisting><![CDATA[ -aspect A { - C.new(Object o) {} // implicitly calls super() - - public static void main(String[] args) { - System.out.println((new C() ).d); // prints 1.414... - System.out.println((new C(null)).d); // prints 0.0 -} -]]></programlisting> - - <para> - It is the job of an inter-type constructor to do all the required - initialization, or to delegate to a <literal>this</literal> - constructor if necessary. - </para> - </sect2> -</sect1> - -<sect1> - <title>Annotation-style Notes</title> - <para>Writing aspects in annotation-style is subject to the same - bytecode limitations since the binary aspects take the same - form and are woven in the same way. However, the implementation - differences (e.g., the mechanism for implementing around advice) - may be apparent at runtime. See the documentation on annotation-style - for more information. - </para> -</sect1> -<sect1> - <title>Summary of implementation requirements</title> - <para> - This summarizes the requirements of our implementation of AspectJ. - For more details, see the relevant sections of this guide. - </para> - <itemizedlist spacing="compact"> - <listitem> - <para>The invoking code must be under the control of ajc - for the following join points:</para> - <itemizedlist spacing="compact"> - <listitem>call join point</listitem> - <listitem>get join point</listitem> - <listitem>set join point</listitem> - </itemizedlist> - </listitem> - <listitem> - <para>The declaring/target code must be under the control of ajc - for the following join points and inter-type declarations:</para> - <itemizedlist spacing="compact"> - <listitem>execution join point</listitem> - <listitem>adviceexecution join point</listitem> - <listitem>handler join point</listitem> - <listitem>initialization join point</listitem> - <listitem>preinitialiaztion join point</listitem> - <listitem>staticinitialization join point</listitem> - <listitem>perthis aspect</listitem> - <listitem>pertarget aspect</listitem> - <listitem>declare parents</listitem> - <listitem>declare method or field (see interface caveats below)</listitem> - </itemizedlist> - </listitem> - <listitem> - <para>Implementation Caveats</para> - <itemizedlist spacing="compact"> - <listitem> - <para>The initialization and preinitialization join points - do not support around advice</para> - </listitem> - <listitem> - <para>The handler join point does not support...</para> - <itemizedlist spacing="compact"> - <listitem>after advice</listitem> - <listitem>around advice</listitem> - <listitem>cflow(handler(..))</listitem> - </itemizedlist> - </listitem> - <listitem> - <para>Declaring members on an interface in an aspect affects only - the topmost implementing classes the implementation controls.</para> - </listitem> - <listitem> - <para>cflow and cflowbelow pointcuts work within a single thread.</para> - </listitem> - <listitem> - <para> - Runtime <literal>ClassCastException</literal> may result - from supplying a supertype of the actual type as an argument - to proceed(..) in around advice.</para> - </listitem> - </itemizedlist> - </listitem> - </itemizedlist> -</sect1> -</appendix> - - - diff --git a/docs/progguide/language.xml b/docs/progguide/language.xml deleted file mode 100644 index 48b0fa62d..000000000 --- a/docs/progguide/language.xml +++ /dev/null @@ -1,1354 +0,0 @@ -<chapter id="language" xreflabel="The AspectJ Language"> - - <title>The AspectJ Language</title> - - <sect1 id="language-intro"> - <title>Introduction</title> - - <para> - The previous chapter, <xref linkend="starting" />, 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="language-anatomy"> - <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 id="an-example-aspect" xreflabel="an-example-aspect"> - <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 inter-type - field on <literal>Server</literal> (line 03), two methods (lines - 05-07 and 09-11), one pointcut definition (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 of other program entities, - ordinary variables and methods, pointcut definitions, inter-type declarations, - 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 id="pointcuts" xreflabel="pointcuts"> - <title>Pointcuts</title> - - <para> - AspectJ's pointcut definitions give names to pointcuts. Pointcuts - themselves pick out join points, i.e. interesting points in the - execution of a program. These join points can be method or - constructor invocations and executions, the handling of exceptions, - field assignments and accesses, etc. Take, for example, the - pointcut definition 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 - <literal>Server</literal> objects have their public methods called. - It also allows anyone using the <literal>services</literal> - pointcut to access the <literal>Server</literal> object whose - method is being 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 <literal>Server</literal>. 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 - <literal>public</literal>. - </para> - - <para> - Pointcuts pick out arbitrarily large numbers of join points of a - program. But they pick out only a small number of - <emphasis>kinds</emphasis> of join points. Those kinds of join - points correspond to some of the most important concepts in - Java. Here is an incomplete list: method call, method execution, - exception handling, instantiation, constructor execution, and - field access. Each kind of join point can be picked out by its - own specialized pointcut that you will learn about in other parts - of this guide. - </para> - </sect2> - -<!-- ============================== --> - -<!-- ============================== --> - - <sect2 id="advice" xreflabel="advice"> - <title>Advice</title> - - <para> - A piece of advice brings together a pointcut and a body of code to - define aspect implementation that runs at join points picked out by - the 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 <literal>Server</literal> class - have their public methods called, as specified by the pointcut - <literal>services</literal>. 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 after those operations throw - exception of type <literal>FaultException</literal>. - </para> - - <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> - </sect2> - - </sect1> - -<!-- ============================== --> - - <sect1 id="language-joinPoints"> - <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 join points - and 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> - This piece of program says that when method named - <literal>setX</literal> with an <literal>int</literal> argument - called on an object of type <literal>Point</literal>, then the method - body <literal>{ this.x = x; }</literal> is executed. Similarly, the - constructor of the class states that when an object of type - <literal>Point</literal> is instantiated through a constructor with - two <literal>int</literal> arguments, then the constructor body - <literal>{ this.x = x; this.y = y; }</literal> is executed. - </para> - - <para> - One pattern that emerges from these descriptions is - - <blockquote> - When something happens, then something gets executed. - </blockquote> - - 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 consist of things like method calls, - method executions, object instantiations, constructor executions, - field references and handler executions. (See the <xref - linkend="quick" /> for a 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> - picks out each call to <literal>setX(int)</literal> or - <literal>setY(int)</literal> when called on an instance of - <literal>Point</literal>. Here's another example: - </para> - -<programlisting><![CDATA[ -pointcut ioHandler(): within(MyClass) && handler(IOException); -]]></programlisting> - - <para> - This pointcut picks out each the join point when exceptions of type - <literal>IOException</literal> are handled inside the code defined by - class <literal>MyClass</literal>. - </para> - - <para> - Pointcut definitions consist of a left-hand side and a right-hand side, - separated by a colon. The left-hand side consists of the pointcut name - and the pointcut parameters (i.e. the data available when the events - happen). The right-hand side consists of the pointcut itself. - </para> - - <sect2 id="some-example-pointcuts" xreflabel="some-example-pointcuts"> - <title>Some Example Pointcuts</title> - - <para> - Here are examples of pointcuts picking out - </para> - - <variablelist> - <varlistentry> - <term>when a particular method body executes</term> - <listitem> - <para> - <literal>execution(void Point.setX(int))</literal> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term>when a method is called</term> - <listitem> - <para> - <literal>call(void Point.setX(int))</literal> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term>when an exception handler executes</term> - <listitem> - <para> - <literal>handler(ArrayOutOfBoundsException)</literal> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - when the object currently executing - (i.e. <literal>this</literal>) is of type - <literal>SomeType</literal> - </term> - <listitem> - <para> - <literal>this(SomeType)</literal> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - when the target object is of type <literal>SomeType</literal> - </term> - <listitem> - <para> - <literal>target(SomeType)</literal> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - when the executing code belongs to - class <literal>MyClass</literal> - </term> - <listitem> - <para> - <literal>within(MyClass)</literal> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - when the join point is in the control flow of a call to a - <literal>Test</literal>'s no-argument <literal>main</literal> - method - </term> - <listitem> - <para> - <literal>cflow(call(void Test.main()))</literal> - </para> - </listitem> - </varlistentry> - </variablelist> - - <para> - Pointcuts 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) the execution of any method regardless of return or - parameter types, and (2) the call to any method named - <literal>set</literal> regardless of return or parameter types - -- in case of overloading there may be more than one such - <literal>set</literal> method; this pointcut picks out calls to - 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) the execution of any method with no parameters that - returns an <literal>int</literal>, (2) the call to any - <literal>setY</literal> method that takes a - <literal>long</literal> as an argument, regardless of return - type or declaring type, (3) the call to any of - <literal>Point</literal>'s <literal>setY</literal> methods that - take an <literal>int</literal> as an argument, regardless of - return type, and (4) the call to any classes' constructor, so - long as it takes exactly two <literal>int</literal>s as - arguments. - </para> - </listitem> - - <listitem> - <para> - You can compose pointcuts. 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(Point) <![CDATA[&&]]> call(int *(..)) - </literal> - </para> - </listitem> - </orderedlist> - - means (1) any call to an <literal>int</literal> method with no - arguments on an instance of <literal>Point</literal>, - regardless of its name, (2) any call to any method where the - call is made from the code in <literal>Point</literal>'s or - <literal>Line</literal>'s type declaration, (3) the execution of - any constructor taking exactly one <literal>int</literal> - argument, regardless of where the call is made from, and - (4) any method call to an <literal>int</literal> method when - the executing object is any type except <literal>Point</literal>. - </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) any call to a public method, (2) any - execution of a non-static method, and (3) any execution of a - public, non-static method. - </para> - </listitem> - - <listitem> - <para> - Pointcuts can also deal with interfaces. For example, given the - interface </para> - -<programlisting><![CDATA[ -interface MyInterface { ... } -]]></programlisting> - - <para> - the pointcut <literal>call(* MyInterface.*(..))</literal> picks - out any call to a method in <literal>MyInterface</literal>'s - signature -- that is, any method defined by - <literal>MyInterface</literal> or inherited by one of its a - supertypes. - </para> - </listitem> - - </itemizedlist> - </sect2> - - <sect2 id="call-vs-execution" xreflabel="call-vs-execution"> - <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 - <literal>call</literal> and <literal>execution</literal> pointcuts. - </para> - - <para> - So what's the difference between these join points? 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 code is that of - the call site. This means that <literal>call(void m()) - <![CDATA[&&]]> withincode(void m())</literal> will only capture - directly recursive calls, for example. At an execution join point, - however, the program is already executing the method, so the - enclosing code is the method itself: <literal>execution(void m()) - <![CDATA[&&]]> withincode(void m())</literal> is the same as - <literal>execution(void m())</literal>. - </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 (as is often the case for - tracing), use <literal>execution</literal>, but if you want to pick - one that runs when a particular <emphasis>signature</emphasis> is - called (as is often the case for production aspects), use - <literal>call</literal>. - </para> - </sect2> - -<!-- ============================== --> - - <sect2 id="pointcut-composition" xreflabel="pointcut-composition"> - <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 <literal>cflow</literal> - and <literal>cflowbelow</literal>. Here's an example: - </para> - - <para> - <literal>cflow(<replaceable>P</replaceable>)</literal> picks out - each join point 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 each join point that is 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> and 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() && !within(A) { - System.out.println("should occur"); - } - - before(): cflow(fooPC() && gooPC()) && printPC() && !within(A) { - System.out.println("should not occur"); - } -} -]]></programlisting> - - <para> - The <literal>!within(<replaceable>A</replaceable>)</literal> - pointcut above is required to avoid the <literal>printPC</literal> - pointcut applying to the <literal>System.out.println</literal> - call in the advice body. If this was not present a recursive call - would result as the pointcut would apply to its own advice. - (See <xref linkend="pitfalls-infiniteLoops"/> for more details.) - </para> - - </sect2> - -<!-- ============================== --> - - <sect2 id="pointcut-parameters" xreflabel="pointcut-parameters"> - <title>Pointcut Parameters</title> - - <para> - Consider again the first pointcut definition in this chapter: - </para> - -<programlisting><![CDATA[ -pointcut setter(): target(Point) && - (call(void setX(int)) || - call(void setY(int))); -]]></programlisting> - - <para> - As we've seen, this pointcut picks out each call to - <literal>setX(int)</literal> or <literal>setY(int)</literal> - methods where the target is an instance of - <literal>Point</literal>. The pointcut is given the name - <literal>setters</literal> and no parameters on the left-hand - side. An empty parameter list means that none of the context from - the join points is published from this pointcut. But consider - another version of version of this pointcut definition: - </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 join points. But in this - version, the pointcut has one parameter of type - <literal>Point</literal>. This means that any advice that uses this - pointcut has access to a <literal>Point</literal> from each join - point picked out by the pointcut. Inside the pointcut definition - this <literal>Point</literal> is named <literal>p</literal> is - available, and according to the right-hand side of the definition, - that <literal>Point p</literal> comes from the - <literal>target</literal> of each matched join point. - </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>. Similar to the - <literal>setters</literal> pointcut, this means that anyone using - this pointcut has access to a <literal>Point</literal> from each - join point. 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 (also of type <literal>Point</literal>) passed to the - <literal>equals</literal> method when some other - <literal>Point</literal> is the target. If we wanted access to both - <literal>Point</literal>s, then the pointcut definition that would - expose 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 <literal>setters</literal> 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 - <literal>int</literal> value are exposed by the named - pointcut. Looking at the the right-hand side of the definition, we - find that the <literal>Point</literal> object is the target object, - and the <literal>int</literal> value is the called method's - argument. - </para> - - <para> - The use of pointcut parameters is relatively flexible. The most - important rule is that all the pointcut parameters must be bound at - every join point picked out by the pointcut. So, for example, the - following pointcut definition will result in a compilation error: - -<programlisting><![CDATA[ -pointcut badPointcut(Point p1, Point p2): - (target(p1) && call(void setX(int))) || - (target(p2) && call(void setY(int))); -]]></programlisting> - - because <literal>p1</literal> is only bound when calling - <literal>setX</literal>, and <literal>p2</literal> is only bound - when calling <literal>setY</literal>, but the pointcut picks out - all of these join points and tries to bind both - <literal>p1</literal> and <literal>p2</literal>. - </para> - </sect2> - -<!-- ============================== --> - - <sect2 id="example" xreflabel="example"> - <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> - - <sect2 id="pointcut-best-practice" xreflabel="pointcut-best-practice"> - <title>Writing good pointcuts</title> - - <para> - During compilation, AspectJ processes pointcuts in order to try and optimize matching performance. Examining code and determining - if each join point matches (statically or dynamically) a given pointcut is a costly process. - (A dynamic match means the match cannot be fully determined from static analysis and a test will be placed in the code - to determine if there is an actual match when the code is running). - On first encountering a pointcut declaration, AspectJ will rewrite it into an optimal form for the matching process. - What does this mean? Basically pointcuts are rewritten in DNF (Disjunctive Normal Form) and the components of the pointcut - are sorted such that those components that are cheaper to evaluate are checked first. This means users do not have to worry - about understanding the performance of various pointcut designators and may supply them in any order in their - pointcut declarations. - </para> - <para> - However, AspectJ can only work with what it is told, and for optimal performance of matching the user should think - about what they are trying to achieve and narrow the search space for matches as much as they can in the definition. - Basically there are three kinds of pointcut designator: kinded, scoping and context: - </para> - <itemizedlist> - <listitem> - Kinded designators are those which select a particular kind of join point. For example: execution, get, set, call, handler - </listitem> - <listitem> - Scoping designators are those which select a group of join points of interest (of probably many kinds). For example: within, withincode - </listitem> - <listitem> - Contextual designators are those that match (and optionally bind) based on context. For example: this, target, @annotation - </listitem> - </itemizedlist> - <para> - A well written pointcut should - try and include at least the first two types (kinded and scoping), whilst the contextual designators may be included if wishing to - match based on join point context, or bind that context for use in the advice. Supplying either just a kinded designator or - just a contextual designator will work but could affect weaving performance (time and memory used) - due to all the extra processing and analysis. - Scoping designators are very fast to match, they can very quickly dismiss groups of join points that should not be further - processed - that is why a good pointcut should always include one if possible. - </para> - - </sect2> - </sect1> - -<!-- ============================== --> - - <sect1 id="language-advice"> - <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> - - <para> - This before advice runs just before the join points picked out by the - (anonymous) pointcut: - </para> - -<programlisting><![CDATA[ -before(Point p, int x): target(p) && args(x) && call(void setX(int)) { - if (!p.assertX(x)) return; -} -]]></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, int x): target(p) && args(x) && call(void setX(int)) { - if (!p.assertX(x)) throw new PostConditionViolation(); -} -]]></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(Point p) returning(int x): target(p) && call(int getX()) { - System.out.println("Returning int value " + x + " for p = " + p); -} -]]></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[ -after() throwing(Exception e): target(Point) && call(void setX(int)) { - System.out.println(e); -} -]]></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> - -<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> - </sect1> - -<!-- ============================== --> - - <sect1 id="language-interType"> - <title>Inter-type declarations</title> - - <para> - Aspects can declare members (fields, methods, and constructors) that - are owned by other types. These are called inter-type members. - Aspects can also declare that other types implement new interfaces or - extend a new class. Here are examples of some such inter-type - declarations: - </para> - - <para> - This declares that each <literal>Server</literal> has a - <literal>boolean</literal> field named <literal>disabled</literal>, - initialized to <literal>false</literal>: - -<programlisting><![CDATA[ -private boolean Server.disabled = false; -]]></programlisting> - - It is declared <literal>private</literal>, which means that it is - private <emphasis>to the aspect</emphasis>: only code in the aspect - can see the field. And even if <literal>Server</literal> has - another private field named <literal>disabled</literal> (declared in - <literal>Server</literal> or in another aspect) there won't be a name - collision, since no reference to <literal>disabled</literal> will be - ambiguous. - </para> - - <para> - This declares that each <literal>Point</literal> has an - <literal>int</literal> method named <literal>getX</literal> with no - arguments that returns whatever <literal>this.x</literal> is: - -<programlisting><![CDATA[ -public int Point.getX() { return this.x; } -]]></programlisting> - - Inside the body, <literal>this</literal> is the - <literal>Point</literal> object currently executing. Because the - method is publically declared any code can call it, but if there is - some other <literal>Point.getX()</literal> declared there will be a - compile-time conflict. - </para> - - <para> - This publically declares a two-argument constructor for - <literal>Point</literal>: - -<programlisting><![CDATA[ -public Point.new(int x, int y) { this.x = x; this.y = y; } -]]></programlisting> - - </para> - - <para> - This publicly declares that each <literal>Point</literal> has an - <literal>int</literal> field named <literal>x</literal>, initialized - to zero: - -<programlisting><![CDATA[ -public int Point.x = 0; -]]></programlisting> - - Because this is publically declared, it is an error if - <literal>Point</literal> already has a field named - <literal>x</literal> (defined by <literal>Point</literal> or by - another aspect). - </para> - - <para> - This declares that the <literal>Point</literal> class implements the - <literal>Comparable</literal> interface: - -<programlisting><![CDATA[ -declare parents: Point implements Comparable; -]]></programlisting> - - Of course, this will be an error unless <literal>Point</literal> - defines the methods required by <literal>Comparable</literal>. - </para> - - <para> - This declares that the <literal>Point</literal> class extends the - <literal>GeometricObject</literal> class. - -<programlisting><![CDATA[ -declare parents: Point extends GeometricObject; -]]></programlisting> - </para> - - <para> - An aspect can have several inter-type declarations. For example, the - following declarations - -<programlisting><![CDATA[ -public String Point.name; -public void Point.setName(String name) { this.name = name; } -]]></programlisting> - - publicly declare that Point has both a String field - <literal>name</literal> and a <literal>void</literal> method - <literal>setName(String)</literal> (which refers to the - <literal>name</literal> field declared by the aspect). - </para> - - <para> - An inter-type member can only have one target type, but often you may - wish to declare the same member on more than one type. This can be - done by using an inter-type member in combination with a private - interface: - -<programlisting><![CDATA[ -aspect A { - private interface HasName {} - declare parents: (Point || Line || Square) implements HasName; - - private String HasName.name; - public String HasName.getName() { return name; } -} -]]></programlisting> - - This declares a marker interface <literal>HasName</literal>, and also declares that any - type that is either <literal>Point</literal>, - <literal>Line</literal>, or <literal>Square</literal> implements that - interface. It also privately declares that all <literal>HasName</literal> - object have a <literal>String</literal> field called - <literal>name</literal>, and publically declares that all - <literal>HasName</literal> objects have a <literal>String</literal> - method <literal>getName()</literal> (which refers to the privately - declared <literal>name</literal> field). - </para> - - <para> - As you can see from the above example, an aspect can declare that - interfaces have fields and methods, even non-constant fields and - methods with bodies. - </para> - -<!-- ============================== --> - - <sect2 id="inter-type-scope" xreflabel="inter-type-scope"> - <title>Inter-type Scope</title> - - <para> - AspectJ allows private and package-protected (default) inter-type declarations in - addition to public inter-type declarations. Private means private in - relation to the aspect, not necessarily the target type. So, if an - aspect makes a private inter-type declaration of a field - -<programlisting><![CDATA[ -private int Foo.x; -]]></programlisting> - - Then code in the aspect can refer to <literal>Foo</literal>'s - <literal>x</literal> 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 or may not be - <literal>Foo</literal>'s package) can access <literal>x</literal>. - </para> - </sect2> - -<!-- ============================== --> - - <sect2 id="example-pointassertions" xreflabel="example-pointassertions"> - <title>Example: <literal>PointAssertions</literal></title> - - <para> - The example below consists of one class and one aspect. The aspect - privately declares the assertion methods of - <literal>Point</literal>, <literal>assertX</literal> and - <literal>assertY</literal>. It also guards calls to - <literal>setX</literal> and <literal>setY</literal> with calls to - these assertion methods. The assertion methods are declared - privately because other parts of the program (including the code in - <literal>Point</literal>) 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 id="language-thisJoinPoint"> - <title>thisJoinPoint</title> - - <para> - AspectJ provides a special reference variable, - <literal>thisJoinPoint</literal>, that contains reflective - information about the current join point for the advice to use. The - <literal>thisJoinPoint</literal> variable can only be used in the - context of advice, just like <literal>this</literal> can only be used - in the context of non-static methods and variable initializers. In - advice, <literal>thisJoinPoint</literal> is an object of type <ulink - url="../api/org/aspectj/lang/JoinPoint.html"><literal>org.aspectj.lang.JoinPoint</literal></ulink>. - </para> - - <para> - One way to use it is simply to print it out. Like all Java objects, - <literal>thisJoinPoint</literal> has a <literal>toString()</literal> - method that makes quick-and-dirty tracing easy: - </para> - -<programlisting><![CDATA[ -aspect TraceNonStaticMethods { - before(Point p): target(p) && call(* *(..)) { - System.out.println("Entering " + thisJoinPoint + " in " + p); - } -} -]]></programlisting> - - <para> - The type of <literal>thisJoinPoint</literal> includes a rich - reflective class hierarchy of signatures, and can be used to access - both static and dynamic information about join points such as the - arguments of the join point: - -<programlisting><![CDATA[ -thisJoinPoint.getArgs() -]]></programlisting> - - In addition, it holds an object consisting of all the static - information about the join point such as corresponding line number - and static signature: - -<programlisting><![CDATA[ -thisJoinPoint.getStaticPart() -]]></programlisting> - - If you only need the static information about the join point, you may - access the static part of the join point directly with the special - variable <literal>thisJoinPointStaticPart</literal>. Using - <literal>thisJoinPointStaticPart</literal> will avoid the run-time - creation of the join point object that may be necessary when using - <literal>thisJoinPoint</literal> directly. - </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> - diff --git a/docs/progguide/pitfalls.xml b/docs/progguide/pitfalls.xml deleted file mode 100644 index daf08f801..000000000 --- a/docs/progguide/pitfalls.xml +++ /dev/null @@ -1,112 +0,0 @@ -<chapter id="pitfalls" xreflabel="Pitfalls"> - <title>Pitfalls</title> - - <sect1 id="pitfalls-intro"> - <title>Introduction</title> - - <para> - This chapter consists of a few AspectJ programs that may lead to - surprising behavior and how to understand them. - </para> - - </sect1> - - <sect1 id="pitfalls-infiniteLoops"> - <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 - may 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> diff --git a/docs/progguide/preface.xml b/docs/progguide/preface.xml deleted file mode 100644 index 5484fe5b3..000000000 --- a/docs/progguide/preface.xml +++ /dev/null @@ -1,66 +0,0 @@ -<preface id="preface"> - <title>Preface</title> - - <para> - This programming 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> - - It includes appendices that give a reference to the syntax of AspectJ, - a more formal description of AspectJ's semantics, and a description of - notes about the AspectJ implementation. - </para> - - <para> - The first section, <xref linkend="starting" />, 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="language" />, covers the features of - the language in more detail, using code snippets as examples. All the - basics of the language is covered, and after reading this section, you - should be able to use 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> - Finally, there are two short chapters, one on <xref linkend="idioms" /> - and one on <xref linkend="pitfalls" />. - </para> - - <para> - The back matter contains several appendices that cover a <xref - linkend="quick">quick reference</xref> to the language's syntax, a more - in depth coverage of its <xref linkend="semantics">semantics</xref>, - and a description of the latitude enjoyed by its <xref - linkend="implementation">implementations</xref>. - </para> - -</preface> diff --git a/docs/progguide/progguide.html.xsl b/docs/progguide/progguide.html.xsl deleted file mode 100644 index 7f6a669fb..000000000 --- a/docs/progguide/progguide.html.xsl +++ /dev/null @@ -1,9 +0,0 @@ -<xsl:stylesheet version="1.0" - xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> - -<xsl:import href="../../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/progguide/progguide.xml b/docs/progguide/progguide.xml deleted file mode 100644 index 433d71585..000000000 --- a/docs/progguide/progguide.xml +++ /dev/null @@ -1,63 +0,0 @@ -<?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 implementation SYSTEM "implementation.xml"> -]> - -<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-2003 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="starting"/> 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="language"/> 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; - &implementation; - -</book> diff --git a/docs/progguide/quickreference.xml b/docs/progguide/quickreference.xml deleted file mode 100644 index ef5c3cb80..000000000 --- a/docs/progguide/quickreference.xml +++ /dev/null @@ -1,773 +0,0 @@ -<appendix id="quick" xreflabel="AspectJ Quick Reference"> - <title>AspectJ Quick Reference</title> - - <sect1 id="quick-pointcuts"> - <title>Pointcuts</title> - - <informaltable frame="none"> - <tgroup cols="2" align="left"> - <colspec colname="c1"/> - <colspec colname="c2"/> - - <tbody valign="top"> - <row> - <entry namest="c1" nameend="c2"> - <emphasis role="bold">Methods and Constructors</emphasis> - </entry> - </row> - - <row> - <entry> - <literal>call(<replaceable>Signature</replaceable>)</literal> - </entry> - - <entry> - every call to any method or constructor matching - <replaceable>Signature</replaceable> at the call site - </entry> - </row> - - <row> - <entry> - <literal>execution(<replaceable>Signature</replaceable>)</literal> - </entry> - - <entry> - every execution of any method or constructor matching - <replaceable>Signature</replaceable> - </entry> - </row> - - - <!-- ===== --> - <row> - <entry namest="c1" nameend="c2"> - <emphasis role="bold">Fields</emphasis> - </entry> - </row> - - <row> - <entry> - <literal>get(<replaceable>Signature</replaceable>)</literal> - </entry> - <entry> - every reference to any field matching <replaceable>Signature</replaceable> - </entry> - </row> - - <row> - <entry> - <literal>set(<replaceable>Signature</replaceable>)</literal> - </entry> - <entry> - every assignment to any field matching - <replaceable>Signature</replaceable>. The assigned value can - be exposed with an <literal>args</literal> pointcut - </entry> - </row> - - <!-- ===== --> - <row> - <entry namest="c1" nameend="c2"> - <emphasis role="bold">Exception Handlers</emphasis> - </entry> - </row> - - <row rowsep="1"> - <entry> - <literal>handler(<replaceable>TypePattern</replaceable>)</literal> - </entry> - <entry> - every exception handler for any <literal>Throwable</literal> - type in <replaceable>TypePattern</replaceable>. The exception - value can be exposed with an <literal>args</literal> pointcut - </entry> - </row> - - <!-- ===== --> - <row> - <entry namest="c1" nameend="c2"> - <emphasis role="bold">Advice</emphasis> - </entry> - </row> - - <row> - <entry> - <literal>adviceexecution()</literal> - </entry> - <entry> - every execution of any piece of advice - </entry> - </row> - - <!-- ===== --> - <row> - <entry namest="c1" nameend="c2"> - <emphasis role="bold">Initialization</emphasis> - </entry> - </row> - - <row rowsep="1"> - <entry> - <literal>staticinitialization(<replaceable>TypePattern</replaceable>)</literal> - </entry> - <entry> - every execution of a static initializer for any type in - <replaceable>TypePattern</replaceable> - </entry> - </row> - - <row> - <entry> - <literal>initialization(<replaceable>Signature</replaceable>)</literal> - </entry> - <entry> - every initialization of an object when the first constructor - called in the type matches - <replaceable>Signature</replaceable>, encompassing the return - from the super constructor call to the return of the - first-called constructor - </entry> - </row> - <row> - <entry> - <literal>preinitialization(<replaceable>Signature</replaceable>)</literal> - </entry> - <entry> - every pre-initialization of an object when the first - constructor called in the type matches - <replaceable>Signature</replaceable>, encompassing the entry - of the first-called constructor to the call to the super - constructor - </entry> - </row> - - <!-- ===== --> - <row> - <entry namest="c1" nameend="c2"> - <emphasis role="bold">Lexical</emphasis> - </entry> - </row> - - <row> - <entry> - <literal>within(<replaceable>TypePattern</replaceable>)</literal> - </entry> - <entry> - every join point from code defined in a type in - <replaceable>TypePattern</replaceable> - </entry> - </row> - - <row> - <entry> - <literal>withincode(<replaceable>Signature</replaceable>)</literal> - </entry> - <entry> - every join point from code defined in a method or constructor - matching <replaceable>Signature</replaceable> - </entry> - </row> - </tbody> - </tgroup> - - <tgroup cols="2" align="left"> - <colspec colname="c1"/> - <colspec colname="c2"/> - <tbody valign="top"> - <row> - <entry namest="c1" nameend="c2" > - <emphasis role="bold">Instanceof checks and context exposure</emphasis> - </entry> - </row> - - <row> - <entry> - <literal>this(<replaceable>Type</replaceable> or <replaceable>Id</replaceable>)</literal> - </entry> - <entry> - every join point when the currently executing object is an - instance of <replaceable>Type</replaceable> or - <replaceable>Id</replaceable>'s type - </entry> - </row> - - <row> - <entry> - <literal>target(<replaceable>Type</replaceable> or <replaceable>Id</replaceable>)</literal> - </entry> - <entry> - every join point when the target executing object is an - instance of <replaceable>Type</replaceable> or - <replaceable>Id</replaceable>'s type - </entry> - </row> - - <row> - <entry> - <literal>args(<replaceable>Type</replaceable> or - <replaceable>Id</replaceable>, ...)</literal> - </entry> - <entry> - every join point when the arguments are instances of - <replaceable>Type</replaceable>s or the types of the - <replaceable>Id</replaceable>s - </entry> - </row> - - <!-- ===== --> - <row> - <entry namest="c1" nameend="c2"> - <emphasis role="bold">Control Flow</emphasis> - </entry> - </row> - - <row> - <entry> - <literal>cflow(<replaceable>Pointcut</replaceable>)</literal> - </entry> - <entry> - every join point in the control flow of each join point - <replaceable>P</replaceable> picked out by - <replaceable>Pointcut</replaceable>, including - <replaceable>P</replaceable> itself - </entry> - </row> - - <row> - <entry> - <literal>cflowbelow(<replaceable>Pointcut</replaceable>)</literal> - </entry> - <entry> - every join point below the control flow of each join point - <replaceable>P</replaceable> picked out by - <replaceable>Pointcut</replaceable>; does not include - <replaceable>P</replaceable> itself - </entry> - </row> - - <!-- ===== --> - <row> - <entry namest="c1" nameend="c2"> - <emphasis role="bold">Conditional</emphasis> - </entry> - </row> - - <row> - <entry> - <literal>if(<replaceable>Expression</replaceable>)</literal> - </entry> - <entry> - every join point when the boolean - <replaceable>Expression</replaceable> is - <literal>true</literal> - </entry> - </row> - </tbody> - </tgroup> - - <tgroup cols="2" align="left"> - <colspec colname="c1"/> - <colspec colname="c2"/> - - <tbody valign="top"> - <row> - <entry namest="c1" nameend="c2"> - <emphasis role="bold">Combination</emphasis> - </entry> - </row> - - <row> - <entry> - <literal>! <replaceable>Pointcut</replaceable></literal> - </entry> - <entry> - every join point not picked out by - <replaceable>Pointcut</replaceable> - </entry> - </row> - - <row> - <entry> - <literal><replaceable>Pointcut0</replaceable> <![CDATA[&&]]> <replaceable>Pointcut1</replaceable></literal> - </entry> - <entry> - each join point 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> - each join point picked out by either - <replaceable>Pointcut0</replaceable> or - <replaceable>Pointcut1</replaceable> - </entry> - </row> - - <row> - <entry> - <literal>( <replaceable>Pointcut</replaceable> )</literal> - </entry> - <entry> - each join point picked out by - <replaceable>Pointcut</replaceable> - </entry> - </row> - </tbody> - </tgroup> - </informaltable> - </sect1> - -<!-- ============================== --> - - <sect1 id="quick-typePatterns"> - <title>Type Patterns</title> - - <para> - A type pattern is one of - </para> - - <informaltable frame="none"> - <tgroup cols="2" > - <tbody valign="top"> - <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> - </informaltable> - - <para> - where <replaceable>TypeNamePattern</replaceable> can either be a - plain type name, the wildcard <literal>*</literal> (indicating all - types), or an identifier with embedded <literal>*</literal> and - <literal>..</literal> wildcards. - </para> - - <para> - An embedded <literal>*</literal> in an identifier matches any - sequence of characters, but does not match the package (or - inner-type) separator ".". - </para> - - <para> - An embedded <literal>..</literal> in an identifier matches any - sequence of characters that starts and ends with the package (or - inner-type) separator ".". - </para> - </sect1> - -<!-- ============================== --> - - <sect1 id="quick-advice"> - <title>Advice</title> - - <para> - Each piece of advice is of the form - - <blockquote> - <literal>[ strictfp ] <replaceable>AdviceSpec</replaceable> - [ throws <replaceable>TypeList</replaceable> ] : - <replaceable>Pointcut</replaceable> { - <replaceable>Body</replaceable> } </literal> - </blockquote> - - where <replaceable>AdviceSpec</replaceable> is one of - </para> - - <variablelist> - <varlistentry> - <term> - <literal>before( <replaceable>Formals</replaceable> ) </literal> - </term> - <listitem> - runs before each join point - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal>after( <replaceable>Formals</replaceable> ) returning - [ ( <replaceable>Formal</replaceable> ) ] </literal> - </term> - <listitem> - runs after each join point that returns normally. The - optional formal gives access to the returned value - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal>after( <replaceable>Formals</replaceable> ) throwing [ - ( <replaceable>Formal</replaceable> ) ] </literal> - </term> - <listitem> - runs after each join point that throws a - <literal>Throwable</literal>. If the optional formal is - present, runs only after each join point that throws a - <literal>Throwable</literal> of the type of - <replaceable>Formal</replaceable>, and - <replaceable>Formal</replaceable> gives access to the - <literal>Throwable</literal> exception value - </listitem> - </varlistentry> - <varlistentry> - <term> - <literal>after( <replaceable>Formals</replaceable> ) </literal> - </term> - <listitem> - runs after each join point regardless of whether it returns - normally or throws a <literal>Throwable</literal> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal><replaceable>Type</replaceable> - around( <replaceable>Formals</replaceable> ) </literal> - </term> - <listitem> - runs in place of each join point. The join point can be - executed by calling <literal>proceed</literal>, which takes - the same number and types of arguments as the around advice. - </listitem> - </varlistentry> - </variablelist> - - <para> - Three special variables are available inside of advice bodies: - </para> - - <variablelist> - <varlistentry> - <term> - <literal>thisJoinPoint</literal> - </term> - <listitem> - an object of type <ulink - url="../api/org/aspectj/lang/JoinPoint.html"><literal>org.aspectj.lang.JoinPoint</literal></ulink> - representing the join point at which the advice is executing. - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal>thisJoinPointStaticPart</literal> - </term> - <listitem> - equivalent to <literal>thisJoinPoint.getStaticPart()</literal>, - but may use fewer runtime resources. - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal>thisEnclosingJoinPointStaticPart</literal> - </term> - <listitem> - the static part of the dynamically enclosing join point. - </listitem> - </varlistentry> - </variablelist> - </sect1> - -<!-- ============================== --> - - <sect1 id="quick-interType"> - <title>Inter-type member declarations</title> - - <para> - Each inter-type member is one of - </para> - - <variablelist> - <varlistentry> - <term> - <literal> - <replaceable>Modifiers ReturnType OnType . Id</replaceable> - ( <replaceable>Formals</replaceable> ) - [ throws <replaceable>TypeList</replaceable> ] - { <replaceable>Body</replaceable> } - </literal> - </term> - <listitem> - a method on <replaceable>OnType</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal> - abstract <replaceable>Modifiers ReturnType OnType . Id</replaceable> - ( <replaceable>Formals</replaceable> ) - [ throws <replaceable>TypeList</replaceable> ] ; - </literal> - </term> - <listitem> - an abstract method on <replaceable>OnType</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal> - <replaceable>Modifiers OnType . </replaceable> new - ( <replaceable>Formals</replaceable> ) - [ throws <replaceable>TypeList</replaceable> ] - { <replaceable>Body</replaceable> } - </literal> - </term> - <listitem> - a constructor on <replaceable>OnType</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal> - <replaceable>Modifiers Type OnType . Id </replaceable> - [ = <replaceable>Expression</replaceable> ] ; - </literal> - </term> - <listitem> - a field on <replaceable>OnType</replaceable>. - </listitem> - </varlistentry> - </variablelist> - </sect1> - -<!-- ============================== --> - - <sect1 id="quick-other"> - <title>Other declarations</title> - - <variablelist> - <varlistentry> - <term> - <literal> - declare parents : - <replaceable>TypePattern</replaceable> extends - <replaceable>Type</replaceable> ; - </literal> - </term> - <listitem> - the types in <replaceable>TypePattern</replaceable> extend - <replaceable>Type</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal> - declare parents : <replaceable>TypePattern</replaceable> - implements <replaceable>TypeList</replaceable> ; - </literal> - </term> - <listitem> - the types in <replaceable>TypePattern</replaceable> - implement the types in <replaceable>TypeList</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal> - declare warning : <replaceable>Pointcut</replaceable> : - <replaceable>String</replaceable> ; - </literal> - </term> - <listitem> - if any of the join points in <replaceable>Pointcut</replaceable> - possibly exist in the program, the compiler emits the warning - <replaceable>String</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal> - declare error : <replaceable>Pointcut</replaceable> : - <replaceable>String</replaceable> ; - </literal> - </term> - <listitem> - if any of the join points in <replaceable>Pointcut</replaceable> - could possibly exist in the program, the compiler emits the - error <replaceable>String</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term> - <literal> - declare soft : - <replaceable>Type</replaceable> : - <replaceable>Pointcut</replaceable> ; - </literal> - </term> - <listitem> - any <replaceable>Type</replaceable> exception - that gets thrown at any join point picked out by - <replaceable>Pointcut</replaceable> is wrapped in <ulink - url="../api/org/aspectj/lang/SoftException.html"><literal>org.aspectj.lang.SoftException</literal></ulink>. - </listitem> - </varlistentry> - <varlistentry> - <term> - <literal> - declare precedence : - <replaceable>TypePatternList</replaceable> ; - </literal> - </term> - <listitem> - at any join point where multiple pieces of advice - apply, the advice precedence at that join point is in - <replaceable>TypePatternList</replaceable> order. - </listitem> - </varlistentry> - </variablelist> - </sect1> - -<!-- ============================== --> - - <sect1 id="quick-aspectAssociations"> - <title>Aspects</title> - - <para> - Each aspect is of the form - - <blockquote> - <literal> - [ privileged ] <replaceable>Modifiers</replaceable> - aspect <replaceable>Id</replaceable> - [ extends <replaceable>Type</replaceable> ] - [ implements <replaceable>TypeList</replaceable> ] - [ <replaceable>PerClause</replaceable> ] - { <replaceable>Body</replaceable> } - </literal> - </blockquote> - where <replaceable>PerClause</replaceable> defines how the aspect is - instantiated and associated (<literal>issingleton()</literal> by - default): - </para> - - <informaltable frame="none"> - <tgroup cols="3" align="left"> - <thead> - <row> - <entry align="left">PerClause</entry> - <entry align="left">Description</entry> - <entry align="left">Accessor</entry> - </row> - </thead> - - <tbody valign="top"> - <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> - </informaltable> - </sect1> - -</appendix> - diff --git a/docs/progguide/semantics.xml b/docs/progguide/semantics.xml deleted file mode 100644 index 6bba37818..000000000 --- a/docs/progguide/semantics.xml +++ /dev/null @@ -1,3271 +0,0 @@ -<appendix id="semantics" xreflabel="Semantics"> - - <title>Language Semantics</title> - - <sect1 id="semantics-intro"> - <title>Introduction</title> - - <para> - AspectJ extends Java by overlaying a concept of join points onto the - existing Java semantics and adding a few new program elements to Java: - </para> - - <para> - A join point is a well-defined point 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, and others can be named and defined by the - <literal>pointcut</literal> declaration. - </para> - - <para> - A piece of 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> - Inter-type declarations 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. Some inter-type declarations 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> - -<!-- ============================== --> - - <sect1 id="semantics-joinPoints"> - <title>Join Points</title> - - <para> - While aspects define types that crosscut, 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> - - <variablelist> - <varlistentry> - <term>Method call</term> - <listitem> - When a method is called, not including super calls of - non-static methods. - </listitem> - </varlistentry> - - <varlistentry> - <term>Method execution</term> - <listitem> - When the body of code for an actual method executes. - </listitem> - </varlistentry> - - <varlistentry> - <term>Constructor call</term> - <listitem> - When an object is built and that object's initial constructor is - called (i.e., not for "super" or "this" constructor calls). The - object being constructed is returned at a constructor call join - point, so its return type is considered to be the type of the - object, and the object itself may be accessed with <literal>after - returning</literal> advice. - </listitem> - </varlistentry> - - <varlistentry> - <term>Constructor execution</term> - <listitem> - 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. The constructor execution - join point for a constructor that calls a super constructor also - includes any non-static initializers of enclosing class. No - value is returned from a constructor execution join point, so its - return type is considered to be void. - </listitem> - </varlistentry> - - <varlistentry> - <term>Static initializer execution</term> - <listitem> - When the static initializer for a class executes. No value is - returned from a static initializer execution join point, so its - return type is considered to be void. - </listitem> - </varlistentry> - - <varlistentry> - <term>Object pre-initialization</term> - <listitem> - 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 of the - evaluation of the arguments of <literal>this()</literal> and - <literal>super()</literal> constructor calls. No value is - returned from an object pre-initialization join point, so its - return type is considered to be void. - </listitem> - </varlistentry> - - <varlistentry> - <term>Object initialization</term> - <listitem> - 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 a - constructor execution join point, so its return type is - considered to be void. - </listitem> - </varlistentry> - - <varlistentry> - <term>Field reference</term> - <listitem> - When a non-constant field is referenced. [Note that references - to constant fields (static final fields bound to a constant - string object or primitive value) are not join points, since Java - requires them to be inlined.] - </listitem> - </varlistentry> - - <varlistentry> - <term>Field set</term> - <listitem> - When a field is assigned to. - Field set join points are considered to have one argument, - the value the field is being set to. - No value is returned from a field set join point, so - its return type is considered to be void. - [Note that the initializations of constant fields (static - final fields where the initializer is a constant string object or - primitive value) are not join points, since Java requires their - references to be inlined.] - </listitem> - </varlistentry> - - <varlistentry> - <term>Handler execution</term> - <listitem> - When an exception handler executes. - Handler execution join points are considered to have one argument, - the exception being handled. - No value is returned from a field set join point, so - its return type is considered to be void. - </listitem> - </varlistentry> - - <varlistentry> - <term>Advice execution</term> - <listitem> - When the body of code for a piece of advice executes. - </listitem> - </varlistentry> - </variablelist> - - <para> - Each join point potentially has three pieces of state associated - with it: the currently executing object, the target object, and - an object array of arguments. These are exposed by the three - state-exposing pointcuts, <literal>this</literal>, - <literal>target</literal>, and <literal>args</literal>, - respectively. - </para> - - <para> - Informally, the currently executing object is the object that a - <literal>this</literal> expression would pick out at the join - point. The target object is where control or attention is - transferred to by the join point. The arguments are those - values passed for that transfer of control or attention. - </para> - - <informaltable frame="1"> - <tgroup cols="4" align="left"> - <thead valign="top"> - <row> - <entry><emphasis role="bold">Join Point</emphasis></entry> - <entry><emphasis role="bold">Current Object</emphasis></entry> - <entry><emphasis role="bold">Target Object</emphasis></entry> - <entry><emphasis role="bold">Arguments</emphasis></entry> - </row> - </thead> - <tbody> - <row> - <entry>Method Call</entry> - <entry>executing object*</entry> - <entry>target object**</entry> - <entry>method arguments</entry> - </row> - - <row> - <entry>Method Execution</entry> - <entry>executing object*</entry> - <entry>executing object*</entry> - <entry>method arguments</entry> - </row> - <row> - <entry>Constructor Call</entry> - <entry>executing object*</entry> - <entry>None</entry> - <entry>constructor arguments</entry> - </row> - - <row> - <entry>Constructor Execution</entry> - <entry>executing object</entry> - <entry>executing object</entry> - <entry>constructor arguments</entry> - </row> - - <row> - <entry>Static initializer execution</entry> - <entry>None</entry> - <entry>None</entry> - <entry>None</entry> - </row> - <row> - <entry>Object pre-initialization</entry> - <entry>None</entry> - <entry>None</entry> - <entry>constructor arguments</entry> - </row> - <row> - <entry>Object initialization</entry> - <entry>executing object</entry> - <entry>executing object</entry> - <entry>constructor arguments</entry> - </row> - <row> - <entry>Field reference</entry> - <entry>executing object*</entry> - <entry>target object**</entry> - <entry>None</entry> - </row> - <row> - <entry>Field assignment</entry> - <entry>executing object*</entry> - <entry>target object**</entry> - <entry>assigned value</entry> - </row> - <row> - <entry>Handler execution</entry> - <entry>executing object*</entry> - <entry>executing object*</entry> - <entry>caught exception</entry> - </row> - <row> - <entry>Advice execution</entry> - <entry>executing aspect</entry> - <entry>executing aspect</entry> - <entry>advice arguments</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>* There is no executing object in static contexts such as - static method bodies or static initializers. - </para> - - <para>** There is no target object for join points associated - with static methods or fields. - </para> - - </sect1> - -<!-- ============================== --> - - <sect1 id="semantics-pointcuts"> - <title>Pointcuts</title> - - <para> - A pointcut is a program element that picks out join points and - exposes data from the execution context of those join points. - Pointcuts are used primarily by advice. They can be composed with - boolean operators to build up other pointcuts. The primitive - pointcuts and combinators provided by the language are: - </para> - - <variablelist> - <varlistentry> - <term><literal>call(<replaceable>MethodPattern</replaceable>)</literal></term> - <listitem> - Picks out each method call join point whose signature matches - <replaceable>MethodPattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>execution(<replaceable>MethodPattern</replaceable>)</literal></term> - <listitem> - Picks out each method execution join point whose signature matches - <replaceable>MethodPattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>get(<replaceable>FieldPattern</replaceable>)</literal></term> - <listitem> - Picks out each field reference join point whose signature matches - <replaceable>FieldPattern</replaceable>. - [Note that references to constant fields (static final - fields bound to a constant string object or primitive value) are not - join points, since Java requires them to be inlined.] - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>set(<replaceable>FieldPattern</replaceable>)</literal></term> - <listitem> - Picks out each field set join point whose signature matches - <replaceable>FieldPattern</replaceable>. - [Note that the initializations of constant fields (static - final fields where the initializer is a constant string object or - primitive value) are not join points, since Java requires their - references to be inlined.] - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>call(<replaceable>ConstructorPattern</replaceable>)</literal></term> - <listitem> - Picks out each constructor call join point whose signature matches - <replaceable>ConstructorPattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>execution(<replaceable>ConstructorPattern</replaceable>)</literal></term> - <listitem> - Picks out each constructor execution join point whose signature matches - <replaceable>ConstructorPattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>initialization(<replaceable>ConstructorPattern</replaceable>)</literal></term> - <listitem> - Picks out each object initialization join point whose signature matches - <replaceable>ConstructorPattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>preinitialization(<replaceable>ConstructorPattern</replaceable>)</literal></term> - <listitem> - Picks out each object pre-initialization join point whose signature matches - <replaceable>ConstructorPattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>staticinitialization(<replaceable>TypePattern</replaceable>)</literal></term> - <listitem> - Picks out each static initializer execution join point whose signature matches - <replaceable>TypePattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>handler(<replaceable>TypePattern</replaceable>)</literal></term> - <listitem> - Picks out each exception handler join point whose signature matches - <replaceable>TypePattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>adviceexecution()</literal></term> - <listitem> - Picks out all advice execution join points. - </listitem> - </varlistentry> - - - <varlistentry> - <term><literal>within(<replaceable>TypePattern</replaceable>)</literal></term> - <listitem> - Picks out each join point where the executing code is defined - in a type matched by <replaceable>TypePattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>withincode(<replaceable>MethodPattern</replaceable>)</literal></term> - <listitem> - Picks out each join point where the executing code is defined in - a method whose signature matches - <replaceable>MethodPattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>withincode(<replaceable>ConstructorPattern</replaceable>)</literal></term> - <listitem> - Picks out each join point where the executing code is defined - in a constructor whose signature matches - <replaceable>ConstructorPattern</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>cflow(<replaceable>Pointcut</replaceable>)</literal></term> - <listitem> - Picks out each join point in the control flow of any join point - <replaceable>P</replaceable> picked out by - <replaceable>Pointcut</replaceable>, including - <replaceable>P</replaceable> itself. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>cflowbelow(<replaceable>Pointcut</replaceable>)</literal></term> - <listitem> - Picks out each join point in the control flow of any join point - <replaceable>P</replaceable> picked out by - <replaceable>Pointcut</replaceable>, but not - <replaceable>P</replaceable> itself. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>this(<replaceable>Type</replaceable> or <replaceable>Id</replaceable>)</literal></term> - <listitem> - Picks out each join point where the currently executing object - (the object bound to <literal>this</literal>) is an instance of - <replaceable>Type</replaceable>, or of the type of the - identifier <replaceable>Id</replaceable> (which must be bound in the enclosing - advice or pointcut definition). - Will not match any join points from static contexts. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>target(<replaceable>Type</replaceable> or <replaceable>Id</replaceable>)</literal></term> - <listitem> - Picks out each join point where the target object (the object - on which a call or field operation is applied to) is an instance of - <replaceable>Type</replaceable>, or of the type of the identifier - <replaceable>Id</replaceable> (which must be bound in the enclosing - advice or pointcut definition). - Will not match any calls, gets, or sets of static members. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>args(<replaceable>Type</replaceable> or <replaceable>Id</replaceable>, ...)</literal></term> - <listitem> - Picks out each join point where the arguments are instances of - the appropriate type (or type of the identifier if using that form). A - <literal>null</literal> argument is matched iff the static type of the - argument (declared parameter type or field type) is the same as, or a subtype of, - the specified args type. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal><replaceable>PointcutId</replaceable>(<replaceable>TypePattern</replaceable> or <replaceable>Id</replaceable>, ...)</literal></term> - <listitem> - Picks out each join point that is picked out by the - user-defined pointcut designator named by - <replaceable>PointcutId</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>if(<replaceable>BooleanExpression</replaceable>)</literal></term> - <listitem> - Picks out each join point where the boolean expression - evaluates to <literal>true</literal>. The boolean expression used - can only access static members, parameters exposed by the enclosing - pointcut or advice, and <literal>thisJoinPoint</literal> forms. In - particular, it cannot call non-static methods on the aspect or - use return values or exceptions exposed by after advice. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>! <replaceable>Pointcut</replaceable></literal></term> - <listitem> - Picks out each join point that is not picked out by - <replaceable>Pointcut</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal><replaceable>Pointcut0</replaceable> <![CDATA[&&]]> <replaceable>Pointcut1</replaceable></literal></term> - <listitem> - Picks out each join points that is picked out by both - <replaceable>Pointcut0</replaceable> and - <replaceable>Pointcut1</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal><replaceable>Pointcut0</replaceable> || <replaceable>Pointcut1</replaceable></literal></term> - <listitem> - Picks out each join point that is picked out by either - pointcuts. <replaceable>Pointcut0</replaceable> or - <replaceable>Pointcut1</replaceable>. - </listitem> - </varlistentry> - - <varlistentry> - <term><literal>( <replaceable>Pointcut</replaceable> )</literal></term> - <listitem> - Picks out each join points picked out by - <replaceable>Pointcut</replaceable>. - </listitem> - </varlistentry> - </variablelist> - - <sect2 id="pointcut-definition" xreflabel="pointcut-definition"> - <title>Pointcut definition</title> - - <para> - Pointcuts are defined and named by the programmer 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 id="context-exposure" xreflabel="context-exposure"> - <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, in - certain pointcut designators, a Java identifier is allowed in place - of a type or collection of types. The pointcut designators that - allow this are <literal>this</literal>, <literal>target</literal>, - and <literal>args</literal>. In all such cases, using an - identifier rather than a type does two things. First, it selects - join points as based on the type of the formal parameter. So the - pointcut - </para> - -<programlisting> -pointcut intArg(int i): args(i); -</programlisting> - - <para> - picks out join points where an <literal>int</literal> (or - a <literal>byte</literal>, <literal>short</literal>, or - <literal>char</literal>; anything assignable to an - <literal>int</literal>) is being passed as an argument. - Second, though, it makes the value of that argument - available to the enclosing advice or pointcut. - </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> - - <para> - The "boxing" of the primitive value is based on the - <emphasis>original</emphasis> primitive type. So in the - following program - </para> - -<programlisting> -public class InstanceOf { - - public static void main(String[] args) { - doInt(5); - } - - static void doInt(int i) { } -} - -aspect IntToLong { - pointcut el(long l) : - execution(* doInt(..)) <![CDATA[&&]]> args(l); - - before(Object o) : el(o) { - System.out.println(o.getClass()); - } -} -</programlisting> - - <para> - The pointcut will match and expose the integer argument, - but it will expose it as an <literal>Integer</literal>, - not a <literal>Long</literal>. - </para> - - </sect2> - - <sect2 id="primitive-pointcuts" xreflabel="primitive-pointcuts"> - <title>Primitive pointcuts</title> - - <sect3> - <title>Method-related pointcuts</title> - - <para>AspectJ provides two primitive pointcut designators designed to - capture method call and execution join points. </para> - - <itemizedlist> - <listitem><literal>call(<replaceable>MethodPattern</replaceable>)</literal></listitem> - <listitem><literal>execution(<replaceable>MethodPattern</replaceable>)</literal></listitem> - </itemizedlist> - </sect3> - - <sect3> - <title>Field-related pointcuts</title> - - <para> - AspectJ provides two primitive pointcut designators designed to - capture field reference and set join points: - </para> - - <itemizedlist> - <listitem><literal>get(<replaceable>FieldPattern</replaceable>)</literal></listitem> - <listitem><literal>set(<replaceable>FieldPattern</replaceable>)</literal></listitem> - </itemizedlist> - - <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 a static 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(static int T.x) && args(newval) { - if (Math.abs(newval - T.x) > MAX_CHANGE) - throw new RuntimeException(); - } -} -]]></programlisting> - - </sect3> - - <sect3> - <title>Object creation-related pointcuts</title> - - <para> - AspectJ provides primitive pointcut designators designed to - capture the initializer execution join points of objects. - </para> - - <itemizedlist> - <listitem><literal>call(<replaceable>ConstructorPattern</replaceable>)</literal></listitem> - <listitem><literal>execution(<replaceable>ConstructorPattern</replaceable>)</literal></listitem> - <listitem><literal>initialization(<replaceable>ConstructorPattern</replaceable>)</literal></listitem> - <listitem><literal>preinitialization(<replaceable>ConstructorPattern</replaceable>)</literal></listitem> - </itemizedlist> - - </sect3> - - <sect3> - <title>Class initialization-related pointcuts</title> - - <para> - AspectJ provides one primitive pointcut designator to pick out - static initializer execution join points. - </para> - - <itemizedlist> - <listitem><literal>staticinitialization(<replaceable>TypePattern</replaceable>)</literal></listitem> - </itemizedlist> - - </sect3> - - <sect3> - <title>Exception handler execution-related pointcuts</title> - - <para> - AspectJ provides one primitive pointcut designator to capture - execution of exception handlers: - </para> - - <itemizedlist> - <listitem><literal>handler(<replaceable>TypePattern</replaceable>)</literal></listitem> - </itemizedlist> - - <para> - All handler join points are treated as having one argument, the value - of the exception being handled. That value can be accessed with an - <literal>args</literal> pointcut. So an aspect used to put - <literal>FooException</literal> 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> - - </sect3> - - <sect3> - <title>Advice execution-related pointcuts</title> - - <para> - AspectJ provides one primitive pointcut designator to capture - execution of advice - </para> - - <itemizedlist> - <listitem><literal>adviceexecution()</literal></listitem> - </itemizedlist> - - <para> - This can be used, for example, to filter out any join point in the - control flow of advice from a particular aspect. - </para> - -<programlisting> -aspect TraceStuff { - pointcut myAdvice(): adviceexecution() <![CDATA[&&]]> within(TraceStuff); - - before(): call(* *(..)) <![CDATA[&&]]> !cflow(myAdvice) { - // do something - } -} -</programlisting> - - </sect3> - - <sect3> - <title>State-based pointcuts</title> - - <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 pick out join points. They may also be used to - expose the objects used for discrimination. - </para> - - <itemizedlist> - <listitem><literal>this(<replaceable>Type</replaceable> or <replaceable>Id</replaceable>)</literal></listitem> - <listitem><literal>target(<replaceable>Type</replaceable> or <replaceable>Id</replaceable>)</literal></listitem> - </itemizedlist> - - <para> - The <literal>this</literal> pointcut picks out each join point where - the currently executing object (the object bound to - <literal>this</literal>) is an instance of a particular type. The - <literal>target</literal> pointcut picks out each join point where - the target object (the object on which a method is called or a field - is accessed) is an instance of a particular type. Note that - <literal>target</literal> should be understood to be the object the - current join point is transfering control to. This means that the - target object is the same as the current object at a method execution - join point, for example, but may be different at a method call join - point. - </para> - - <itemizedlist> - <listitem><literal>args(<replaceable>Type</replaceable> or <replaceable>Id</replaceable> or "..", ...)</literal></listitem> - </itemizedlist> - - <para> - The args pointcut picks out each join point where the arguments are - instances of some types. Each element in the comma-separated list is - one of four things. If it is a type name, then the argument in that - position must be an instance of that type. If it is an identifier, - then that identifier must be bound in the enclosing advice or - pointcut declaration, and so 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 "*" wildcard, then any - argument will match, and if it is the special wildcard "..", then any - number of arguments will match, just like in signature patterns. 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> - - </sect3> - - <sect3> - <title>Control flow-based pointcuts</title> - - <para> - Some concerns cut across the control flow of the program. The - <literal>cflow</literal> and <literal>cflowbelow</literal> primitive - pointcut designators capture join points based on control flow. - </para> - - <itemizedlist> - <listitem><literal>cflow(<replaceable>Pointcut</replaceable>)</literal></listitem> - <listitem><literal>cflowbelow(<replaceable>Pointcut</replaceable>)</literal></listitem> - </itemizedlist> - - <para> - The <literal>cflow</literal> pointcut picks out all join points that - occur between entry and exit of each join point - <replaceable>P</replaceable> picked out by - <replaceable>Pointcut</replaceable>, including - <replaceable>P</replaceable> itself. Hence, it picks out the join - points <emphasis>in</emphasis> the control flow of the join points - picked out by <replaceable>Pointcut</replaceable>. - </para> - - <para> - The <literal>cflowbelow</literal> pointcut picks out all join points - that occur between entry and exit of each join point - <replaceable>P</replaceable> picked out by - <replaceable>Pointcut</replaceable>, but not including - <replaceable>P</replaceable> itself. Hence, it picks out the join - points <emphasis>below</emphasis> the control flow of the join points - picked out by <replaceable>Pointcut</replaceable>. - </para> - - <sect4> - <title>Context exposure from control flows</title> - - <para> - The <literal>cflow</literal> and - <literal>cflowbelow</literal> pointcuts may expose context - state through enclosed <literal>this</literal>, - <literal>target</literal>, and <literal>args</literal> - pointcuts. - </para> - - <para> - Anytime such state is accessed, it is accessed through the - <emphasis>most recent</emphasis> control flow that - matched. So the "current arg" that would be printed by - the following program is zero, even though it is in many - control flows. - </para> - -<programlisting> -class Test { - public static void main(String[] args) { - fact(5); - } - static int fact(int x) { - if (x == 0) { - System.err.println("bottoming out"); - return 1; - } - else return x * fact(x - 1); - } -} - -aspect A { - pointcut entry(int i): call(int fact(int)) <![CDATA[&&]]> args(i); - pointcut writing(): call(void println(String)) <![CDATA[&&]]> ! within(A); - - before(int i): writing() <![CDATA[&&]]> cflow(entry(i)) { - System.err.println("Current arg is " + i); - } -} -</programlisting> - - <para> - It is an error to expose such state through - <emphasis>negated</emphasis> control flow pointcuts, such - as within <literal>! - cflowbelow(<replaceable>P</replaceable>)</literal>. - </para> - - </sect4> - </sect3> - - <sect3> - <title>Program text-based pointcuts</title> - - <para> - While many concerns cut across the runtime structure of the program, - some must deal with the lexical structure. AspectJ allows aspects to - pick out join points based on where their associated code is defined. - </para> - - <itemizedlist> - <listitem><literal>within(<replaceable>TypePattern</replaceable>)</literal></listitem> - <listitem><literal>withincode(<replaceable>MethodPattern</replaceable>)</literal></listitem> - <listitem><literal>withincode(<replaceable>ConstructorPattern</replaceable>)</literal></listitem> - </itemizedlist> - - <para> - The <literal>within</literal> pointcut picks out each join point - 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 in a - type's nested types, and that type's default constructor, if there is - one. - </para> - - <para> - The <literal>withincode</literal> pointcuts picks out each join point - 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 in a method or constructor's local or anonymous types. - </para> - - </sect3> - - <sect3> - <title>Expression-based pointcuts</title> - - <itemizedlist> - <listitem><literal>if(<replaceable>BooleanExpression</replaceable>)</literal></listitem> - </itemizedlist> - - <para> - The if pointcut picks out join points based on a dynamic property. - its 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> - - <para> - Note that the order of evaluation for pointcut expression - components at a join point is undefined. Writing <literal>if</literal> - pointcuts that have side-effects is considered bad style and may also - lead to potentially confusing or even changing behavior with regard - to when or if the test code will run. - </para> - </sect3> - </sect2> - - <sect2 id="signatures" xreflabel="signatures"> - <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> - - <sect3> - <title>Methods</title> - - <para> - Join points associated with methods typically have method signatures, - consisting of a method name, parameter types, return type, the types of - the declared (checked) exceptions, and some type that the method could - be called on (below called the "qualifying type"). - </para> - - <para> - At a method call join point, the signature is a method signature whose - qualifying type is the static type used to <emphasis>access</emphasis> - the method. This means that the signature for the join point created - from the call <literal>((Integer)i).toString()</literal> is different - than that for the call <literal>((Object)i).toString()</literal>, even - if <literal>i</literal> is the same variable. - </para> - - <para> - At a method execution join point, the signature is a method signature - whose qualifying type is the declaring type of the method. - </para> - - </sect3> - - <sect3> - <title>Fields</title> - - <para> - Join points associated with fields typically have field signatures, - consisting of a field name and a field type. A field reference join - point has such a signature, and no parameters. A field set join point - has such a signature, but has a has a single parameter whose type is - the same as the field type. - </para> - - </sect3> - - <sect3> - <title>Constructors</title> - - <para> - Join points associated with constructors typically have constructor - signatures, consisting of a parameter types, the types of the declared - (checked) exceptions, and the declaring type. - </para> - - <para> - At a constructor call join point, the signature is the constructor - signature of the called constructor. At a constructor execution join - point, the signature is the constructor signature of the currently - executing constructor. - </para> - - <para> - At object initialization and pre-initialization join points, the - signature is the constructor signature for the constructor that started - this initialization: the first constructor entered during this type's - initialization of this object. - </para> - </sect3> - - <sect3> - <title>Others</title> - - <para> - At a handler execution join point, the signature is composed of the - exception type that the handler handles. - </para> - - <para> - At an advice execution join point, the signature is composed of the - aspect type, the parameter types of the advice, the return type (void - for all but around advice) and the types of the declared (checked) - exceptions. - </para> - </sect3> - </sect2> - -<!-- ============================== --> - - <sect2 id="matching" xreflabel="matching"> - <title>Matching</title> - - <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 declaring individual members - and constructors. - </para> - - <para> - Method declarations in Java include method names, method parameters, - return types, modifiers like static or private, and throws clauses, - while constructor declarations omit the return type and replace the - method name with the class name. The start of a particular method - declaration, 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> - The wildcard <literal>..</literal> indicates zero or more - parameters, 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> - - <sect3> - <title>Matching based on the declaring type</title> - - <para> - The signature-matching pointcuts all specify a declaring type, - but the meaning varies slightly for each join point signature, - in line with Java semantics. - </para> - - <para> - When matching for pointcuts <literal>withincode</literal>, - <literal>get</literal>, and <literal>set</literal>, the declaring - type is the class that contains the declaration. - </para> - - <para> - When matching method-call join points, the - declaring type is the static type used to access the method. - A common mistake is to specify a declaring type for the - <literal>call</literal> pointcut that is a subtype of the - originally-declaring type. For example, given the class - </para> - -<programlisting> -class Service implements Runnable { - public void run() { ... } -} -</programlisting> - - <para> - the following pointcut - </para> - -<programlisting> -call(void Service.run()) -</programlisting> - - <para> - would fail to pick out the join point for the code - </para> - -<programlisting> -((Runnable) new Service()).run(); -</programlisting> - - <para> - Specifying the originally-declaring type is correct, but would - pick out any such call (here, calls to the <literal>run()</literal> - method of any Runnable). - In this situation, consider instead picking out the target type: - </para> - -<programlisting> -call(void run()) && target(Service) -</programlisting> - - <para> - When matching method-execution join points, - if the execution pointcut method signature specifies a declaring type, - the pointcut will only match methods declared in that type, or methods - that override methods declared in or inherited by that type. - So the pointcut - </para> - -<programlisting> -execution(public void Middle.*()) -</programlisting> - - <para> - picks out all method executions for public methods returning void - and having no arguments that are either declared in, or inherited by, - Middle, even if those methods are overridden in a subclass of Middle. - So the pointcut would pick out the method-execution join point - for Sub.m() in this code: - </para> - -<programlisting> -class Super { - protected void m() { ... } -} -class Middle extends Super { -} -class Sub extends Middle { - public void m() { ... } -} -</programlisting> - - </sect3> - - <sect3> - <title>Matching based on the throws clause</title> - - <para> - Type patterns may be used to pick out methods and constructors - based on their throws clauses. This allows the following two - kinds of extremely wildcarded pointcuts: - </para> - -<programlisting> -pointcut throwsMathlike(): - // each call to a method with a throws clause containing at least - // one exception exception with "Math" in its name. - call(* *(..) throws *..*Math*); - -pointcut doesNotThrowMathlike(): - // each call to a method with a throws clause containing no - // exceptions with "Math" in its name. - call(* *(..) throws !*..*Math*); -</programlisting> - - <para> - A <replaceable>ThrowsClausePattern</replaceable> is a comma-separated list of - <replaceable>ThrowsClausePatternItem</replaceable>s, where - - <variablelist> - <varlistentry> - <term><replaceable>ThrowsClausePatternItem</replaceable> :</term> - <listitem> - <literal>[ ! ] - <replaceable>TypeNamePattern</replaceable></literal> - </listitem> - </varlistentry> - </variablelist> - </para> - - <para> - A <replaceable>ThrowsClausePattern</replaceable> matches the - throws clause of any code member signature. To match, each - <literal>ThrowsClausePatternItem</literal> must - match the throws clause of the member in question. If any item - doesn't match, then the whole pattern doesn't match. - </para> - - <para> - If a ThrowsClausePatternItem begins with "!", then it matches a - particular throws clause if and only if <emphasis>none</emphasis> - of the types named in the throws clause is matched by the - <literal>TypeNamePattern</literal>. - </para> - - <para> - If a <replaceable>ThrowsClausePatternItem</replaceable> does not - begin with "!", then it matches a throws clause if and only if - <emphasis>any</emphasis> of the types named in the throws clause - is matched by the <emphasis>TypeNamePattern</emphasis>. - </para> - - <para> - The rule for "!" matching has one potentially surprising - property, in that these two pointcuts - - <itemizedlist> - <listitem> call(* *(..) throws !IOException) </listitem> - <listitem> call(* *(..) throws (!IOException)) </listitem> - </itemizedlist> - - will match differently on calls to - - <blockquote> - <literal> - void m() throws RuntimeException, IOException {} - </literal> - </blockquote> - </para> - - <para> - [1] will NOT match the method m(), because method m's throws - clause declares that it throws IOException. [2] WILL match the - method m(), because method m's throws clause declares the it - throws some exception which does not match IOException, - i.e. RuntimeException. - </para> - </sect3> - </sect2> - - <sect2 id="type-patterns" xreflabel="type-patterns"> - <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> - - <sect3> - <title>Exact type pattern</title> - - <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> - If a type pattern is an exact type - if it doesn't - include a wildcard - then the matching works just - like normal type lookup in Java: </para> - - <itemizedlist> - <listitem>Patterns that have the same names as - primitive types (like <literal>int</literal>) match - those primitive types.</listitem> - - <listitem>Patterns that are qualified by package names - (like <literal>java.util.HashMap</literal>) match types - in other packages. - </listitem> - - <listitem>Patterns that are not qualified (like - <literal>HashMap</literal>) match types that are - resolved by Java's normal scope rules. So, for - example, <literal>HashMap</literal> might match a - package-level type in the same package or a type that - have been imported with java's - <literal>import</literal> form. But it would not match - <literal>java.util.HashMap</literal> unless the aspect - were in <literal>java.util</literal> or the type had - been imported. - </listitem> - </itemizedlist> - - <para> - So exact type patterns match based on usual Java scope - rules. - </para> - - </sect3> - - <sect3> - <title>Type name patterns</title> - - <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> -within(com.xerox..*) -</programlisting> - - <para> - picks out all join points where the code is in any - declaration of a type whose name begins with "<literal>com.xerox.</literal>". - </para> - - <para> - Type patterns with wildcards do not depend on Java's - usual scope rules - they match against all types - available to the weaver, not just those that are - imported into an Aspect's declaring file. - </para> - - </sect3> - - <sect3> - <title>Subtype patterns</title> - - <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> - - </sect3> - - <sect3> - <title>Array type patterns</title> - - <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> - </sect3> - - <sect3> - <title>Type patterns</title> - - <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> - </sect3> - </sect2> - - <sect2 id="pattern-summary" xreflabel="pattern-summary"> - <title>Pattern Summary</title> - - <para> - Here is a summary of the pattern syntax used in AspectJ: - </para> - -<programlisting> -MethodPattern = - [ModifiersPattern] TypePattern - [TypePattern . ] IdPattern (TypePattern | ".." , ... ) - [ throws ThrowsPattern ] -ConstructorPattern = - [ModifiersPattern ] - [TypePattern . ] new (TypePattern | ".." , ...) - [ throws ThrowsPattern ] -FieldPattern = - [ModifiersPattern] TypePattern [TypePattern . ] IdPattern -ThrowsPattern = - [ ! ] TypePattern , ... -TypePattern = - IdPattern [ + ] [ [] ... ] - | ! TypePattern - | TypePattern <![CDATA[&&]]> TypePattern - | TypePattern || TypePattern - | ( TypePattern ) -IdPattern = - Sequence of characters, possibly with special * and .. wildcards -ModifiersPattern = - [ ! ] JavaModifier ... -</programlisting> - - </sect2> - - </sect1> - -<!-- ============================== --> - - <sect1 id="semantics-advice"> - <title>Advice</title> - - <para> - Each piece of advice is of the form - - <blockquote> - <literal>[ strictfp ] <replaceable>AdviceSpec</replaceable> [ - throws <replaceable>TypeList</replaceable> ] : - <replaceable>Pointcut</replaceable> { - <replaceable>Body</replaceable> } </literal> - </blockquote> - - where <replaceable>AdviceSpec</replaceable> is one of - </para> - - <itemizedlist> - <listitem> - <literal>before( <replaceable>Formals</replaceable> ) </literal> - </listitem> - <listitem> - <literal>after( <replaceable>Formals</replaceable> ) returning - [ ( <replaceable>Formal</replaceable> ) ] </literal> - </listitem> - <listitem> - <literal>after( <replaceable>Formals</replaceable> ) throwing [ - ( <replaceable>Formal</replaceable> ) ] </literal> - </listitem> - <listitem> - <literal>after( <replaceable>Formals</replaceable> ) </literal> - </listitem> - <listitem> - <literal><replaceable>Type</replaceable> - around( <replaceable>Formals</replaceable> )</literal> - </listitem> - </itemizedlist> - <para> - and where <replaceable>Formal</replaceable> refers to a - variable binding like those used for method parameters, - of the form - <literal><replaceable>Type</replaceable></literal> - <literal><replaceable>Variable-Name</replaceable></literal>, - and <replaceable>Formals</replaceable> refers to a comma-delimited - list of <replaceable>Formal</replaceable>. - </para> - - - <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> - If after returning does expose its returned object, then the - type of the parameter is considered to be an - <literal>instanceof</literal>-like constraint on the advice: it - will run only when the return value is of the appropriate type. - </para> - - <para> - A value is of the appropriate type if it would be assignable to - a variable of that type, in the Java sense. That is, a - <literal>byte</literal> value is assignable to a - <literal>short</literal> parameter but not vice-versa, an - <literal>int</literal> is assignable to a - <literal>float</literal> parameter, <literal>boolean</literal> - values are only assignable to <literal>boolean</literal> - parameters, and reference types work by instanceof. - </para> - - <para> - There are two special cases: If the exposed value is typed to - <literal>Object</literal>, then the advice is not constrained by - that type: 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> - Secondly, the <literal>null</literal> value is assignable to a - parameter <literal>T</literal> if the join point - <emphasis>could</emphasis> return something of type - <literal>T</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. - </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> - Any occurence of <literal>proceed(..)</literal> within the body of around - advice is treated as the special proceed form (even if the - aspect defines a method named <literal>proceed</literal>), unless a - target other than the aspect instance is specified as the recipient of - the call. - For example, in the following program the first - call to proceed will be treated as a method call to - the <literal>ICanProceed</literal> instance, whereas the second call to - proceed is treated as the special proceed form. - </para> - -<programlisting> -aspect A { - Object around(ICanProceed canProceed) : execution(* *(..)) <![CDATA[&&]]> this(canProceed) { - canProceed.proceed(); // a method call - return proceed(canProceed); // the special proceed form - } - - private Object proceed(ICanProceed canProceed) { - // this method cannot be called from inside the body of around advice in - // the aspect - } -} -</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> - <para> - With <literal>proceed(..)</literal> it is possible to change the values - used by less-precedent advice and the underlying join point by supplying - different values for the variables. For example, this aspect replaces - the string bound to <literal>s</literal> in the named pointcut - <literal>privateData</literal>: - </para> - -<programlisting> -aspect A { - Object around(String s): MyPointcuts.privateData(s) { - return proceed("private data"); - } -} -</programlisting> - <para> - If you replace an argument to <literal>proceed(..)</literal>, you can cause - a <literal>ClassCastException</literal> at runtime when the argument - refers to a supertype of the actual type and you do not supply a - reference of the actual type. In the following aspect, the - around advice replaces the declared target <literal>List</literal> - with an <literal>ArrayList</literal>. This is valid code at - compile-time since the types match. - </para> -<programlisting> -import java.util.*; - -aspect A { - Object around(List list): call(* List+.*()) <![CDATA[&&]]> target(list) { - return proceed(new ArrayList()); - } -} -</programlisting> - <para> - But imagine a simple program where the actual target is - <literal>LinkedList</literal>. In this case, the advice would cause a - <literal>ClassCastException</literal> at runtime, and - <literal>peek()</literal> is not declared in <literal>ArrayList</literal>. - </para> -<programlisting> -public class Test { - public static void main(String[] args) { - new LinkedList().peek(); - } -} -</programlisting> - <para> - The <literal>ClassCastException</literal> can occur even in situations - where it appears to be unnecessary, e.g., if the program is changed to - call <literal>size()</literal>, declared in <literal>List</literal>: - </para> -<programlisting> -public class Test { - public static void main(String[] args) { - new LinkedList().size(); - } -} -</programlisting> - <para> - There will still be a <literal>ClassCastException</literal> because - it is impossible to prove that there won't be a runtime binary-compatible - change in the hierarchy of <literal>LinkedList</literal> or some - other advice on the join point that requires a - <literal>LinkedList</literal>. - </para> - - <sect2 id="advice-modifiers" xreflabel="advice-modifiers"> - <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 id="advice-and-checked-exceptions" xreflabel="advice-and-checked-exceptions"> - <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> - the checked exceptions declared by the target method's - <literal>throws</literal> clause. - </listitem> - </varlistentry> - - <varlistentry> - <term>constructor call and execution</term> - <listitem> - the checked exceptions declared by the target constructor's - <literal>throws</literal> clause. - </listitem> - </varlistentry> - - <varlistentry> - <term>field get and set</term> - <listitem> - no checked exceptions can be thrown from these join points. - </listitem> - </varlistentry> - - <varlistentry> - <term>exception handler execution</term> - <listitem> - the exceptions that can be thrown by the target exception handler. - </listitem> - </varlistentry> - - <varlistentry> - <term>static initializer execution</term> - <listitem> - no checked exceptions can be thrown from these join points. - </listitem> - </varlistentry> - - <varlistentry> - <term>pre-initialization and initialization</term> - <listitem> - any exception that is in the throws clause of - <emphasis>all</emphasis> constructors of the initialized class. - </listitem> - </varlistentry> - - <varlistentry> - <term>advice execution</term> - <listitem> - any exception that is in the throws clause of the advice. - </listitem> - </varlistentry> - - </variablelist> - - </sect2> - - <sect2 id="advice-precedence" xreflabel="advice-precedence"> - <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> - - <itemizedlist> - <listitem>If aspect A is matched earlier than aspect B in some - <literal>declare precedence</literal> form, then all advice in - concrete aspect A has precedence over all advice in concrete aspect B - when they are on the same join point. </listitem> - - <listitem> - 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 - <literal>declare precedence</literal>, advice in a subaspect - has precedence over advice in a superaspect. - </listitem> - - <listitem> - Otherwise, if two pieces of advice are defined in two different - aspects, it is undefined which one has precedence. - </listitem> - - </itemizedlist> - - <para>If the two pieces of advice are defined in the same aspect, then - there are two cases: </para> - - <itemizedlist> - <listitem>If either are <literal>after</literal> advice, then the one that - appears later in the aspect has precedence over the one that appears - earlier. </listitem> - - <listitem>Otherwise, then the one that appears earlier in the aspect - has precedence over the one that appears later. - </listitem> - - </itemizedlist> - - <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 id="reflective-access-to-the-join-point" xreflabel="reflective-access-to-the-join-point"> - <title>Reflective access to the join point</title> - - <para> - Three special variables are visible within bodies of advice - and within <literal>if()</literal> pointcut expressions: - <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. - - </para> - - <para> - <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. It is - equivalent to <literal>thisJoinPoint.getStaticPart()</literal>. - </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> - Standard Java reflection uses objects from the - <literal>java.lang.reflect</literal> hierarchy to build up its - reflective objects. Similarly, AspectJ 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 id="semantics-declare"> - <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 - inter-type member declarations and other <literal>declare</literal> forms. - </para> - - <sect2 id="inter-type-member-declarations" xreflabel="inter-type-member-declarations"> - <title>Inter-type member declarations</title> - - <para> - AspectJ allows the declaration of members by aspects that are - associated with other types. - </para> - - <para> - An inter-type method declaration looks like - </para> - - <itemizedlist> - <listitem><literal> - [ <replaceable>Modifiers</replaceable> ] - <replaceable>Type</replaceable> <replaceable>OnType</replaceable> - . - <replaceable>Id</replaceable>(<replaceable>Formals</replaceable>) - [ <replaceable>ThrowsClause</replaceable> ] - { <replaceable>Body</replaceable> }</literal></listitem> - - <listitem><literal>abstract - [ <replaceable>Modifiers</replaceable> ] - <replaceable>Type</replaceable> <replaceable>OnType</replaceable> - . <replaceable>Id</replaceable>(<replaceable>Formals</replaceable>) - [ <replaceable>ThrowsClause</replaceable> ] - ; - </literal></listitem> - </itemizedlist> - - <para> - The effect of such a declaration is to make <replaceable>OnType</replaceable> - support the new method. Even if <replaceable>OnType</replaceable> is - an interface. 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> - An inter-type constructor declaration looks like - </para> - - <itemizedlist> - <listitem><literal> - [ <replaceable>Modifiers</replaceable> ] - <replaceable>OnType</replaceable> . new ( - <replaceable>Formals</replaceable> ) - [ <replaceable>ThrowsClause</replaceable> ] - { <replaceable>Body</replaceable> }</literal></listitem> - </itemizedlist> - - <para> - The effect of such a declaration is to make - <replaceable>OnType</replaceable> support the new constructor. It is - an error for <replaceable>OnType</replaceable> to be an interface. - </para> - - <para> - Inter-type declared constructors cannot be used to assign a - value to a final variable declared in <replaceable>OnType</replaceable>. - This limitation significantly increases the ability to both understand - and compile the <replaceable>OnType</replaceable> class and the - declaring aspect separately. - </para> - - <para> - Note that in the Java language, classes that define no constructors - have an implicit no-argument constructor that just calls - <literal>super()</literal>. This means that attempting to declare - a no-argument inter-type constructor on such a class may result in - a conflict, even though it <emphasis>looks</emphasis> like no - constructor is defined. - </para> - - <para> - An inter-type field declaration looks like one of - </para> - - <itemizedlist> - <listitem><literal> - [ <replaceable>Modifiers</replaceable> ] - <replaceable>Type</replaceable> - <replaceable>OnType</replaceable> . <replaceable>Id</replaceable> - = <replaceable>Expression</replaceable>;</literal></listitem> - - <listitem><literal> - [ <replaceable>Modifiers</replaceable> ] - <replaceable>Type</replaceable> - <replaceable>OnType</replaceable> . <replaceable>Id</replaceable>;</literal></listitem> - </itemizedlist> - - <para> - The effect of such a declaration is to make - <replaceable>OnType</replaceable> support the new field. Even if - <replaceable>OnType</replaceable> is an interface. Even if the field is - neither public, nor static, nor final. - </para> - - <para> - The initializer, if any, of an inter-type field declaration runs - before the class-local initializers defined in its target class. - </para> - - </sect2> - - <para> - Any occurrence of the identifier <literal>this</literal> in the body of - an inter-type constructor or method declaration, or in the initializer - of an inter-type field declaration, refers to the - <replaceable>OnType</replaceable> object rather than to the aspect - type; it is an error to access <literal>this</literal> in such a - position from a <literal>static</literal> inter-type member - declaration. - </para> - - <sect2 id="access-modifiers" xreflabel="access-modifiers"> - <title>Access modifiers</title> - - <para> - Inter-type member declarations may be public or private, or have - default (package-protected) visibility. AspectJ does not provide - protected inter-type members. - </para> - - <para> - The access modifier applies in relation to the aspect, not in relation - to the target type. So a private inter-type member is visible only from - code that is defined within the declaring aspect. A default-visibility - inter-type member is visible only from code that is defined within the - declaring aspect's package. - </para> - - <para> - Note that a declaring a private inter-type method (which AspectJ - supports) is very different from inserting a private method declaration - into another class. The former allows access only from the declaring - aspect, while the latter would allow access only from the target type. - Java serialization, for example, uses the presense of a private method - <literal>void writeObject(ObjectOutputStream)</literal> for the - implementation of <literal>java.io.Serializable</literal>. A private - inter-type declaration of that method would not fulfill this - requirement, since it would be private to the aspect, not private to - the target type. - </para> - - <para> - The access modifier of abstract inter-type methods has - one constraint: It is illegal to declare an abstract - non-public inter-type method on a public interface. This - is illegal because it would say that a public interface - has a constraint that only non-public implementors must - fulfill. This would not be compatible with Java's type - system. - </para> - </sect2> - - <sect2 id="conflicts" xreflabel="conflicts"> - <title>Conflicts</title> - - <para> - Inter-type declarations raise the possibility of conflicts among - locally declared members and inter-type members. For example, assuming - <literal>otherPackage</literal> is not the package containing the - aspect <classname>A</classname>, the code - </para> - -<programlisting> -aspect A { - private Registry otherPackage.onType.r; - public void otherPackage.onType.register(Registry r) { - r.register(this); - this.r = r; - } -} -</programlisting> - - <para> - declares that <literal>onType</literal> in <literal>otherPackage</literal> has a field - <literal>r</literal>. This field, however, is only accessible from the - code inside of aspect <literal>A</literal>. The aspect also declares - that <literal>onType</literal> has a method - "<literal>register</literal>", but makes this method accessible from - everywhere. - </para> - - <para> - If <literal>onType</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 inter-type - "<literal>r</literal>". - </para> - - <para> - If <literal>onType</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 private inter-type - "<literal>r</literal>" or the public locally-defined - "<literal>r</literal>" should be used. - </para> - - <para> - If <literal>onType</literal> defines a 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> - - <itemizedlist> - <listitem>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.</listitem> - - <listitem>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). - </listitem> - </itemizedlist> - - <para> - Given a potential conflict between inter-type member declarations in - different aspects, if one aspect has precedence over the other its - declaration will take effect without any conflict notice from compiler. - This is true both when the precedence is declared explicitly with - <literal>declare precedence</literal> as well as when when sub-aspects - implicitly have precedence over their super-aspect. - </para> - - </sect2> - - <sect2 id="extension-and-implementation" xreflabel="extension-and-implementation"> - <title>Extension and Implementation</title> - - <para> - An aspect may change the inheritance hierarchy of a system by changing - the superclass of a type or adding a superinterface onto a type, with - the <literal>declare parents</literal> form. - </para> - - <itemizedlist> - <listitem><literal>declare parents: <replaceable>TypePattern</replaceable> extends <replaceable>Type</replaceable>;</literal></listitem> - <listitem><literal>declare parents: <replaceable>TypePattern</replaceable> implements <replaceable>TypeList</replaceable>;</literal></listitem> - </itemizedlist> - - <para> - For example, if an aspect wished to make a particular class runnable, - it might define appropriate inter-type <literal>void - run()</literal> method, but it should also declare that the class - fulfills the <literal>Runnable</literal> interface. In order to - implement the methods in the <literal>Runnable</literal> interface, the - inter-type <literal>run()</literal> method must be public: - </para> - -<programlisting> -aspect A { - declare parents: SomeClass implements Runnable; - public void SomeClass.run() { ... } -} -</programlisting> - - </sect2> - - <sect2 id="interfaces-with-members" xreflabel="interfaces-with-members"> - <title>Interfaces with members</title> - - <para> - Through the use of inter-type members, 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, each interface - behaves as if it has a zero-argument constructor containing its - initializers. The order of super-interface instantiation is - observable. We fix this order with the following properties: A - supertype is initialized before a subtype, initialized code runs only - once, and the initializers for a type's superclass are run before the - initializers for its superinterfaces. 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 id="warnings-and-errors" xreflabel="warnings-and-errors"> - <title>Warnings and Errors</title> - - <para>An aspect may specify that a particular join point should never be - reached. </para> - - <itemizedlist> - <listitem><literal>declare error: <replaceable>Pointcut</replaceable>: <replaceable>String</replaceable>;</literal></listitem> - <listitem><literal>declare warning: <replaceable>Pointcut</replaceable>: <replaceable>String</replaceable>;</literal></listitem> - </itemizedlist> - - <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 id="softened-exceptions" xreflabel="softened-exceptions"> - <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> - - <itemizedlist> - <listitem><literal>declare soft: <replaceable>Type</replaceable>: <replaceable>Pointcut</replaceable>;</literal></listitem> - </itemizedlist> - - <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> - - <para> Like advice, the declare soft form has no effect in an - abstract aspect that is not extended by a concreate aspect. So - the following code will not compile unless it is compiled with an - extending concrete aspect:</para> - -<programlisting> -abstract aspect A { - abstract pointcut softeningPC(); - - before() : softeningPC() { - Class.forName("FooClass"); // error: uncaught ClassNotFoundException - } - - declare soft : ClassNotFoundException : call(* Class.*(..)); -} -</programlisting> - - </sect2> - - <sect2 id="advice-precedence-cross" xreflabel="advice-precedence-cross"> - <title>Advice Precedence</title> - - <para> - An aspect may declare a precedence relationship between concrete - aspects with the <literal>declare precedence</literal> form: - </para> - - <itemizedlist> - <listitem><literal>declare precedence : - <replaceable>TypePatternList</replaceable> ; </literal></listitem> - </itemizedlist> - - <para>This signifies that if any join point has advice from two - concrete aspects matched by some pattern in - <replaceable>TypePatternList</replaceable>, then the precedence of - the advice will be the order of in the list. </para> - - <para>In <replaceable>TypePatternList</replaceable>, the wildcard "*" can - appear at most once, and it means "any type not matched by any other - pattern in the list". </para> - - <para>For example, the constraints that (1) aspects that have - Security as part of their name should have precedence over all other - aspects, and (2) the Logging aspect (and any aspect that extends it) - should have precedence over all non-security aspects, can be - expressed by:</para> - -<programlisting> -declare precedence: *..*Security*, Logging+, *; -</programlisting> - - <para> - For another 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 has precedence - over DisallowNulls. This declaration could be in either aspect, or - in another, ordering aspect: - </para> - -<programlisting> -aspect Ordering { - declare precedence: CountEntry, DisallowNulls; -} -aspect DisallowNulls { - pointcut allTypeMethods(Type obj): call(* *(..)) <![CDATA[&&]]> args(obj, ..); - before(Type obj): allTypeMethods(obj) { - if (obj == null) throw new RuntimeException(); - } -} -aspect CountEntry { - pointcut allTypeMethods(Type obj): call(* *(..)) <![CDATA[&&]]> args(obj, ..); - static int count = 0; - before(): allTypeMethods(Type) { - count++; - } -} -</programlisting> - - <sect3> - <title>Various cycles</title> - - <para> - It is an error for any aspect to be matched by more than one - TypePattern in a single decare precedence, so: - </para> - -<programlisting> -declare precedence: A, B, A ; // error -</programlisting> - - <para> - However, multiple declare precedence forms may legally have this - kind of circularity. For example, each of these declare - precedence is perfectly legal: - </para> - -<programlisting> -declare precedence: B, A; -declare precedence: A, B; -</programlisting> - - <para> - And a system in which both constraints are active may also be - legal, so long as advice from A and B don't share a join - point. So this is an idiom that can be used to enforce that A and - B are strongly independent. - </para> - </sect3> - - <sect3> - <title>Applies to concrete aspects</title> - - <para> - Consider the following library aspects: - </para> - -<programlisting> -abstract aspect Logging { - abstract pointcut logged(); - - before(): logged() { - System.err.println("thisJoinPoint: " + thisJoinPoint); - } -} - -abstract aspect MyProfiling { - abstract pointcut profiled(); - - Object around(): profiled() { - long beforeTime = System.currentTimeMillis(); - try { - return proceed(); - } finally { - long afterTime = System.currentTimeMillis(); - addToProfile(thisJoinPointStaticPart, - afterTime - beforeTime); - } - } - abstract void addToProfile( - org.aspectj.JoinPoint.StaticPart jp, - long elapsed); -} -</programlisting> - - <para> - In order to use either aspect, they must be extended with - concrete aspects, say, MyLogging and MyProfiling. Because advice - only applies from concrete aspects, the declare precedence form - only matters when declaring precedence with concrete aspects. So - </para> - -<programlisting> -declare precedence: Logging, Profiling; -</programlisting> - - <para> - has no effect, but both - </para> - -<programlisting> -declare precedence: MyLogging, MyProfiling; -declare precedence: Logging+, Profiling+; -</programlisting> - - <para> - are meaningful. - </para> - </sect3> - </sect2> - - - <sect2 id="statically-determinable-pointcuts" xreflabel="statically-determinable-pointcuts"> - <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> - - <itemizedlist> - <listitem>cflow</listitem> - <listitem>cflowbelow</listitem> - <listitem>this</listitem> - <listitem>target</listitem> - <listitem>args</listitem> - <listitem>if</listitem> - </itemizedlist> - - <para> all of which can discriminate on runtime information. </para> - </sect2> - </sect1> - - <sect1 id="semantics-aspects"> - <title>Aspects</title> - - <para> - An aspect is a crosscutting type defined by the <literal>aspect</literal> - declaration. - </para> - - <sect2 id="aspect-declaration" xreflabel="aspect-declaration"> - <title>Aspect Declaration</title> - - <para> - The <literal>aspect</literal> declaration is similar to the - <literal>class</literal> declaration in that it defines a type and an - implementation for that type. It differs in a number of - ways: - </para> - - <sect3> - <title>Aspect implementation can cut across other types</title> - - <para> In addition to normal Java class declarations such as - methods and fields, aspect declarations can include AspectJ - declarations such as advice, pointcuts, and inter-type - declarations. Thus, aspects contain implementation - declarations that can can cut across other types (including those defined by - other aspect declarations). - </para> - </sect3> - - <sect3> - <title>Aspects are not directly instantiated</title> - - <para> Aspects are not 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> - </sect3> - - <sect3> - <title>Nested aspects must be <literal>static</literal></title> - - <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> - </sect3> - </sect2> - - <sect2 id="aspect-extension" xreflabel="aspect-extension"> - <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 id="aspect-instantiation" xreflabel="aspect-instantiation"> - <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. A program - can get a reference to an aspect instance using the static - method <literal>aspectOf(..)</literal>. - </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. - How an aspect is instantiated controls the form of the - <literal>aspectOf(..)</literal> method defined on the - concrete aspect class. - </para> - - <sect3> - <title>Singleton Aspects</title> - - <itemizedlist> - <listitem><literal>aspect <replaceable>Id</replaceable> { ... }</literal></listitem> - <listitem><literal>aspect <replaceable>Id</replaceable> issingleton() { ... }</literal></listitem> - </itemizedlist> - - <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 from the static method <literal>aspectOf()</literal> - automatically defined on all concrete aspects - -- 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> - - <para> - (In actuality, one instance of the aspect A is made for each version - of the aspect A, so there will be one instantiation for each time A - is loaded by a different classloader.) - </para> - </sect3> - - <sect3> - <title>Per-object aspects</title> - - <itemizedlist> - <listitem><literal>aspect <replaceable>Id</replaceable> perthis(<replaceable>Pointcut</replaceable>) { ... }</literal></listitem> - <listitem><literal>aspect <replaceable>Id</replaceable> pertarget(<replaceable>Pointcut</replaceable>) { ... }</literal></listitem> - </itemizedlist> - - <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 will run only at a 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 will run only at a 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="implementation"/> appendix. </para> - </sect3> - - <sect3> - <title>Per-control-flow aspects</title> - - <itemizedlist> - <listitem><literal>aspect <replaceable>Id</replaceable> percflow(<replaceable>Pointcut</replaceable>) { ... }</literal></listitem> - <listitem><literal>aspect <replaceable>Id</replaceable> percflowbelow(<replaceable>Pointcut</replaceable>) { ... }</literal></listitem> - </itemizedlist> - - <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> - - <sect3> - <title>Aspect instantiation and advice</title> - - <para> - All advice runs in the context of an aspect instance, - but it is possible to write a piece of advice with a pointcut - that picks out a join point that must occur before asopect - instantiation. For example: - </para> - -<programlisting> -public class Client -{ - public static void main(String[] args) { - Client c = new Client(); - } -} - -aspect Watchcall { - pointcut myConstructor(): execution(new(..)); - - before(): myConstructor() { - System.err.println("Entering Constructor"); - } -} -</programlisting> - - <para> - The before advice should run before the execution of all - constructors in the system. It must run in the context of an - instance of the Watchcall aspect. The only way to get such an - instance is to have Watchcall's default constructor execute. But - before that executes, we need to run the before advice... - </para> - - <para> - There is no general way to detect these kinds of circularities at - compile time. If advice runs before its aspect is instantiated, - AspectJ will throw a <ulink - url="../api/org/aspectj/lang/NoAspectBoundException.html"> - <literal>org.aspectj.lang.NoAspectBoundException</literal></ulink>. - </para> - </sect3> - </sect2> - - <sect2 id="aspect-privilege" xreflabel="aspect-privilege"> - <title>Aspect privilege</title> - - <itemizedlist> - <listitem><literal>privileged aspect <replaceable>Id</replaceable> { ... }</literal></listitem> - </itemizedlist> - - <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 inter-type members 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 signaled 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 private inter-type 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 its own inter-type - fields even if it were not privileged. - </para> - - <para> - Note that a privileged aspect can access private inter-type - declarations made by other aspects, since they are simply - considered private members of that other aspect. - </para> - </sect2> - </sect1> -</appendix> - - - |