From 6803c91210f78e6024109c8b9b46ae823131dc19 Mon Sep 17 00:00:00 2001 From: Alexander Kriegisch Date: Mon, 19 Jul 2021 12:12:37 +0700 Subject: [PATCH] More AsciiDoc formatting improvements (WIP) Signed-off-by: Alexander Kriegisch --- docs/devGuideDB/ajc.adoc | 2 +- docs/devGuideDB/ajdejbuilder.adoc | 2 +- docs/devGuideDB/antsupport.adoc | 10 +- docs/devGuideDB/ltw.adoc | 1 + docs/dist/LICENSE-AspectJ.adoc | 2 +- docs/pdGuideDB/messages.adoc | 17 +- docs/pdGuideDB/pdguide.adoc | 50 + docs/pdGuideDB/pdguide.xml | 33 +- docs/pdGuideDB/pointcuts.adoc | 67 +- docs/progGuideDB/examples.adoc | 1089 +++++++++++----------- docs/progGuideDB/gettingstarted.adoc | 305 +++--- docs/progGuideDB/idioms.adoc | 42 +- docs/progGuideDB/implementation.adoc | 157 ++-- docs/progGuideDB/language.adoc | 106 ++- docs/progGuideDB/pitfalls.adoc | 46 +- docs/progGuideDB/progguide.adoc | 27 +- docs/progGuideDB/progguide.html.xsl.adoc | 1 - docs/progGuideDB/quickreference.adoc | 48 +- docs/progGuideDB/semantics.adoc | 604 ++++++------ 19 files changed, 1291 insertions(+), 1318 deletions(-) create mode 100644 docs/pdGuideDB/pdguide.adoc delete mode 100644 docs/progGuideDB/progguide.html.xsl.adoc diff --git a/docs/devGuideDB/ajc.adoc b/docs/devGuideDB/ajc.adoc index ff789be2d..7fbc4053a 100644 --- a/docs/devGuideDB/ajc.adoc +++ b/docs/devGuideDB/ajc.adoc @@ -1,3 +1,4 @@ +[[ajc]] == `ajc`, the AspectJ compiler/weaver === Name @@ -9,7 +10,6 @@ [subs=+quotes] ajc [_option_...] [_file_... | @_file_... | -argfile _file_...] -[[ajc]] === Description The `ajc` command compiles and weaves AspectJ and Java source and .class diff --git a/docs/devGuideDB/ajdejbuilder.adoc b/docs/devGuideDB/ajdejbuilder.adoc index 445a61a89..facfc766f 100644 --- a/docs/devGuideDB/ajdejbuilder.adoc +++ b/docs/devGuideDB/ajdejbuilder.adoc @@ -135,7 +135,7 @@ exist) . in the leftmost pane you will notice "Spacewar.jpr", right click this and select "Add to project" in the popup, then "Add class/package..." in thenext popup. Or directly choose "Add files/packages". -. select the "spacewar" and "coordination" packages and then +. select the "spacewar" and "coordination" packages and then click "OK"; this will add the two packages to your project . click the "Build Project" button (image:jbuilder-build.gif[image]) to compile the project diff --git a/docs/devGuideDB/antsupport.adoc b/docs/devGuideDB/antsupport.adoc index 1bc9b6f70..9a370d718 100644 --- a/docs/devGuideDB/antsupport.adoc +++ b/docs/devGuideDB/antsupport.adoc @@ -328,8 +328,8 @@ depends on compliance mode. ==== AjcTask matching parameters specified as nested elements This task forms an implicit FileSet and supports all attributes of -`` (dir becomes srcdir) as well as the nested ``, -``, and `` elements. These can be used to specify +`fileset` (dir becomes srcdir) as well as the nested `include`, +`exclude`, and `patternset` elements. These can be used to specify source files. However, it is better to use `sourceroots` to specify source directories unless using filters to exclude some files from compilation. @@ -753,13 +753,13 @@ sure to include exactly one argument on each line. ==== Ajc10 parameters specified as nested elements This task forms an implicit FileSet and supports all attributes of -`` (dir becomes srcdir) as well as the nested ``, -``, and `` elements. These can be used to specify +`fileset` (dir becomes srcdir) as well as the nested `include`, +`exclude`, and `patternset` elements. These can be used to specify source files. ``ajc``'s `srcdir`, `classpath`, `bootclasspath`, `extdirs`, and `jvmarg` attributes are path-like structures and can also be set via nested -``, ``, ``, ``, and `` +`src`, `classpath`, `bootclasspath`, `extdirs`, and `jvmargs` elements, respectively. [[antTasks-ajc-sample]] diff --git a/docs/devGuideDB/ltw.adoc b/docs/devGuideDB/ltw.adoc index 7f25562db..e5ce4ba54 100644 --- a/docs/devGuideDB/ltw.adoc +++ b/docs/devGuideDB/ltw.adoc @@ -381,6 +381,7 @@ You have to remember that the `name` attribute must be a valid fully qualified class name that will be then reserved for this concrete-aspect and must not conflict with other classes you deploy. +[[weaver-options]] ==== Weaver Options The table below lists the AspectJ options supported by LTW. All other diff --git a/docs/dist/LICENSE-AspectJ.adoc b/docs/dist/LICENSE-AspectJ.adoc index 9b874e58f..4aad458a8 100644 --- a/docs/dist/LICENSE-AspectJ.adoc +++ b/docs/dist/LICENSE-AspectJ.adoc @@ -1,6 +1,6 @@ == *AspectJ^TM^ Compiler and Core Tools License* -This is a binary-only release. Source code is available from +This is a binary-only release. Source code is available from http://eclipse.org/aspectj The Eclipse Foundation makes available all content in this distribution diff --git a/docs/pdGuideDB/messages.adoc b/docs/pdGuideDB/messages.adoc index 277a4f472..efff9be24 100644 --- a/docs/pdGuideDB/messages.adoc +++ b/docs/pdGuideDB/messages.adoc @@ -1,3 +1,4 @@ +[[messages]] == Messages [[messages-introduction]] @@ -18,9 +19,9 @@ summarizes some of the more relevant messages. The compiler offers `-verbose`, `-warning`, and `-XLint` options when invoked using the command-line, Ant, or embedded in an IDE. All options are listed in the AspectJ Development Environment Guide sections for -xref:../devguide/ajc-ref.html[Ajc] and -xref:../devguide/antTasks-iajc.html[Ant Tasks]. The -xref:../devguide/ltw.html[Load-time Weaving] section describes how to +xref:../devGuideDB/ajc.adoc#ajc[Ajc] and +xref:../devGuideDB/antsupport.adoc#antTasks[Ant Tasks]. The +xref:../devGuideDB/ltw.adoc#ltw[Load-time Weaving] section describes how to use XML configuration files and system properties to pass options to the weaver. (You can also pass options to the weaver using system properties in build- time weaving.) The `-verbose` option has the effect of @@ -37,9 +38,9 @@ compiler and weaver messages. The tables below list some options, System Properties (for LTW only) and Java 5 annotations used to control AspectJ messages. The method of configuration depends on your environment so please refer to the -relevant documentation for xref:../devguide/ajc-ref.html[ajc], -xref:../devguide/antTasks.html[Ant] or -xref:../devguide/ltw-configuration.html#weaver-options[LTW]. +relevant documentation for xref:../devGuideDB/ajc.adoc[ajc], +xref:../devGuideDB/antsupport.adoc#antTasks[Ant] or +xref:../devGuideDB/ltw.adoc#weaver-options[LTW]. [cols=",",options="header",] |=== @@ -58,9 +59,9 @@ output .class files.) |`messageHolderClass`/ `-XmessageHolderClass:` |In Ant tasks and LTW respectively specify the class to receive all messages. See -xref:../devguide/antTasks-iajc.html#antTasks-iajc-options[iajc task +xref:../devGuideDB/antsupport.adoc#antTasks-iajc-options[iajc task options] or -xref:../devguide/ltw-configuration.html#weaver-options[Weaver Options]. +xref:../devGuideDB/ltw.adoc#weaver-options[Weaver Options]. |=== [cols=",",options="header",] diff --git a/docs/pdGuideDB/pdguide.adoc b/docs/pdGuideDB/pdguide.adoc new file mode 100644 index 000000000..dcbcfc331 --- /dev/null +++ b/docs/pdGuideDB/pdguide.adoc @@ -0,0 +1,50 @@ += The AspectJ^TM^ Problem Diagnosis Guide + +:doctype: book + +_by the AspectJ Team_ + +_Copyright (c) 2006 IBM Corporation and others. 2006 Contributors. All rights reserved._ + +This guide describes how to configure the AspectJ compiler/weaver to provide +information for diagnosing problems in the input programs, the +compiler/weaver or its configuration. + +The AspectJ compiler and weaver can provide lots of information for diagnosing +problems in building AspectJ programs. For problems in the input program, +there are a number of default warning and error messages, as well as many +configurable "lint" messages, all of which can be emitted normally, +logged using standard facilities, or intercepted programmatically. +These are discussed in xref:messages.adoc#messages[Messages]. Since most errors +relate to writing pointcuts incorrectly, there is a section on +xref:pointcuts.adoc#pointcuts[Debugging Pointcuts]. + +For problems with the compiler/weaver itself there are three facilities +that enable the AspectJ developers to resolve bugs even when it is +too hard to deliver a reproducible test case: + +* xref:trace.adoc#trace[Tracing] can be enabled to track progress up to the time of a failure; +* xref:ajcore.adoc#ajcore[AspectJ Core Files] can give a relatively complete picture of the state of + the world at the time of a failure; and +* xref:ltwdump.adoc#ltwdump[Dumping classes during load-time weaving] is a way to capture both input and output classes during load-time weaving. + +This guide describes how to configure messages to get the right information +and how to configure traces, dumps, and core files. Although the compiler/weaver +operates in roughly three modes (from the command-line, embedded in an IDE, +and enabled as load-time weaving), the principles are basically the same for +all modes. The differences lie in how to set up diagnostics and what +information is likely to be relevant. + +//// +ATTENTION: Please do not remove blank lines in between 'include::' statements. Otherwise, section numbers in the +table of contents (TOC) can be wrong and the first section of each document missing completely. +//// +include::messages.adoc[Messages] + +include::pointcuts.adoc[Debugging Pointcuts] + +include::trace.adoc[Tracing] + +include::ajcore.adoc[AspectJ Core Files] + +include::ltwdump.adoc[Dumping classes during load-time weaving] diff --git a/docs/pdGuideDB/pdguide.xml b/docs/pdGuideDB/pdguide.xml index 08af6fe28..619f54052 100644 --- a/docs/pdGuideDB/pdguide.xml +++ b/docs/pdGuideDB/pdguide.xml @@ -22,7 +22,7 @@ Copyright (c) 2006 IBM Corporation and others. - 2006 Contributors. + 2006 Contributors. All rights reserved. @@ -30,28 +30,28 @@ This guide describes how to configure the AspectJ compiler/weaver to provide - information for diagnosing problems in the input programs, the + information for diagnosing problems in the input programs, the compiler/weaver or its configuration. The AspectJ compiler and weaver can provide lots of information for diagnosing problems in building AspectJ programs. For problems in the input program, - there are a number of default warning and error messages, as well as many - configurable "lint" messages, all of which can be emitted normally, - logged using standard facilities, or intercepted programmatically. + there are a number of default warning and error messages, as well as many + configurable "lint" messages, all of which can be emitted normally, + logged using standard facilities, or intercepted programmatically. These are discussed in . Since most errors - relate to writing pointcuts incorrectly, there is a section on + relate to writing pointcuts incorrectly, there is a section on . For problems with the compiler/weaver itself there are three facilities that enable the AspectJ developers to resolve bugs even when it is - too hard to deliver a reproducible test case: + too hard to deliver a reproducible test case: can be enabled to track progress up to the time of a failure; - can give a relatively complete picture of the state of + can give a relatively complete picture of the state of the world at the time of a failure; and - is a way to capture both + is a way to capture both input and output classes during load-time weaving. @@ -59,14 +59,14 @@ This guide describes how to configure messages to get the right information and how to configure traces, dumps, and core files. Although the compiler/weaver - operates in roughly three modes (from the command-line, embedded in an IDE, - and enabled as load-time weaving), the principles are basically the same for - all modes. The differences lie in how to set up diagnostics and what - information is likely to be relevant. - - + operates in roughly three modes (from the command-line, embedded in an IDE, + and enabled as load-time weaving), the principles are basically the same for + all modes. The differences lie in how to set up diagnostics and what + information is likely to be relevant. + + - + &messages; &pointcuts; &ajcore; @@ -74,4 +74,3 @@ <wdump; - diff --git a/docs/pdGuideDB/pointcuts.adoc b/docs/pdGuideDB/pointcuts.adoc index 66e133e65..7f17ae94b 100644 --- a/docs/pdGuideDB/pointcuts.adoc +++ b/docs/pdGuideDB/pointcuts.adoc @@ -16,17 +16,23 @@ compile-time, can save a lot of time. [[pointcuts-debugging]] === Debugging pointcuts -Go at it top-down and then bottom-up. Top-down, draft significant +Go at it top-down and then bottom-up. + +==== Top-down + +Top-down, draft significant aspects by first writing the comments to specify responsibilities. -Advice responsibility usually takes the form, "When X, do Y." Pointcut -responsibility for "When X" often takes the form, "When [join points] -[in locations] [are ...]". These []'s often translate to named pointcuts -(like `libraryCalls() && within(Client) && args(Context)`) which form a -semantic bridge to the plain-text meaning in a comment (e.g., `// when -the client passes only context into the library`). This gets you to a +Advice responsibility usually takes the form, _"When X, do Y"_. Pointcut +responsibility for _"When X"_ often takes the form, _"When [join points] +[in locations] [are ...]"_. These __[]__'s often translate to named pointcuts +like `libraryCalls() && within(Client) && args(Context)`, which form a +semantic bridge to the plain-text meaning in a comment, e.g. `// when +the client passes only context into the library`. This gets you to a point where you can debug the parts of the pointcut independently. -Bottom up (to build each part), consider each primitive pointcut +==== Bottom-up + +Bottom-up (to build each part), consider each primitive pointcut designator (PCD), then the composition, and then any implicit constraints: @@ -43,7 +49,7 @@ each join point? This translates to `this()`, `target()`, `args()`, . Are there any advice or implementation limitations at issue? This involves knowing the few constraints on AspectJ imposed by Java bytecode as listed in the AspectJ Programming Guide section on -xref:../progguide/implementation.html[Implementation Notes]. +xref:../progGuideDB/implementation.adoc#implementation[Implementation Notes]. It's much faster to iterate a pointcut at compile-time using declare warning (even better, some errors are identified at parse-time in the @@ -53,42 +59,52 @@ listed above). If compiles themselves take too long because of all the AspectJ weaving, then try to only include the debugging aspect with the prototype pointcut, and limit the scope using `within(..)`. -Some mistakes in primitive pointcuts: +=== Common pointcut mistakes + +There are some typical types of mistakes developers make when designing pointcuts. +Here are a few examples: + +==== Mistakes in primitive pointcuts * `this(Foo) && execution(static * *(..))`: There is no `this` in a static context, so `this()` or `target()` should not be used in a static context or when targetting a static context (respectively). This happens -most often when you want to say things like "all calls to Foo from Bar" -and you only pick out calls to instance methods of Foo or you try to -pick out calls from static methods of Bar. +most often when you want to say things like "all calls to `Foo` from ``Bar``" +and you only pick out calls to instance methods of `Foo` or you try to +pick out calls from static methods of `Bar`. + * `target(Foo) && call(new(..)`: This will never match. In constructor-call join points, there is no target because the object has not been created yet. + * `call(* Foo.*(..))`: `Foo` refers to the compile-time type of the invoking reference, not the implementing class. In Java before 1.4, the compile-time type was rendered as the defining type, not the reference type; this was corrected in 1.4 (as shown when using ajc with the -1.4 flag) Most people should use `target(Foo) && call(...)`. -* `execution(* Foo.bar(..))`: An execution join point for Foo is always -within Foo, so this won't pick out any overrides of bar(..). Use + +* `execution(* Foo.bar(..))`: An execution join point for `Foo` is always +within `Foo`, so this won't pick out any overrides of `bar(..)`. Use `target(Foo) && execution(* bar(..))` for instance methods. + * `within(Foo)`: anonymous types are not known at weave-time to be within the lexically-enclosing type (a limitation of Java bytecode). -Some mistakes in composition: +==== Mistakes in composition * `call(* foo(Bar, Foo)) && args(Foo)`: This will never match. The parameters in `args(..)` are position-dependent, so `args(Foo)` only picks out join points where there is only one argument possible, of type -Foo. Use the indeterminate-arguments operator '..' as needed, e.g., +Foo. Use the indeterminate-arguments operator `..` as needed, e.g., `args(Foo, ..)`. + * `call(* foo()) && execution(* foo())`: This will never match. Each pointcut must be true at each join point matched. For a union of -different kinds of join points (here, call or execution), use '||'. -E.g., to match both method-call and field-get join points, use `call(* -...) || get(...)`. +different kinds of join points (here, call or execution), use `||`. +E.g., to match both method-call and field-get join points, use +`call(* ...) || get(...)`. -Some mistakes in implicit advice constraints: +==== Mistakes in implicit advice constraints * `after () returning (Foo foo) : ...`: after advice can bind the returned object or exception thrown. That effectively acts like @@ -96,18 +112,19 @@ returned object or exception thrown. That effectively acts like based on the runtime type of the bound object, even though it is not explicitly part of the pointcut. -Some mistakes in implementation requirements: +==== Mistakes in implementation requirements -* `ajc` has to control the code for a join point in order to implement -the join point. This translates to an implicit `within(\{code under the +* _ajc_ has to control the code for a join point in order to implement +the join point. This translates to an implicit `within({code under the control of the compiler})` for all join points, with additional caveat for some join points. Take exception handlers, for example: there is no way to be sure from the bytecode where the original handler ends, so -`ajc` can't implement after advice on handler join points. (Since these +_ajc_ can't implement after advice on handler join points. (Since these are on a per-join-point basis, they should be considered for each corresponding primitive pointcut designator.) Unlike the mistakes with the primitive PCDs above, the compiler will emit an error for these caveats. + * `call(@SuperAnnotation Subclass.meth()`: Annotations are not inherited by default, so e.g., if the pointcut specifies an annotation, then subclass implementations of that method will not be matched. diff --git a/docs/progGuideDB/examples.adoc b/docs/progGuideDB/examples.adoc index 5b20a1b4e..f01ae46d8 100644 --- a/docs/progGuideDB/examples.adoc +++ b/docs/progGuideDB/examples.adoc @@ -1,3 +1,4 @@ +[[examples]] == Examples [[examples-intro]] @@ -83,12 +84,13 @@ and one of the argument values of the method calls directly. [source, java] .... -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 x): + target(p) && + args(x) && + call(void setX(int)) +{ + if (!p.assertX(x)) + System.out.println("Illegal value for x"); return; } .... @@ -98,8 +100,9 @@ when any method of some class is executed. The pointcut [source, java] .... -pointcut execsInProblemClass(): within(ProblemClass) - && execution(* *(..)); +pointcut execsInProblemClass(): + within(ProblemClass) && + execution(* *(..)); .... will pick out each execution join point of every method defined within @@ -132,26 +135,26 @@ within its `main` method. [source, java] .... public class Demo { - static Demo d; + static Demo d; - public static void main(String[] args){ - new Demo().go(); - } + 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 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"); - } + 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 + ")"; - } + String bar (Integer j) { + System.out.println("Demo.bar(" + j + ")\n"); + return "Demo.bar(" + j + ")"; + } } .... @@ -165,35 +168,36 @@ This aspect uses around advice to intercept the execution of methods .... 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]); - } - } + 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]); + } + } } .... @@ -305,30 +309,30 @@ We also define a test `main` method in the aspect for convenience. .... 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 ); - } + 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); + } } .... @@ -341,11 +345,9 @@ The interface `Comparable` defines the single method `compareTo` which can be use to define a natural ordering relation among the objects of a class that implement it. -`ComparablePoint` uses `declare - parents` to declare that `Point implements - Comparable`, and also publically declares the appropriate -`compareTo(Object)` method: A `Point` `p1` is said to be less than -another `Point p2` if `p1` is closer to the origin. +`ComparablePoint` uses `declare parents` to declare that `Point implements Comparable`, +and also publically declares the appropriate `compareTo(Object)` method: +A `Point` `p1` is said to be less than another `Point p2` if `p1` is closer to the origin. We also define a test `main` method in the aspect for convenience. @@ -353,35 +355,35 @@ We also define a test `main` method in the aspect for convenience. .... public aspect ComparablePoint { - declare parents: Point implements Comparable; + declare parents: Point implements Comparable; - public int Point.compareTo(Object o) { - return (int) (this.getRho() - ((Point)o).getRho()); - } + 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(); + public static void main(String[] args) { + Point p1 = new Point(); + Point p2 = new Point(); - System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); - p1.setRectangular(2,5); - p2.setRectangular(2,5); - 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)); + 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.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.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)); - } + p1.offset(1,1); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + } } .... @@ -416,34 +418,34 @@ And again, we supply a `main` method in the aspect for testing. .... public aspect HashablePoint { - public int Point.hashCode() { - return (int) (getX() + getY() % Integer.MAX_VALUE); - } + 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 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(); + public static void main(String[] args) { + Hashtable h = new Hashtable(); + Point p1 = new Point(); - p1.setRectangular(10, 10); - Point p2 = new Point(); + p1.setRectangular(10, 10); + Point p2 = new Point(); - p2.setRectangular(10, 10); + 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()); + 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)); - } + h.put(p1, "P1"); + System.out.println("Got: " + h.get(p2)); + } } .... @@ -489,22 +491,22 @@ class is the root of the shape hierarchy: [source, java] .... 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) + ") "); - } + 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) + ") "); + } } .... @@ -513,44 +515,44 @@ public abstract class TwoDShape { [source, java] .... 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()); - } + 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()); + } } .... [source, java] .... 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()); - } + 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()); + } } .... @@ -594,10 +596,10 @@ public interface is: [source, java] .... 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) {...} + public static int TRACELEVEL = 0; + public static void initStream(PrintStream s) {...} + public static void traceEntry(String str) {...} + public static void traceExit(String str) {...} } .... @@ -612,23 +614,23 @@ that more consistently and reliably with the following aspect (found in [source, java] .... public aspect TraceMyClasses { - pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); - pointcut myConstructor(): myClass() && execution(new(..)); - pointcut myMethod(): myClass() && execution(* *(..)); + 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 (): myConstructor() { + Trace.traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myConstructor() { + Trace.traceExit("" + thisJoinPointStaticPart.getSignature()); + } - before (): myMethod() { - Trace.traceEntry("" + thisJoinPointStaticPart.getSignature()); - } - after(): myMethod() { - Trace.traceExit("" + thisJoinPointStaticPart.getSignature()); - } + before (): myMethod() { + Trace.traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myMethod() { + Trace.traceExit("" + thisJoinPointStaticPart.getSignature()); + } } .... @@ -717,12 +719,11 @@ functionality of `Trace - version1` with the crosscutting support of [source, java] .... 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(); + 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(); } .... @@ -732,13 +733,13 @@ our application classes, in `version2/TraceMyClasses.java`: [source, java] .... public aspect TraceMyClasses extends Trace { - pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); + pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); - public static void main(String[] args) { - Trace.TRACELEVEL = 2; - Trace.initStream(System.err); - ExampleMain.main(args); - } + public static void main(String[] args) { + Trace.TRACELEVEL = 2; + Trace.initStream(System.err); + ExampleMain.main(args); + } } .... @@ -751,7 +752,7 @@ tracing, go to the directory `examples` and type: ajc -argfile tracing/tracev2.lst .... -The file tracev2.lst lists the application classes as well as this +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 `tracing.version2.TraceMyClasses` should output exactly the same trace information as that from version 1. @@ -762,58 +763,58 @@ The entire implementation of the new `Trace` class is: .... abstract aspect Trace { - // implementation part + // implementation part - public static int TRACELEVEL = 2; - protected static PrintStream stream = System.err; - protected static int callDepth = 0; + 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(" "); - } + 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 + // protocol part - abstract pointcut myClass(); + abstract pointcut myClass(); - pointcut myConstructor(): myClass() && execution(new(..)); - pointcut myMethod(): myClass() && execution(* *(..)); + pointcut myConstructor(): myClass() && execution(new(..)); + pointcut myMethod(): myClass() && execution(* *(..)); - before(): myConstructor() { - traceEntry("" + thisJoinPointStaticPart.getSignature()); - } - after(): myConstructor() { - traceExit("" + thisJoinPointStaticPart.getSignature()); - } + before(): myConstructor() { + traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myConstructor() { + traceExit("" + thisJoinPointStaticPart.getSignature()); + } - before(): myMethod() { - traceEntry("" + thisJoinPointStaticPart.getSignature()); - } - after(): myMethod() { - traceExit("" + thisJoinPointStaticPart.getSignature()); - } + before(): myMethod() { + traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myMethod() { + traceExit("" + thisJoinPointStaticPart.getSignature()); + } } .... @@ -860,13 +861,13 @@ bean are few. Beans must define a no-argument constructor and must be either `Serializable` or `Externalizable`. Any properties of the object that are to be treated as bean properties should be indicated by the presence of appropriate `get` and `set` methods whose names are -`get`__property__ and `set `__property__ where _property_ is the name of +`get__property__` and `set__property__` where `__property__` 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__property__ methods. +change the property values, such as `set__property__` methods. `Point` is a simple class representing points with rectangular coordinates. `Point` does not know anything about being a bean: there @@ -945,13 +946,10 @@ property change support object: public void Point.addPropertyChangeListener(PropertyChangeListener listener){ support.addPropertyChangeListener(listener); } -public void Point.addPropertyChangeListener(String propertyName, - PropertyChangeListener listener){ - +public void Point.addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { support.addPropertyChangeListener(propertyName, listener); } -public void Point.removePropertyChangeListener(String propertyName, - PropertyChangeListener listener) { +public void Point.removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { support.removePropertyChangeListener(propertyName, listener); } public void Point.removePropertyChangeListener(PropertyChangeListener listener) { @@ -986,16 +984,13 @@ called. aspect BoundPoint { private PropertyChangeSupport Point.support = new PropertyChangeSupport(this); - public void Point.addPropertyChangeListener(PropertyChangeListener listener){ + public void Point.addPropertyChangeListener(PropertyChangeListener listener) { support.addPropertyChangeListener(listener); } - public void Point.addPropertyChangeListener(String propertyName, - PropertyChangeListener listener){ - + public void Point.addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { support.addPropertyChangeListener(propertyName, listener); } - public void Point.removePropertyChangeListener(String propertyName, - PropertyChangeListener listener) { + public void Point.removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { support.removePropertyChangeListener(propertyName, listener); } public void Point.removePropertyChangeListener(PropertyChangeListener listener) { @@ -1010,25 +1005,20 @@ aspect BoundPoint { 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")){ + 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 { + } 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)); + void firePropertyChange(Point p, String property, double oldval, double newval) { + p.support.firePropertyChange(property, new Double(oldval), new Double(newval)); } } .... @@ -1048,11 +1038,13 @@ 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() ); + System.out.println( + "Property " + e.getPropertyName() + " changed from " + + e.getOldValue() + " to " + e.getNewValue() + ); } - public static void main(String[] args){ + public static void main(String[] args) { Point p1 = new Point(); p1.addPropertyChangeListener(new Demo()); System.out.println("p1 =" + p1); @@ -1067,8 +1059,8 @@ class Demo implements PropertyChangeListener { Point p2 = (Point) restore(fileName); System.out.println("Had: " + p1); System.out.println("Got: " + p2); - } - ... + } + // ... } .... @@ -1114,10 +1106,10 @@ changes: [source, java] .... interface Subject { - void addObserver(Observer obs); - void removeObserver(Observer obs); - Vector getObservers(); - Object getData(); + void addObserver(Observer obs); + void removeObserver(Observer obs); + Vector getObservers(); + Object getData(); } .... @@ -1127,9 +1119,9 @@ The `Observer` interface is just as simple, with methods to set and get [source, java] .... interface Observer { - void setSubject(Subject s); - Subject getSubject(); - void update(); + void setSubject(Subject s); + Subject getSubject(); + void update(); } .... @@ -1141,28 +1133,28 @@ objects' update methods when some state changes in a subject. .... abstract aspect SubjectObserverProtocol { - abstract pointcut stateChanges(Subject s); + 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(); - } + 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 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; } + private Subject Observer.subject = null; + public void Observer.setSubject(Subject s) { subject = s; } + public Subject Observer.getSubject() { return subject; } } .... @@ -1182,25 +1174,24 @@ the `void click()` method is called whenever a button is clicked. .... 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() {} + 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() {} } .... @@ -1213,21 +1204,21 @@ Again, they know nothing about being an observer. .... class ColorLabel extends Label { - ColorLabel(Display display) { - super(); - display.addToFrame(this); - } + 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); - } + 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); + } } .... @@ -1243,17 +1234,17 @@ import java.util.Vector; aspect SubjectObserverProtocolImpl extends SubjectObserverProtocol { - declare parents: Button implements Subject; - public Object Button.getData() { return this; } + declare parents: Button implements Subject; + public Object Button.getData() { return this; } - declare parents: ColorLabel implements Observer; - public void ColorLabel.update() { - colorCycle(); - } + declare parents: ColorLabel implements Observer; + public void ColorLabel.update() { + colorCycle(); + } - pointcut stateChanges(Subject s): - target(s) && - call(void Button.click()); + pointcut stateChanges(Subject s): + target(s) && + call(void Button.click()); } .... @@ -1293,17 +1284,17 @@ which customers make, accept, merge and hang-up both local and long distance calls. The application architecture is in three layers. * The basic objects provide basic functionality to simulate customers, -calls and connections (regular calls have one connection, conference -calls have more than one). + calls and connections (regular calls have one connection, conference + calls have more than one). * 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. + 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. * 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. + 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. The simulation of system has three configurations: basic, timing and billing. Programs for the three configurations are in classes @@ -1321,7 +1312,9 @@ have methods for managing calls. Simple calls are made between one customer (the caller) and another (the receiver), a `Connection` 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. image:telecom.gif[image] +involved in many calls at one time. + +image:telecom.gif[image] ===== The `Customer` class @@ -1332,56 +1325,56 @@ managing calls. .... public class Customer { - private String name; - private int areacode; - private Vector calls = new Vector(); + private String name; + private int areacode; + private Vector calls = new Vector(); - protected void removeCall(Call c){ - calls.removeElement(c); - } + protected void removeCall(Call c){ + calls.removeElement(c); + } - protected void addCall(Call c){ - calls.addElement(c); - } + protected void addCall(Call c){ + calls.addElement(c); + } - public Customer(String name, int areacode) { - this.name = name; - this.areacode = areacode; - } + public Customer(String name, int areacode) { + this.name = name; + this.areacode = areacode; + } - public String toString() { - return name + "(" + areacode + ")"; - } + public String toString() { + return name + "(" + areacode + ")"; + } - public int getAreacode(){ - return areacode; - } + public int getAreacode(){ + return areacode; + } - public boolean localTo(Customer other){ - return areacode == other.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 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 pickup(Call call) { + call.pickup(); + addCall(call); + } - public void hangup(Call call) { - call.hangup(this); - removeCall(call); - } + public void hangup(Call call) { + call.hangup(this); + removeCall(call); + } - public void merge(Call call1, Call call2){ - call1.merge(call2); - removeCall(call2); - } + public void merge(Call call1, Call call2){ + call1.merge(call2); + removeCall(call2); } +} .... ===== The `Call` class @@ -1407,39 +1400,39 @@ concrete subclasses: `Local` and `LongDistance`. .... abstract class Connection { - public static final int PENDING = 0; - public static final int COMPLETE = 1; - public static final int DROPPED = 2; + 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; + Customer caller, receiver; + private int state = PENDING; - Connection(Customer a, Customer b) { - this.caller = a; - this.receiver = b; - } + Connection(Customer a, Customer b) { + this.caller = a; + this.receiver = b; + } - public int getState(){ - return state; - } + public int getState(){ + return state; + } - public Customer getCaller() { return caller; } + public Customer getCaller() { return caller; } - public Customer getReceiver() { return receiver; } + public Customer getReceiver() { return receiver; } - void complete() { - state = COMPLETE; - System.out.println("connection completed"); - } + void complete() { + state = COMPLETE; + System.out.println("connection completed"); + } - void drop() { - state = DROPPED; - System.out.println("connection dropped"); - } + void drop() { + state = DROPPED; + System.out.println("connection dropped"); + } - public boolean connects(Customer c){ - return (caller == c || receiver == c); - } + public boolean connects(Customer c){ + return (caller == c || receiver == c); + } } .... @@ -1452,22 +1445,24 @@ The two kinds of connections supported by our simulation are `Local` and [source, java] .... class Local extends Connection { - Local(Customer a, Customer b) { - super(a, b); - System.out.println("[new local connection from " + - a + " to " + b + "]"); - } + Local(Customer a, Customer b) { + super(a, b); + System.out.println( + "[new local connection from " + a + " to " + b + "]" + ); + } } .... [source, java] .... class LongDistance extends Connection { - LongDistance(Customer a, Customer b) { - super(a, b); - System.out.println("[new long distance connection from " + - a + " to " + b + "]"); - } + LongDistance(Customer a, Customer b) { + super(a, b); + System.out.println( + "[new long distance connection from " + a + " to " + b + "]" + ); + } } .... @@ -1499,20 +1494,20 @@ times to be printed to standard output. [source, java] .... class Timer { - long startTime, stopTime; + long startTime, stopTime; - public void start() { - startTime = System.currentTimeMillis(); - stopTime = startTime; - } + public void start() { + startTime = System.currentTimeMillis(); + stopTime = startTime; + } - public void stop() { - stopTime = System.currentTimeMillis(); - } + public void stop() { + stopTime = System.currentTimeMillis(); + } - public long getTime() { - return stopTime - startTime; - } + public long getTime() { + return stopTime - startTime; + } } .... @@ -1525,13 +1520,13 @@ announce when it is started and stopped. .... 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.start()) { + System.err.println("Timer started: " + t.startTime); + } - after(Timer t): target(t) && call(* Timer.stop()) { - System.err.println("Timer stopped: " + t.stopTime); - } + after(Timer t): target(t) && call(* Timer.stop()) { + System.err.println("Timer stopped: " + t.stopTime); + } } .... @@ -1555,26 +1550,26 @@ connection is completed and and stopped when it is dropped. The pointcut .... public aspect Timing { - public long Customer.totalConnectTime = 0; + 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; } + 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(); - } + after (Connection c): target(c) && call(void Connection.complete()) { + getTimer(c).start(); + } - pointcut endTiming(Connection c): target(c) && - call(void Connection.drop()); + 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(); - } + after(Connection c): endTiming(c) { + getTimer(c).stop(); + c.getCaller().totalConnectTime += getTimer(c).getTime(); + c.getReceiver().totalConnectTime += getTimer(c).getTime(); + } } .... @@ -1597,38 +1592,38 @@ to handle the `totalCharge`. [source, java] .... public aspect Billing { - // precedence required to get advice on endtiming in the right order - declare precedence: Billing, Timing; + // 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 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; } + 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; - } + after(Customer cust) returning (Connection conn): + args(cust, ..) && call(Connection+.new(..)) { + conn.payer = cust; + } - public abstract long Connection.callRate(); + public abstract long Connection.callRate(); - public long LongDistance.callRate() { return LONG_DISTANCE_RATE; } - public long Local.callRate() { return LOCAL_RATE; } + 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); - } + 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 long Customer.totalCharge = 0; + public long getTotalCharge(Customer cust) { return cust.totalCharge; } - public void Customer.addCharge(long charge){ - totalCharge += charge; - } + public void Customer.addCharge(long charge) { + totalCharge += charge; + } } .... @@ -1651,8 +1646,8 @@ intended to print out the status of the customer, with respect to the [source, java] .... protected void report(Customer c){ - Timing t = Timing.aspectOf(); - System.out.println(c + " spent " + t.getTotalConnectTime(c)); + Timing t = Timing.aspectOf(); + System.out.println(c + " spent " + t.getTotalConnectTime(c)); } .... @@ -1679,13 +1674,13 @@ java telecom.BillingSimulation ===== Discussion -There are some explicit dependencies between the aspects Billing and -Timing: +There are some explicit dependencies between the aspects `Billing` and +`Timing`: -* 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. -* Billing uses the pointcut Timing.endTiming. -* Billing needs access to the timer associated with a connection. +* `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. +* `Billing` uses the pointcut `Timing.endTiming`. +* `Billing` needs access to the timer associated with a connection. [[examples-reusable]] === Reusable Aspects @@ -1696,7 +1691,7 @@ advice runs after that of Timing when they are on the same join point. ===== Tracing - Version 3 -One advantage of not exposing the methods traceEntry and traceExit as +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. @@ -1742,7 +1737,7 @@ Trace.traceEntry("Square.distance", this); 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! +operations `traceEntry` and `traceExit` must be changed! Here's another advantage of doing tracing with an aspect. We've already seen that in version 2 `traceEntry` and `traceExit` are not publicly @@ -1755,60 +1750,60 @@ to version 2 are stressed in the comments: .... abstract aspect Trace { - public static int TRACELEVEL = 0; - protected static PrintStream stream = null; - protected static int callDepth = 0; + public static int TRACELEVEL = 0; + protected static PrintStream stream = null; + protected static int callDepth = 0; - public static void initStream(PrintStream s) { - stream = s; - } + 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 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--; - } + 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 printEntering(String str) { + printIndent(); + stream.println("Entering " + str); + } - private static void printExiting(String str) { - printIndent(); - stream.println("Exiting " + 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(" "); - } + private static void printIndent() { + for (int i = 0; i < callDepth; i++) + stream.print(" "); + } - abstract pointcut myClass(Object obj); + abstract pointcut myClass(Object obj); - pointcut myConstructor(Object obj): myClass(obj) && execution(new(..)); - pointcut myMethod(Object obj): myClass(obj) && - execution(* *(..)) && !execution(String toString()); + 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): 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); - } + before(Object obj): myMethod(obj) { + traceEntry("" + thisJoinPointStaticPart.getSignature(), obj); + } + after(Object obj): myMethod(obj) { + traceExit("" + thisJoinPointStaticPart.getSignature(), obj); + } } .... @@ -1834,7 +1829,7 @@ calls back to the objects, there is always the possibility of recursion. Keep that in mind! 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, +if there are calls to other traced methods within it - in which case, the restriction should be [source, java] @@ -1842,7 +1837,7 @@ the restriction should be && !cflow(execution(String toString())) .... -excluding both the execution of toString methods and all join points +excluding both the execution of `toString` methods and all join points under that execution. In summary, to implement the change in the tracing requirements we had @@ -1860,7 +1855,7 @@ and type: ajc -argfile tracing/tracev3.lst .... -The file tracev3.lst lists the application classes as well as this +The file `tracev3.lst` lists the application classes as well as this version of the files `Trace.java` and `TraceMyClasses.java`. To run the program, type diff --git a/docs/progGuideDB/gettingstarted.adoc b/docs/progGuideDB/gettingstarted.adoc index f22c9cefd..c4bb4eb25 100644 --- a/docs/progGuideDB/gettingstarted.adoc +++ b/docs/progGuideDB/gettingstarted.adoc @@ -188,11 +188,11 @@ form. So the following declares a new, named pointcut: [source, java] .... 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)); + 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)); .... and whenever this definition is visible, the programmer can simply use @@ -255,7 +255,7 @@ call are evaluated. [source, java] .... before(): move() { - System.out.println("about to move"); + System.out.println("about to move"); } .... @@ -271,7 +271,7 @@ throwing, like Java's `finally`). [source, java] .... after() returning: move() { - System.out.println("just successfully moved"); + System.out.println("just successfully moved"); } .... @@ -292,8 +292,9 @@ advice [source, java] .... after(FigureElement fe, int x, int y) returning: - ...SomePointcut... { - ...SomeBody... + // SomePointcut... +{ + // SomeBody } .... @@ -305,8 +306,9 @@ The body of the advice uses the names just like method parameters, so [source, java] .... after(FigureElement fe, int x, int y) returning: - ...SomePointcut... { - System.out.println(fe + " moved to (" + x + ", " + y + ")"); + // SomePointcut... +{ + System.out.println(fe + " moved to (" + x + ", " + y + ")"); } .... @@ -317,10 +319,11 @@ publish these values. So now we can write the complete piece of advice: [source, java] .... 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 + ")"); + call(void FigureElement.setXY(int, int)) + && target(fe) + && args(x, y) +{ + System.out.println(fe + " moved to (" + x + ", " + y + ")"); } .... @@ -341,12 +344,12 @@ pointcut. So another way to write the above advice is [source, java] .... pointcut setXY(FigureElement fe, int x, int y): - call(void FigureElement.setXY(int, int)) - && target(fe) - && args(x, 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 + ")."); + System.out.println(fe + " moved to (" + x + ", " + y + ")."); } .... @@ -378,8 +381,8 @@ observing ``Point``s. [source, java] .... aspect PointObserving { - private Vector Point.observers = new Vector(); - ... + private Vector Point.observers = new Vector(); + // ... } .... @@ -390,15 +393,15 @@ and `removeObserver` on the aspect. [source, java] .... 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); - } - ... + 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); + } + //... } .... @@ -409,27 +412,27 @@ observe a change. [source, java] .... aspect PointObserving { - private Vector Point.observers = new Vector(); + 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); - } + 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)); + 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()); - } + 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); - } + static void updateObserver(Point p, Screen s) { + s.display(p); + } } .... @@ -454,11 +457,11 @@ the aspect, if it needs to keep state around: [source, java] .... aspect Logging { - OutputStream logStream = System.err; + OutputStream logStream = System.err; - before(): move() { - logStream.println("about to move"); - } + before(): move() { + logStream.println("about to move"); + } } .... @@ -491,12 +494,12 @@ such aspect might simply trace whenever points are drawn. [source, java] .... aspect SimpleTracing { - pointcut tracedCall(): - call(void FigureElement.draw(GraphicsContext)); + pointcut tracedCall(): + call(void FigureElement.draw(GraphicsContext)); - before(): tracedCall() { - System.out.println("Entering: " + thisJoinPoint); - } + before(): tracedCall() { + System.out.println("Entering: " + thisJoinPoint); + } } .... @@ -525,7 +528,7 @@ code look bad, and can cause trace statements for one kind of debugging to get confused with trace statements for another kind of debugging. 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. +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. @@ -551,17 +554,19 @@ to `rotate`: [source, java] .... 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++; - } + 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++; + } } .... @@ -569,32 +574,17 @@ In effect, this aspect allows the programmer to ask very specific questions like ____ -How many times is the - -rotate - -method defined on - -Line - -objects called? +How many times is the `rotate` method defined on `Line` objects called? ____ and ____ -How many times are methods defined on - -Point - -objects whose name begins with " - -set - -" called in fulfilling those rotate calls? +How many times are methods defined on `Point` objects whose name begins with +`"set"` called in fulfilling those `rotate` calls? ____ -questions it may be difficult to express using standard profiling or +Such questions may be difficult to express using standard profiling or logging tools. [[pre-and-post-conditions]] @@ -613,23 +603,23 @@ in modular form. For example, this code .... aspect PointBoundsChecking { - pointcut setX(int x): - (call(void FigureElement.setXY(int, int)) && args(x, *)) - || (call(void Point.setX(int)) && args(x)); + 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)); + 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 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."); - } + before(int y): setY(y) { + if ( y < MIN_Y || y > MAX_Y ) + throw new IllegalArgumentException("y is out of bounds."); + } } .... @@ -661,13 +651,12 @@ ensures that no figure element is added to the registry more than once. .... aspect RegistrationProtection { - pointcut register(): call(void Registry.register(FigureElement)); - - pointcut canRegister(): withincode(static * FigureElement.make*(..)); + pointcut register(): call(void Registry.register(FigureElement)); + pointcut canRegister(): withincode(static * FigureElement.make*(..)); - before(): register() && !canRegister() { - throw new IllegalAccessException("Illegal call " + thisJoinPoint); - } + before(): register() && !canRegister() { + throw new IllegalAccessException("Illegal call " + thisJoinPoint); + } } .... @@ -688,10 +677,10 @@ _compiler_ signal the error. .... aspect RegistrationProtection { - pointcut register(): call(void Registry.register(FigureElement)); - pointcut canRegister(): withincode(static * FigureElement.make*(..)); + pointcut register(): call(void Registry.register(FigureElement)); + pointcut canRegister(): withincode(static * FigureElement.make*(..)); - declare error: register() && !canRegister(): "Illegal call" + declare error: register() && !canRegister(): "Illegal call" } .... @@ -748,24 +737,24 @@ advice on `move` sets the dirty flag whenever an object moves. [source, java] .... 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; - } + 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; + } } .... @@ -834,15 +823,16 @@ method on a `ColorControllingClient`. [source, java] .... aspect ColorControl { - pointcut CCClientCflow(ColorControllingClient client): - cflow(call(* * (..)) && target(client)); + pointcut CCClientCflow(ColorControllingClient client): + cflow(call(* * (..)) && target(client)); - pointcut make(): call(FigureElement Figure.make*(..)); + pointcut make(): call(FigureElement Figure.make*(..)); - after (ColorControllingClient c) returning (FigureElement fe): - make() && CCClientCflow(c) { - fe.setColor(c.colorFor(fe)); - } + after (ColorControllingClient c) returning (FigureElement fe): + make() && CCClientCflow(c) + { + fe.setColor(c.colorFor(fe)); + } } .... @@ -869,14 +859,14 @@ Error and then the throw resumes. [source, java] .... aspect PublicErrorLogging { - Log log = new Log(); + Log log = new Log(); - pointcut publicMethodCall(): - call(public * com.bigboxco.*.*(..)); + pointcut publicMethodCall(): + call(public * com.bigboxco.*.*(..)); - after() throwing (Error e): publicMethodCall() { - log.write(e); - } + after() throwing (Error e): publicMethodCall() { + log.write(e); + } } .... @@ -890,8 +880,9 @@ these re-entrant calls: [source, java] .... after() throwing (Error e): - publicMethodCall() && !cflow(publicMethodCall()) { - log.write(e); + publicMethodCall() && !cflow(publicMethodCall()) +{ + log.write(e); } .... @@ -904,26 +895,24 @@ and `parseExpr`. [source, java] .... 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; - } + 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; + } } .... This example exhibits a property found in many aspects with large property-based pointcuts. In addition to a general property based pattern `call(* JavaParser.parse*(..))` it includes an exception to the -pattern `!call(Stmt - parseVarDec(boolean))`. The exclusion of `parseVarDec` happens +pattern `!call(Stmt parseVarDec(boolean))`. The exclusion of `parseVarDec` happens because the parsing of variable declarations in Java is too complex to fit with the clean pattern of the other `parse*` methods. Even with the explicit exclusion this aspect is a clear expression of a clean @@ -974,8 +963,8 @@ are also highly modular, making it possible to develop plug-and-play implementations of crosscutting functionality. AspectJ provides more functionality than was covered by this short -introduction. The next chapter, xref:language.adoc[The AspectJ Language], covers in detail +introduction. The next chapter, xref:language.adoc#language[The AspectJ Language], covers in detail more of the features of the AspectJ language. The following chapter, -xref:examples.adoc[Examples], then presents some carefully chosen examples that +xref:examples.adoc#examples[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. diff --git a/docs/progGuideDB/idioms.adoc b/docs/progGuideDB/idioms.adoc index 8e5f6e43e..e27395a48 100644 --- a/docs/progGuideDB/idioms.adoc +++ b/docs/progGuideDB/idioms.adoc @@ -7,62 +7,62 @@ 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. -Here's an example of how to enfore a rule that code in the java.sql +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. +This doesn't require any access to code in the `java.sql` package. [source, java] .... /* Any call to methods or constructors in java.sql */ pointcut restrictedCall(): - call(* java.sql.*.*(..)) || call(java.sql.*.new(..)); + 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.*); + within(com.foo..*) && !within(com.foo.sqlAccess.*); declare error: restrictedCall() && illegalSource(): - "java.sql package can only be accessed from com.foo.sqlAccess"; + "java.sql package can only be accessed from com.foo.sqlAccess"; .... -Any call to an instance of a subtype of AbstractFacade whose class is -not exactly equal to AbstractFacade: +Any call to an instance of a subtype of `AbstractFacade` whose class is +not exactly equal to `AbstractFacade`: [source, java] .... pointcut nonAbstract(AbstractFacade af): - call(* *(..)) - && target(af) - && !if(af.getClass() == AbstractFacade.class); + call(* *(..)) + && target(af) + && !if(af.getClass() == AbstractFacade.class); .... -If AbstractFacade is an abstract class or an interface, then every +If `AbstractFacade` is an abstract class or an interface, then every instance must be of a subtype and you can replace this with: [source, java] .... pointcut nonAbstract(AbstractFacade af): - call(* *(..)) - && target(af); + call(* *(..)) + && target(af); .... -Any call to a method which is defined by a subtype of AbstractFacade, -but which isn't defined by the type AbstractFacade itself: +Any call to a method which is defined by a subtype of `AbstractFacade`, +but which isn't defined by the type `AbstractFacade` itself: [source, java] .... pointcut callToUndefinedMethod(): - call(* AbstractFacade+.*(..)) - && !call(* AbstractFacade.*(..)); + call(* AbstractFacade+.*(..)) + && !call(* AbstractFacade.*(..)); .... 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: +that is a subtype of `AbstractFacade` but not in `AbstractFacade` itself: [source, java] .... pointcut executionOfUndefinedMethod(): - execution(* *(..)) - && within(AbstractFacade+) - && !within(AbstractFacade) + execution(* *(..)) + && within(AbstractFacade+) + && !within(AbstractFacade) .... diff --git a/docs/progGuideDB/implementation.adoc b/docs/progGuideDB/implementation.adoc index f7a8f7c7b..42ee2e37e 100644 --- a/docs/progGuideDB/implementation.adoc +++ b/docs/progGuideDB/implementation.adoc @@ -22,8 +22,8 @@ According to the AspectJ language semantics, the declaration before(): get(int Point.x) { System.out.println("got x"); } .... -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 +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. @@ -33,28 +33,27 @@ well-defined way -- they are permitted to advise only accesses in _code the implementation controls_. Each implementation is free within certain bounds to provide its own definition of what it means to control code. -In the current AspectJ compiler, ajc, control of the code means having +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 `new - Point().x` (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 +during the compile. This means that if some class `Client` contains code +with the expression `new Point().x` (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. Different join points have different requirements. Method and -constructor call join points can be advised only if ajc controls the +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 +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 +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 +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 +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. @@ -63,37 +62,36 @@ 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 `perthis` of that join point will not be associated. So aspects defined `perthis(Object)` will not create aspect instances for every -object unless `Object`is part of the compile. Similar restrictions apply +object unless `Object` is part of the compile. Similar restrictions apply to `pertarget` aspects. Inter-type declarations such as `declare parents` 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, `declare parents : String implements - MyInterface` will not work for `java.lang.String` unless -`java.lang.String` is part of the compile. +is not made on that target. So, `declare parents : String implements MyInterface` +will not work for `java.lang.String`, unless `java.lang.String` is part of the compile. 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 +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 +`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 +`public`. Finally, note that one cannot define `static` fields or methods on interfaces. -When declaring methods on target types, only methods declared public are -recognizable in the bytecode, so methods must be declared public to be +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. -Other AspectJ implementations, indeed, future versions of ajc, may +Other AspectJ implementations, indeed, future versions of _ajc_, may define _code the implementation controls_ more liberally or restrictively, so long as they comport with the Java language. For example, the `call` pointcut does not pick out reflective calls to a @@ -101,25 +99,25 @@ method implemented in `java.lang.reflect.Method.invoke(Object, Object[])`. 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 +control of the implementation, even when it is a well-defined API in a Java standard library. 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 +limitations of the _ajc_ compiler you're using, but these limitations should not drive the design of your aspects. === Bytecode Notes -[[the-class-expression-and-string]] -==== The .class expression and String + +[[the-class-expression-and-string-plus]] +==== The `.class` expression and `String` `+` The java language form `Foo.class` is implemented in bytecode with a call to `Class.forName` guarded by an exception handler catching a `ClassNotFoundException`. -The java language + operator, when applied to String arguments, is +The java language `+` operator, when applied to `String` arguments, is implemented in bytecode by calls to `StringBuffer.append`. In both of these cases, the current AspectJ compiler operates on the @@ -132,32 +130,32 @@ first glance, appear to contain such calls: [source, java] .... class Test { - void main(String[] args) { - System.out.println(Test.class); // calls Class.forName - System.out.println(args[0] + args[1]); // calls StringBuffer.append - } + void main(String[] args) { + System.out.println(Test.class); // calls Class.forName + System.out.println(args[0] + args[1]); // calls StringBuffer.append + } } .... In short, the join point model of the current AspectJ compiler considers these as valid join points. -==== The Handler join point +==== The `handler()` join point 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: +Instead of removing the `handler` join point entirely, the current AspectJ +compiler restricts what can be done with the `handler` join point: -* After and around advice cannot apply to handler join points. -* The control flow of a handler join point cannot be detected. +* `after` and `around` advice cannot apply to `handler` join points. +* The control flow of a `handler` join point cannot be detected. -The first of these is relatively straightforward. If any piece of after +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. +`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. -The second is that the control flow of a handler join point is not +The second is that the control flow of a `handler` join point is not picked out. For example, the following pointcut [source, java] @@ -179,7 +177,7 @@ fine: [source, java] .... before(): handler(java.io.IOException) && cflow(void parse()) { - System.out.println("about to handle an exception while parsing"); + System.out.println("about to handle an exception while parsing"); } .... @@ -189,18 +187,18 @@ have fewer such restrictions. ==== Initializers and Inter-type Constructors -The code for Java initializers, such as the assignment to the field d in +The code for Java initializers, such as the assignment to the field `d` in [source, java] .... class C { - double d = Math.sqrt(2); + double d = Math.sqrt(2); } .... 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 -_inside_ the default constructor of C. +bytecode. That is, the assignment of `d` to the square root of two happens +_inside_ the default constructor of `C`. Thus inter-type constructors will not necessarily run a target type's initialization code. In particular, if the inter-type constructor calls @@ -211,11 +209,12 @@ constructor is called. [source, java] .... aspect A { - C.new(Object o) {} // implicitly calls super() + 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 + 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 + } } .... @@ -227,7 +226,7 @@ initialization, or to delegate to a `this` constructor if necessary. 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. +mechanism for implementing `around` advice) may be apparent at runtime. See the documentation on annotation-style for more information. === Summary of implementation requirements @@ -235,32 +234,32 @@ See the documentation on annotation-style for more information. This summarizes the requirements of our implementation of AspectJ. For more details, see the relevant sections of this guide. -* The invoking code must be under the control of ajc for the following +* The invoking code must be under the control of _ajc_ for the following join points: -** call join point -** get join point -** set join point -* The declaring/target code must be under the control of ajc for the +** `call` join point +** `get` join point +** `set` join point +* The declaring/target code must be under the control of _ajc_ for the following join points and inter-type declarations: -** execution join point -** adviceexecution join point -** handler join point -** initialization join point -** preinitialiaztion join point -** staticinitialization join point -** perthis aspect -** pertarget aspect -** declare parents -** declare method or field (see interface caveats below) +** `execution` join point +** `adviceexecution` join point +** `handler` join point +** `initialization` join point +** `preinitialiaztion` join point +** `staticinitialization` join point +** `perthis` aspect +** `pertarget` aspect +** `declare _parents_` +** `declare _method_ | _field_` (see interface caveats below) * Implementation Caveats -** The initialization and preinitialization join points do not support -around advice -** The handler join point does not support... -*** after advice -*** around advice -*** cflow(handler(..)) +** The `initialization` and `preinitialization` join points do not support +`around` advice +** The `handler` join point does not support... +*** `after advice` +*** `around` advice +*** `cflow(handler(..))` ** Declaring members on an interface in an aspect affects only the topmost implementing classes the implementation controls. -** cflow and cflowbelow pointcuts work within a single thread. +** `cflow` and `cflowbelow` pointcuts work within a single thread. ** Runtime `ClassCastException` may result from supplying a supertype of -the actual type as an argument to proceed(..) in around advice. +the actual type as an argument to `proceed(..)` in `around` advice. diff --git a/docs/progGuideDB/language.adoc b/docs/progGuideDB/language.adoc index 21d3d1857..14b662aad 100644 --- a/docs/progGuideDB/language.adoc +++ b/docs/progGuideDB/language.adoc @@ -4,7 +4,7 @@ [[language-intro]] === Introduction -The previous chapter, xref:gettingstarted.adoc[Getting Started with AspectJ], was a brief overview of the +The previous chapter, xref:gettingstarted.adoc#starting[Getting Started with AspectJ], 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. @@ -94,10 +94,10 @@ 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 (`&&`, meaning and) with a pointcut picking out call join -points (call(...)). The calls are identified by signatures that can +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 +type position (first `\*`), in the name position (second `*`) and in the +argument list position `(..)`; the only concrete information is given by the qualifier `public`. Pointcuts pick out arbitrarily large numbers of join points of a @@ -155,15 +155,15 @@ Consider the following Java class: [source, java] .... class Point { - private int x, y; + private int x, y; - Point(int x, int y) { this.x = x; this.y = 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; } + void setX(int x) { this.x = x; } + void setY(int y) { this.y = y; } - int getX() { return x; } - int getY() { return y; } + int getX() { return x; } + int getY() { return y; } } .... @@ -394,29 +394,29 @@ Here's some code that expresses this. [source, java] .... public class Test { - public static void main(String[] args) { - foo(); - } - static void foo() { - goo(); - } - static void goo() { - System.out.println("hi"); - } + 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)); + 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()) && cflow(gooPC()) && printPC() && !within(A) { + System.out.println("should occur"); + } - before(): cflow(fooPC() && gooPC()) && printPC() && !within(A) { - System.out.println("should not occur"); - } + before(): cflow(fooPC() && gooPC()) && printPC() && !within(A) { + System.out.println("should not occur"); + } } .... @@ -856,36 +856,34 @@ aspect can call those methods. [source, java] .... class Point { - int x, y; + int x, y; - public void setX(int x) { this.x = x; } - public void setY(int y) { this.y = 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); - } + 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); - } + 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; - } - } + 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; + } } .... @@ -907,9 +905,9 @@ tracing easy: [source, java] .... aspect TraceNonStaticMethods { - before(Point p): target(p) && call(* *(..)) { - System.out.println("Entering " + thisJoinPoint + " in " + p); - } + before(Point p): target(p) && call(* *(..)) { + System.out.println("Entering " + thisJoinPoint + " in " + p); + } } .... diff --git a/docs/progGuideDB/pitfalls.adoc b/docs/progGuideDB/pitfalls.adoc index 0bbe6f5f5..eb9e15315 100644 --- a/docs/progGuideDB/pitfalls.adoc +++ b/docs/progGuideDB/pitfalls.adoc @@ -14,25 +14,25 @@ Here is a Java program with peculiar behavior [source, java] .... 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(); - } + public static void main(String[] args) { + foo(); + System.out.println("done with call to foo"); + } + + static void foo() { + try { + foo(); + } finally { + foo(); } + } } .... -This program will never reach the println call, but when it aborts may +This program will never reach the `println` call, but when it aborts may have no stack trace. -This silence is caused by multiple StackOverflowExceptions. First the +This silence is caused by multiple ``StackOverflowException``s. 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 @@ -43,24 +43,24 @@ The following short aspect will also generate this behavior: [source, java] .... aspect A { - before(): call(* *(..)) { System.out.println("before"); } - after(): call(* *(..)) { System.out.println("after"); } + before(): call(* *(..)) { System.out.println("before"); } + after(): call(* *(..)) { System.out.println("after"); } } .... Why? Because the call to println is also a call matched by the pointcut -`call (* *(..))`. We get no output because we used simple after() +`call (* *(..))`. We get no output because we used simple `after()` advice. If the aspect were changed to [source, java] .... aspect A { - before(): call(* *(..)) { System.out.println("before"); } - after() returning: call(* *(..)) { System.out.println("after"); } + before(): call(* *(..)) { System.out.println("before"); } + after() returning: call(* *(..)) { System.out.println("after"); } } .... -Then at least a StackOverflowException with a stack trace would be seen. +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. @@ -71,8 +71,8 @@ points caused within the aspect. So: [source, java] .... aspect A { - before(): call(* *(..)) && !within(A) { System.out.println("before"); } - after() returning: call(* *(..)) && !within(A) { System.out.println("after"); } + before(): call(* *(..)) && !within(A) { System.out.println("before"); } + after() returning: call(* *(..)) && !within(A) { System.out.println("after"); } } .... @@ -82,8 +82,8 @@ ways, for example: [source, java] .... aspect A { - before(): call(* MyObject.*(..)) { System.out.println("before"); } - after() returning: call(* MyObject.*(..)) { System.out.println("after"); } + before(): call(* MyObject.*(..)) { System.out.println("before"); } + after() returning: call(* MyObject.*(..)) { System.out.println("after"); } } .... diff --git a/docs/progGuideDB/progguide.adoc b/docs/progGuideDB/progguide.adoc index 2ca7c8a89..2e595edb6 100644 --- a/docs/progGuideDB/progguide.adoc +++ b/docs/progGuideDB/progguide.adoc @@ -10,28 +10,31 @@ All rights reserved._ This programming guide describes the AspectJ language. A companion guide describes the tools which are part of the AspectJ development environment. -* If you are completely new to AspectJ, please read the link:gettingstarted.adoc[getting started] chapter for a broad overview of AspectJ programming. -* If you are already familiar with AspectJ, but want a deeper understanding, you can learn more about the link:language.adoc[AspectJ language] and look at the examples in the chapter. -* If you want a more formal definition of AspectJ, please refer to the link:semantics.adoc[language semantics] section. +* If you are completely new to AspectJ, please read the xref:gettingstarted.adoc#starting[getting started] chapter for a + broad overview of AspectJ programming. +* If you are already familiar with AspectJ, but want a deeper understanding, you can learn more about the + xref:language.adoc#language[AspectJ language] and look at the examples in the chapter. +* If you want a more formal definition of AspectJ, please refer to the xref:semantics.adoc#semantics[language semantics] + section. //// ATTENTION: Please do not remove blank lines in between 'include::' statements. Otherwise, section numbers in the table of contents (TOC) can be wrong and the first section of each document missing completely. //// -include::preface.adoc[] +include::preface.adoc[Preface] -include::gettingstarted.adoc[] +include::gettingstarted.adoc[Getting Started with AspectJ] -include::language.adoc[] +include::language.adoc[The AspectJ Language] -include::examples.adoc[] +include::examples.adoc[Examples] -include::idioms.adoc[] +include::idioms.adoc[Idioms] -include::pitfalls.adoc[] +include::pitfalls.adoc[Pitfalls] -include::quickreference.adoc[] +include::quickreference.adoc[AspectJ Quick Reference] -include::semantics.adoc[] +include::semantics.adoc[Language Semantics] -include::implementation.adoc[] +include::implementation.adoc[Implementation Notes] diff --git a/docs/progGuideDB/progguide.html.xsl.adoc b/docs/progGuideDB/progguide.html.xsl.adoc deleted file mode 100644 index 8b1378917..000000000 --- a/docs/progGuideDB/progguide.html.xsl.adoc +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/progGuideDB/quickreference.adoc b/docs/progGuideDB/quickreference.adoc index 6d8febc56..3920b5ef2 100644 --- a/docs/progGuideDB/quickreference.adoc +++ b/docs/progGuideDB/quickreference.adoc @@ -9,22 +9,22 @@ |*Methods and Constructors* | |`call(Signature)` |every call to any method or constructor matching -`` at the call site +`Signature` at the call site |`execution(Signature)` |every execution of any method or constructor -matching `` +matching `Signature` |*Fields* | -|`get(Signature)` |every reference to any field matching `` +|`get(Signature)` |every reference to any field matching `Signature` -|`set(Signature)` |every assignment to any field matching ``. +|`set(Signature)` |every assignment to any field matching `Signature`. The assigned value can be exposed with an `args` pointcut |*Exception Handlers* | |`handler(TypePattern)` |every exception handler for any `Throwable` -type in . The exception value can be exposed with an `args` +type in `TypePattern`. The exception value can be exposed with an `args` pointcut |*Advice* | @@ -34,25 +34,25 @@ pointcut |*Initialization* | |`staticinitialization(TypePattern)` |every execution of a static -initializer for any type in +initializer for any type in `TypePattern` |`initialization(Signature)` |every initialization of an object when the -first constructor called in the type matches ``, encompassing +first constructor called in the type matches `Signature`, encompassing the return from the super constructor call to the return of the first-called constructor |`preinitialization(Signature)` |every pre-initialization of an object -when the first constructor called in the type matches ``, +when the first constructor called in the type matches `Signature`, encompassing the entry of the first-called constructor to the call to the super constructor |*Lexical* | |`within(TypePattern)` |every join point from code defined in a type in - +`TypePattern` |`withincode(Signature)` |every join point from code defined in a method -or constructor matching `` +or constructor matching `Signature` |=== [[quick-typePatterns]] @@ -64,22 +64,22 @@ A type pattern is one of |=== |*Type pattern* | -|`` |all types in `` +|`TypeNamePattern` |all types in `TypeNamePattern` -|`` |all types in ``, a pattern with a `+` +|`SubtypePattern` |all types in `SubtypePattern`, a pattern with a `+` -|`` |all types in ``, a pattern with one or more ``[]``s. +|`ArrayTypePattern` |all types in `ArrayTypePattern`, a pattern with one or more ``[]``s. -|`!TypePattern` |all types not in +|`!TypePattern` |all types not in `TypePattern` -|`TypePattern0 && TypePattern1` |all types in both `` and `` +|`TypePattern0 && TypePattern1` |all types in both `TypePattern0` and `TypePattern1` -|`TypePattern0 \|\| TypePattern1` |all types in either `` or `` +|`TypePattern0 \|\| TypePattern1` |all types in either `TypePattern0` or `TypePattern1` -|`( TypePattern )` |all types in `` +|`( TypePattern )` |all types in `TypePattern` |=== -where `` can either be a plain type name, the wildcard +where `TypeNamePattern` can either be a plain type name, the wildcard `\*` (indicating all types), or an identifier with embedded `*` and `..` wildcards. @@ -99,7 +99,7 @@ Each piece of advice is of the form [ strictfp ] AdviceSpec [ throws TypeList ] : Pointcut { Body } .... -where `` is one of +where `AdviceSpec` is one of `before( Formals )`:: runs before each join point @@ -173,7 +173,7 @@ Each aspect is of the form [ privileged ] Modifiers aspect Id [ extends Type ] [ implements TypeList ] [ PerClause ] { Body } .... -where `` defines how the aspect is instantiated and associated +where `PerClause` defines how the aspect is instantiated and associated (`issingleton()` by default): [cols=",,",options="header",] @@ -183,18 +183,18 @@ where `` defines how the aspect is instantiated and associated default. |`aspectOf()` at all join points |`perthis(Pointcut)` |An instance is associated with each object that is -the currently executing object at any join point in ``. +the currently executing object at any join point in `Pointcut`. |`aspectOf(Object)` at all join points |`pertarget(Pointcut)` |An instance is associated with each object that -is the target object at any join point in ``. +is the target object at any join point in `Pointcut`. |`aspectOf(Object)` at all join points |`percflow(Pointcut)` |The aspect is defined for each entrance to the -control flow of the join points defined by ``. |`aspectOf()` at +control flow of the join points defined by `Pointcut`. |`aspectOf()` at join points in `cflow(Pointcut)` |`percflowbelow(Pointcut)` |The aspect is defined for each entrance to -the control flow below the join points defined by ``. +the control flow below the join points defined by `Pointcut`. |`aspectOf()` at join points in `cflowbelow(Pointcut)` |=== diff --git a/docs/progGuideDB/semantics.adoc b/docs/progGuideDB/semantics.adoc index d1a90673b..0cb513ad0 100644 --- a/docs/progGuideDB/semantics.adoc +++ b/docs/progGuideDB/semantics.adoc @@ -145,10 +145,10 @@ exception |Advice execution |executing aspect |executing aspect |advice arguments |=== -* There is no executing object in static contexts such as static method ++++*+++ There is no executing object in static contexts such as static method bodies or static initializers. -** There is no target object for join points associated with static ++++**+++ There is no target object for join points associated with static methods or fields. [[semantics-pointcuts]] @@ -241,7 +241,7 @@ declaration. [source, java] .... pointcut publicIntCall(int i): - call(public * *(int)) && args(i); + call(public * *(int)) && args(i); .... A named pointcut may be defined in either a class or aspect, and is @@ -251,13 +251,13 @@ member, it may have an access modifier such as `public` or `private`. [source, java] .... class C { - pointcut publicCall(int i): - call(public * *(int)) && args(i); + pointcut publicCall(int i): + call(public * *(int)) && args(i); } class D { - pointcut myPublicCall(int i): - C.publicCall(i) && within(SomeType); + pointcut myPublicCall(int i): + C.publicCall(i) && within(SomeType); } .... @@ -268,7 +268,7 @@ aspects. [source, java] .... abstract aspect A { - abstract pointcut publicCall(int i); + abstract pointcut publicCall(int i); } .... @@ -277,7 +277,7 @@ In such a case, an extending aspect may override the abstract pointcut. [source, java] .... aspect B extends A { - pointcut publicCall(int i): call(public Foo.m(int)) && args(i); + pointcut publicCall(int i): call(public Foo.m(int)) && args(i); } .... @@ -296,7 +296,7 @@ legal: [source, java] .... aspect B percflow(publicCall()) { - pointcut publicCall(): call(public Foo.m(int)); + pointcut publicCall(): call(public Foo.m(int)); } .... @@ -364,7 +364,6 @@ type. So in the following program [source, java] .... public class InstanceOf { - public static void main(String[] args) { doInt(5); } @@ -374,10 +373,10 @@ public class InstanceOf { aspect IntToLong { pointcut el(long l) : - execution(* doInt(..)) && args(l); + execution(* doInt(..)) && args(l); before(Object o) : el(o) { - System.out.println(o.getClass()); + System.out.println(o.getClass()); } } .... @@ -392,32 +391,16 @@ expose it as an `Integer`, not a `Long`. AspectJ provides two primitive pointcut designators designed to capture method call and execution join points. -* call( -+ -MethodPattern -+ -) -* execution( -+ -MethodPattern -+ -) +* `call( MethodPattern )` +* `execution( MethodPattern )` ===== Field-related pointcuts AspectJ provides two primitive pointcut designators designed to capture field reference and set join points: -* get( -+ -FieldPattern -+ -) -* set( -+ -FieldPattern -+ -) +* `get( FieldPattern )` +* `set( FieldPattern )` 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 @@ -427,11 +410,12 @@ variable x declared in type T might be written as [source, java] .... 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) + 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(); - } + } } .... @@ -440,48 +424,24 @@ aspect GuardedX { AspectJ provides primitive pointcut designators designed to capture the initializer execution join points of objects. -* call( -+ -ConstructorPattern -+ -) -* execution( -+ -ConstructorPattern -+ -) -* initialization( -+ -ConstructorPattern -+ -) -* preinitialization( -+ -ConstructorPattern -+ -) +* `call( ConstructorPattern )` +* `execution( ConstructorPattern )` +* `initialization( ConstructorPattern )` +* `preinitialization( ConstructorPattern )` ===== Class initialization-related pointcuts AspectJ provides one primitive pointcut designator to pick out static initializer execution join points. -* staticinitialization( -+ -TypePattern -+ -) +* `staticinitialization( TypePattern )` ===== Exception handler execution-related pointcuts AspectJ provides one primitive pointcut designator to capture execution of exception handlers: -* handler( -+ -TypePattern -+ -) +* `handler( TypePattern )` All handler join points are treated as having one argument, the value of the exception being handled. That value can be accessed with an `args` @@ -491,9 +451,9 @@ normal form before they are handled could be written as [source, java] .... aspect NormalizeFooException { - before(FooException e): handler(FooException) && args(e) { - e.normalize(); - } + before(FooException e): handler(FooException) && args(e) { + e.normalize(); + } } .... @@ -502,7 +462,7 @@ aspect NormalizeFooException { AspectJ provides one primitive pointcut designator to capture execution of advice -* adviceexecution() +* `adviceexecution()` This can be used, for example, to filter out any join point in the control flow of advice from a particular aspect. @@ -510,11 +470,11 @@ control flow of advice from a particular aspect. [source, java] .... aspect TraceStuff { - pointcut myAdvice(): adviceexecution() && within(TraceStuff); + pointcut myAdvice(): adviceexecution() && within(TraceStuff); - before(): call(* *(..)) && !cflow(myAdvice) { - // do something - } + before(): call(* *(..)) && !cflow(myAdvice) { + // do something + } } .... @@ -527,24 +487,8 @@ 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. -* this( -+ -Type -+ -or -+ -Id -+ -) -* target( -+ -Type -+ -or -+ -Id -+ -) +* `this( Type or Id )` +* `target( Type or Id )` The `this` pointcut picks out each join point where the currently executing object (the object bound to `this`) is an instance of a @@ -556,15 +500,7 @@ 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. -* args( -+ -Type -+ -or -+ -Id -+ -or "..", ...) +* `args( Type or Id or "..", ...)` 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 @@ -573,8 +509,8 @@ 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 +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 [source, java] @@ -591,26 +527,18 @@ Some concerns cut across the control flow of the program. The `cflow` and `cflowbelow` primitive pointcut designators capture join points based on control flow. -* cflow( -+ -Pointcut -+ -) -* cflowbelow( -+ -Pointcut -+ -) +* `cflow( Pointcut )` +* `cflowbelow( Pointcut )` The `cflow` pointcut picks out all join points that occur between entry -and exit of each join point

picked out by , including

+and exit of each join point `P` picked out by `Pointcut`, including `P` itself. Hence, it picks out the join points _in_ the control flow of the -join points picked out by . +join points picked out by `Pointcut`. The `cflowbelow` pointcut picks out all join points that occur between -entry and exit of each join point

picked out by , but not -including

itself. Hence, it picks out the join points _below_ the -control flow of the join points picked out by . +entry and exit of each join point `P` picked out by `Pointcut`, but not +including `P` itself. Hence, it picks out the join points _below_ the +control flow of the join points picked out by `Pointcut`. ====== Context exposure from control flows @@ -624,31 +552,30 @@ the following program is zero, even though it is in many control flows. [source, java] .... 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); + 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)) && args(i); - pointcut writing(): call(void println(String)) && ! within(A); + pointcut entry(int i): call(int fact(int)) && args(i); + pointcut writing(): call(void println(String)) && ! within(A); - before(int i): writing() && cflow(entry(i)) { - System.err.println("Current arg is " + i); - } + before(int i): writing() && cflow(entry(i)) { + System.err.println("Current arg is " + i); + } } .... It is an error to expose such state through _negated_ control flow -pointcuts, such as within `! - cflowbelow(P)`. +pointcuts, such as within `!cflowbelow(P)`. ===== Program text-based pointcuts @@ -656,24 +583,12 @@ 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. -* within( -+ -TypePattern -+ -) -* withincode( -+ -MethodPattern -+ -) -* withincode( -+ -ConstructorPattern -+ -) +* `within( TypePattern )` +* `withincode( MethodPattern )` +* `withincode( ConstructorPattern )` The `within` pointcut picks out each join point where the code executing -is defined in the declaration of one of the types in . This +is defined in the declaration of one of the types in `TypePattern`. 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 @@ -690,11 +605,7 @@ or anonymous types. ===== Expression-based pointcuts -* if( -+ -BooleanExpression -+ -) +* `if( BooleanExpression )` 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 @@ -786,7 +697,7 @@ declaration, in class `Test`, for example, might be [source, java] .... class C { - public final void foo() throws ArrayOutOfBoundsException { ... } + public final void foo() throws ArrayOutOfBoundsException { ... } } .... @@ -808,7 +719,7 @@ call(public final void *.*() throws ArrayOutOfBoundsException) 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 `public` and `final`, and are declared to -throw `ArrayOutOfBounds` exceptions. +throw ``ArrayOutOfBoundsException``s. The defining type name, if not present, defaults to *, so another way of writing that pointcut would be @@ -877,8 +788,8 @@ starts with the characters "get". AspectJ uses the `new` 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 +private null constructor of a class `C` defined to throw an +`ArithmeticException` can be picked out with [source, java] .... @@ -921,7 +832,7 @@ would fail to pick out the join point for the code .... Specifying the originally-declaring type is correct, but would pick out -any such call (here, calls to the `run()` method of any Runnable). In +any such call (here, calls to the `run()` method of any `Runnable`). In this situation, consider instead picking out the target type: [source, java] @@ -941,39 +852,40 @@ execution(public void Middle.*()) 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() +`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: [source, java] .... class Super { - protected void m() { ... } -} -class Middle extends Super { + protected void m() { /*...*/ } } + +class Middle extends Super {} + class Sub extends Middle { - public void m() { ... } + public void m() { /*...*/ } } .... -===== Matching based on the throws clause +===== Matching based on the `throws` clause Type patterns may be used to pick out methods and constructors based on -their throws clauses. This allows the following two kinds of extremely +their `throws` clauses. This allows the following two kinds of extremely wildcarded pointcuts: [source, java] .... 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*); + // 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*); + // each call to a method with a throws clause containing no + // exceptions with "Math" in its name. + call(* *(..) throws !*..*Math*); .... A `ThrowsClausePattern` is a comma-separated list of ``ThrowsClausePatternItem``s, where @@ -985,11 +897,11 @@ ThrowsClausePatternItem := [ ! ] TypeNamePattern A `ThrowsClausePattern` matches the `throws` clause of any code member signature. To match, each `ThrowsClausePatternItem` must match the -throws clause of the member in question. If any item doesn't match, then +`throws` clause of the member in question. If any item doesn't match, then the whole pattern doesn't match. If a `ThrowsClausePatternItem` begins with `!`, then it matches a -particular throws clause if and only if _none_ of the types named in the +particular `throws` clause if and only if _none_ of the types named in the `throws` clause is matched by the `TypeNamePattern`. If a `ThrowsClausePatternItem` does not begin with `!`, then it matches @@ -1157,17 +1069,17 @@ Here is a summary of the pattern syntax used in AspectJ: [source, text] .... MethodPattern = - [ModifiersPattern] TypePattern - [TypePattern . ] IdPattern (TypePattern | ".." , ... ) - [ throws ThrowsPattern ] + [ModifiersPattern] TypePattern + [TypePattern . ] IdPattern (TypePattern | ".." , ... ) + [ throws ThrowsPattern ] ConstructorPattern = - [ModifiersPattern ] - [TypePattern . ] new (TypePattern | ".." , ...) - [ throws ThrowsPattern ] + [ModifiersPattern ] + [TypePattern . ] new (TypePattern | ".." , ...) + [ throws ThrowsPattern ] FieldPattern = - [ModifiersPattern] TypePattern [TypePattern . ] IdPattern + [ModifiersPattern] TypePattern [TypePattern . ] IdPattern ThrowsPattern = - [ ! ] TypePattern , ... + [ ! ] TypePattern , ... TypePattern = IdPattern [ + ] [ [] ... ] | ! TypePattern @@ -1175,9 +1087,9 @@ TypePattern = | TypePattern || TypePattern | ( TypePattern ) IdPattern = - Sequence of characters, possibly with special * and .. wildcards + Sequence of characters, possibly with special * and .. wildcards ModifiersPattern = - [ ! ] JavaModifier ... + [ ! ] JavaModifier ... .... [[semantics-advice]] @@ -1209,42 +1121,45 @@ advice. 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. +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. -While before advice is relatively unproblematic, there can be three -interpretations of after advice: After the execution of a join point +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. +either one. AspectJ allows `after` advice for any of these situations: [source, java] .... 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"); - } + 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"); + } } .... -After returning advice may not care about its returned object, in which +`after returning` advice may not care about its returned object, in which case it may be written [source, java] .... after() returning: call(public Object *(..)) { - System.out.println("Returned normally"); + System.out.println("Returned normally"); } .... -If after returning does expose its returned object, then the type of the +If `after returning` does expose its returned object, then the type of the parameter is considered to be an `instanceof`-like constraint on the advice: it will run only when the return value is of the appropriate type. @@ -1253,34 +1168,34 @@ 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 `byte` value is assignable to a `short` parameter but not vice-versa, an `int` is assignable to a `float` parameter, `boolean` values are only assignable -to `boolean` parameters, and reference types work by instanceof. +to `boolean` parameters, and reference types work by `instanceof`. There are two special cases: If the exposed value is typed to `Object`, 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: `int` values are represented as `java.lang.Integer` objects, etc, and no value (from -void methods, for example) is represented as `null`. +`void` methods, for example) is represented as `null`. Secondly, the `null` value is assignable to a parameter `T` if the join point _could_ return something of type `T`. -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 +`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. -Thus, a simple use of around advice is to make a particular method +Thus, a simple use of `around` advice is to make a particular method constant: [source, java] .... aspect A { - int around(): call(int C.foo()) { - return 3; - } + int around(): call(int C.foo()) { + return 3; + } } .... -Within the body of around advice, though, the computation of the +Within the body of `around` advice, though, the computation of the original join point can be executed with the special syntax [source, java] @@ -1288,7 +1203,7 @@ original join point can be executed with the special syntax proceed( ... ) .... -The proceed form takes as arguments the context exposed by the around's +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 `foo` whenever it is called, and then halve its result: @@ -1296,49 +1211,49 @@ whenever it is called, and then halve its result: [source, java] .... aspect A { - int around(int i): call(int C.foo(Object, int)) && args(i) { - int newi = proceed(i*2) - return newi/2; - } + int around(int i): call(int C.foo(Object, int)) && args(i) { + int newi = proceed(i*2) + return newi/2; + } } .... -If the return value of around advice is typed to `Object`, then the +If the return value of `around` advice is typed to `Object`, 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 +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: [source, java] .... aspect A { - Object around(int i): call(int C.foo(Object, int)) && args(i) { - Integer newi = (Integer) proceed(i*2) - return new Integer(newi.intValue() / 2); - } + Object around(int i): call(int C.foo(Object, int)) && args(i) { + Integer newi = (Integer) proceed(i*2) + return new Integer(newi.intValue() / 2); + } } .... Any occurence of `proceed(..)` within the body of around advice is -treated as the special proceed form (even if the aspect defines a method +treated as the special `proceed` form (even if the aspect defines a method named `proceed`), 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 `ICanProceed` instance, whereas the second call to proceed is -treated as the special proceed form. +program the first call to `proceed` will be treated as a method call to +the `ICanProceed` instance, whereas the second call to `proceed` is +treated as the special `proceed` form. [source, java] .... aspect A { - Object around(ICanProceed canProceed) : execution(* *(..)) && 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 - } + Object around(ICanProceed canProceed) : execution(* *(..)) && 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 + } } .... @@ -1350,15 +1265,15 @@ means that [source, java] .... aspect A { - after() returning (int i): call(int C.foo()) { - i = i * 2; - } + after() returning (int i): call(int C.foo()) { + i = i * 2; + } } .... will _not_ 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. +values of join points can be done by using `around` advice. With `proceed(..)` it is possible to change the values used by less-precedent advice and the underlying join point by supplying @@ -1443,18 +1358,18 @@ For example, in the following declarations: import java.io.FileNotFoundException; class C { - int i; - - int getI() { return i; } + 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(); - } + before(): get(int C.i) { + throw new FileNotFoundException(); + } + + before() throws FileNotFoundException: get(int C.i) { + throw new FileNotFoundException(); + } } .... @@ -1515,9 +1430,9 @@ These rules can lead to circularity, such as [source, java] .... aspect A { - before(): execution(void main(String[] args)) {} - after(): execution(void main(String[] args)) {} - before(): execution(void main(String[] args)) {} + before(): execution(void main(String[] args)) {} + after(): execution(void main(String[] args)) {} + before(): execution(void main(String[] args)) {} } .... @@ -1605,8 +1520,8 @@ An inter-type method declaration looks like * `[ Modifiers ] Type OnType . Id ( Formals ) [ ThrowsClause ] { Body }` * `abstract [ Modifiers ] Type OnType . Id ( Formals ) [ ThrowsClause ] ;` -The effect of such a declaration is to make support the new -method. Even if is an interface. Even if the method is neither +The effect of such a declaration is to make `OnType` support the new +method. Even if `OnType` is an interface. Even if the method is neither public nor abstract. So the following is legal AspectJ code: [source, java] @@ -1614,13 +1529,14 @@ public nor abstract. So the following is legal AspectJ code: 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(); - } + 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(); + } } .... @@ -1628,12 +1544,12 @@ An inter-type constructor declaration looks like * `[ Modifiers ] OnType . new ( Formals ) [ ThrowsClause ] { Body }` -The effect of such a declaration is to make support the new -constructor. It is an error for to be an interface. +The effect of such a declaration is to make `OnType` support the new +constructor. It is an error for `OnType` to be an interface. Inter-type declared constructors cannot be used to assign a value to a -final variable declared in . This limitation significantly -increases the ability to both understand and compile the class +final variable declared in `OnType`. This limitation significantly +increases the ability to both understand and compile the `OnType` class and the declaring aspect separately. Note that in the Java language, classes that define no constructors have @@ -1662,7 +1578,7 @@ from a `static` inter-type member declaration. ==== Access modifiers -Inter-type member declarations may be public or private, or have default +Inter-type member declarations may be `public` or `private`, or have default (package-protected) visibility. AspectJ does not provide protected inter-type members. @@ -1697,11 +1613,12 @@ declared members and inter-type members. For example, assuming [source, java] .... aspect A { - private Registry otherPackage.onType.r; - public void otherPackage.onType.register(Registry r) { + private Registry otherPackage.onType.r; + + public void otherPackage.onType.register(Registry r) { r.register(this); this.r = r; - } + } } .... @@ -1764,8 +1681,9 @@ the `Runnable` interface, the inter-type `run()` method must be public: [source, java] .... aspect A { - declare parents: SomeClass implements Runnable; - public void SomeClass.run() { ... } + declare parents: SomeClass implements Runnable; + + public void SomeClass.run() { ... } } .... @@ -1787,13 +1705,13 @@ its superinterfaces. Consider the following hierarchy where {`Object`, [source, text] .... - Object M O - \ / \ / - C N Q - \ / / - D P - \ / - E +Object M O + \ / \ / + C N Q + \ / / + D P + \ / + E .... when a new `E` is instantiated, the initializers run in this order: @@ -1830,7 +1748,7 @@ For example, the aspect [source, java] .... aspect A { - declare soft: Exception: execution(void main(String[] args)); + declare soft: Exception: execution(void main(String[] args)); } .... @@ -1842,12 +1760,12 @@ This is similar to what the following advice would do [source, java] .... aspect A { - void around() execution(void main(String[] args)) { - try { proceed(); } - catch (Exception e) { + void around() execution(void main(String[] args)) { + try { proceed(); } + catch (Exception e) { throw new org.aspectj.lang.SoftException(e); - } } + } } .... @@ -1907,22 +1825,22 @@ another, ordering aspect: [source, java] .... aspect Ordering { - declare precedence: CountEntry, DisallowNulls; + declare precedence: CountEntry, DisallowNulls; } aspect DisallowNulls { - pointcut allTypeMethods(Type obj): call(* *(..)) && args(obj, ..); - before(Type obj): allTypeMethods(obj) { - if (obj == null) throw new RuntimeException(); - } + pointcut allTypeMethods(Type obj): call(* *(..)) && args(obj, ..); + before(Type obj): allTypeMethods(obj) { + if (obj == null) throw new RuntimeException(); + } } aspect CountEntry { - pointcut allTypeMethods(Type obj): call(* *(..)) && args(obj, ..); - static int count = 0; - before(): allTypeMethods(Type) { - count++; - } + pointcut allTypeMethods(Type obj): call(* *(..)) && args(obj, ..); + static int count = 0; + before(): allTypeMethods(Type) { + count++; + } } .... @@ -1957,29 +1875,30 @@ Consider the following library aspects: [source, java] .... abstract aspect Logging { - abstract pointcut logged(); + abstract pointcut logged(); - before(): logged() { - System.err.println("thisJoinPoint: " + thisJoinPoint); - } + 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 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); + } + + abstract void addToProfile( + org.aspectj.JoinPoint.StaticPart jp, + long elapsed + ); } .... @@ -2051,10 +1970,10 @@ and throwing no checked exceptions. ===== Nested aspects must be `static` -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 +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 _must_ be defined -with the static keyword. Local and anonymous aspects are not allowed. +with the `static` keyword. Local and anonymous aspects are not allowed. ==== Aspect Extension @@ -2136,7 +2055,7 @@ associated with an instance of `A`. In either case, the static method call `A.aspectOf(Object)` 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 where there is no associated +a join point picked out by `Pointcut` where there is no associated aspect of type `A`. Both `perthis` and `pertarget` aspects may be affected by code the @@ -2167,17 +2086,17 @@ that must occur before asopect instantiation. For example: .... public class Client { - public static void main(String[] args) { - Client c = new Client(); - } + public static void main(String[] args) { + Client c = new Client(); + } } aspect Watchcall { - pointcut myConstructor(): execution(new(..)); + pointcut myConstructor(): execution(new(..)); - before(): myConstructor() { - System.err.println("Entering Constructor"); - } + before(): myConstructor() { + System.err.println("Entering Constructor"); + } } .... @@ -2211,19 +2130,21 @@ all members, even private ones. [source, java] .... class C { - private int i = 0; - void incI(int x) { i = i+x; } + 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)) && target(c) && args(x) { - if (c.i+x > MAX) throw new RuntimeException(); - } + static final int MAX = 1000; + + before(int x, C c): call(void C.incI(int)) && target(c) && args(x) { + if (c.i+x > MAX) throw new RuntimeException(); + } } .... -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. +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. If a privileged aspect can access multiple versions of a particular member, then those that it could see if it were not privileged take @@ -2232,20 +2153,21 @@ precedence. For example, in the code [source, java] .... class C { - private int i = 0; - void foo() { } + 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); - } + private int C.i = 999; + + before(C c): call(void C.foo()) target(c) { + System.out.println(c.i); + } } .... -``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 +``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 `A` would have access to its own inter-type fields even if it were not privileged. -- 2.39.5