diff options
Diffstat (limited to 'docs/progGuideDB/language.xml')
-rw-r--r-- | docs/progGuideDB/language.xml | 1354 |
1 files changed, 0 insertions, 1354 deletions
diff --git a/docs/progGuideDB/language.xml b/docs/progGuideDB/language.xml deleted file mode 100644 index 48b0fa62d..000000000 --- a/docs/progGuideDB/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> - |