From d842c4f1139629c1f062b74ba818d233b2c31043 Mon Sep 17 00:00:00 2001 From: wisberg Date: Mon, 16 Dec 2002 17:58:19 +0000 Subject: initial version --- docs/build.xml | 399 +++ docs/devGuideDB/ajbrowser-building.gif | Bin 0 -> 26404 bytes docs/devGuideDB/ajbrowser-options.gif | Bin 0 -> 9437 bytes docs/devGuideDB/ajbrowser.xml | 222 ++ docs/devGuideDB/ajc.xml | 484 +++ docs/devGuideDB/ajdb.xml | 312 ++ docs/devGuideDB/ajdee.gif | Bin 0 -> 21193 bytes docs/devGuideDB/ajdee.xml | 452 +++ docs/devGuideDB/ajdeforte.xml | 215 ++ docs/devGuideDB/ajdejbuilder.xml | 266 ++ docs/devGuideDB/ajdoc.xml | 155 + docs/devGuideDB/antsupport.xml | 23 + docs/devGuideDB/aspectj-mode.gif | Bin 0 -> 11988 bytes docs/devGuideDB/aspectj-mode.xml | 354 ++ docs/devGuideDB/aspectj-mode2.gif | Bin 0 -> 20913 bytes docs/devGuideDB/devguide.xml | 69 + docs/devGuideDB/jbuilder-buildOptions.gif | Bin 0 -> 10064 bytes docs/devGuideDB/jbuilder-building.gif | Bin 0 -> 27587 bytes docs/devGuideDB/jbuilder-configs.gif | Bin 0 -> 24200 bytes docs/devGuideDB/jbuilder-structureNavigation.gif | Bin 0 -> 30813 bytes docs/devGuideDB/netbeans-buildOptions.gif | Bin 0 -> 10273 bytes docs/devGuideDB/netbeans-building.gif | Bin 0 -> 33075 bytes docs/dist/doc/ant-ajc-task.html | 389 +++ docs/dist/doc/ant-ajc10-task.html | 383 +++ docs/dist/doc/ant-tasks.html | 230 ++ docs/dist/doc/changes.html | 1502 +++++++++ docs/dist/doc/index.html | 329 ++ docs/dist/doc/porting.html | 1785 ++++++++++ docs/dist/doc/quick.doc | Bin 0 -> 56832 bytes docs/dist/examples/bean/BoundPoint.java | 93 + docs/dist/examples/bean/Demo.java | 83 + docs/dist/examples/bean/Point.java | 76 + docs/dist/examples/build.xml | 282 ++ docs/dist/examples/coordination/Condition.java | 37 + .../examples/coordination/CoordinationAction.java | 37 + docs/dist/examples/coordination/Coordinator.java | 449 +++ docs/dist/examples/coordination/Exclusion.java | 33 + docs/dist/examples/coordination/MethodState.java | 45 + docs/dist/examples/coordination/Mutex.java | 86 + docs/dist/examples/coordination/Selfex.java | 55 + .../examples/coordination/TimeoutException.java | 27 + .../dist/examples/introduction/CloneablePoint.java | 42 + .../examples/introduction/ComparablePoint.java | 46 + docs/dist/examples/introduction/HashablePoint.java | 47 + docs/dist/examples/introduction/Point.java | 98 + docs/dist/examples/observer/Button.java | 45 + docs/dist/examples/observer/ColorLabel.java | 40 + docs/dist/examples/observer/Demo.java | 34 + docs/dist/examples/observer/Display.java | 52 + docs/dist/examples/observer/Observer.java | 22 + docs/dist/examples/observer/Subject.java | 24 + .../examples/observer/SubjectObserverProtocol.java | 47 + .../observer/SubjectObserverProtocolImpl.java | 36 + docs/dist/examples/spacewar/Bullet.java | 48 + docs/dist/examples/spacewar/Debug.java | 219 ++ docs/dist/examples/spacewar/Display.java | 166 + docs/dist/examples/spacewar/Display1.java | 203 ++ docs/dist/examples/spacewar/Display2.java | 138 + docs/dist/examples/spacewar/EnergyPacket.java | 44 + .../examples/spacewar/EnergyPacketProducer.java | 63 + docs/dist/examples/spacewar/EnsureShipIsAlive.java | 35 + docs/dist/examples/spacewar/Game.java | 215 ++ .../examples/spacewar/GameSynchronization.java | 54 + docs/dist/examples/spacewar/Makefile | 12 + docs/dist/examples/spacewar/Pilot.java | 44 + docs/dist/examples/spacewar/Player.java | 122 + docs/dist/examples/spacewar/README.html | 79 + docs/dist/examples/spacewar/Registry.java | 126 + .../examples/spacewar/RegistrySynchronization.java | 58 + docs/dist/examples/spacewar/Robot.java | 201 ++ docs/dist/examples/spacewar/SWFrame.java | 92 + docs/dist/examples/spacewar/Ship.java | 296 ++ docs/dist/examples/spacewar/SpaceObject.java | 106 + docs/dist/examples/spacewar/Timer.java | 53 + docs/dist/examples/telecom/AbstractSimulation.java | 80 + docs/dist/examples/telecom/BasicSimulation.java | 34 + docs/dist/examples/telecom/Billing.java | 80 + docs/dist/examples/telecom/BillingSimulation.java | 44 + docs/dist/examples/telecom/Call.java | 97 + docs/dist/examples/telecom/Connection.java | 87 + docs/dist/examples/telecom/Customer.java | 112 + docs/dist/examples/telecom/Local.java | 26 + docs/dist/examples/telecom/LongDistance.java | 26 + docs/dist/examples/telecom/Timer.java | 50 + docs/dist/examples/telecom/TimerLog.java | 29 + docs/dist/examples/telecom/Timing.java | 62 + docs/dist/examples/telecom/TimingSimulation.java | 40 + docs/dist/examples/tjp/Demo.java | 40 + docs/dist/examples/tjp/GetInfo.java | 49 + docs/dist/examples/tracing/Circle.java | 71 + docs/dist/examples/tracing/ExampleMain.java | 44 + docs/dist/examples/tracing/README | 32 + docs/dist/examples/tracing/Square.java | 71 + docs/dist/examples/tracing/TwoDShape.java | 78 + docs/dist/examples/tracing/lib/AbstractTrace.java | 185 ++ docs/dist/examples/tracing/lib/TraceMyClasses.java | 67 + docs/dist/examples/tracing/version1/Trace.java | 83 + .../examples/tracing/version1/TraceMyClasses.java | 75 + docs/dist/examples/tracing/version2/Trace.java | 123 + .../examples/tracing/version2/TraceMyClasses.java | 43 + docs/dist/examples/tracing/version3/Trace.java | 123 + .../examples/tracing/version3/TraceMyClasses.java | 46 + docs/faq/faq.xml | 3397 ++++++++++++++++++++ docs/install/finish.html | 20 + docs/install/install-finish.html | 20 + docs/install/install-start.html | 21 + docs/install/intro.html | 24 + docs/install/location.html | 23 + docs/progGuideDB/aspectjdoc.dsl | 124 + docs/progGuideDB/aspects.gif | Bin 0 -> 7071 bytes docs/progGuideDB/bibliography.xml | 70 + docs/progGuideDB/build.sh | 79 + docs/progGuideDB/examples.xml | 2343 ++++++++++++++ docs/progGuideDB/figureUML.gif | Bin 0 -> 3480 bytes docs/progGuideDB/gettingstarted.xml | 1090 +++++++ docs/progGuideDB/glossary.xml | 192 ++ docs/progGuideDB/idioms.xml | 104 + docs/progGuideDB/language.xml | 1226 +++++++ docs/progGuideDB/limitations.xml | 123 + docs/progGuideDB/overview.gif | Bin 0 -> 2576 bytes docs/progGuideDB/pitfalls.xml | 103 + docs/progGuideDB/preface.xml | 52 + docs/progGuideDB/progguide.html.xsl | 9 + docs/progGuideDB/progguide.xml | 83 + docs/progGuideDB/quickreference.xml | 658 ++++ docs/progGuideDB/semantics.xml | 2361 ++++++++++++++ docs/progGuideDB/telecom.gif | Bin 0 -> 4047 bytes docs/readme-docs-module.html | 32 + 128 files changed, 25830 insertions(+) create mode 100644 docs/build.xml create mode 100644 docs/devGuideDB/ajbrowser-building.gif create mode 100644 docs/devGuideDB/ajbrowser-options.gif create mode 100644 docs/devGuideDB/ajbrowser.xml create mode 100644 docs/devGuideDB/ajc.xml create mode 100644 docs/devGuideDB/ajdb.xml create mode 100644 docs/devGuideDB/ajdee.gif create mode 100644 docs/devGuideDB/ajdee.xml create mode 100644 docs/devGuideDB/ajdeforte.xml create mode 100644 docs/devGuideDB/ajdejbuilder.xml create mode 100644 docs/devGuideDB/ajdoc.xml create mode 100644 docs/devGuideDB/antsupport.xml create mode 100644 docs/devGuideDB/aspectj-mode.gif create mode 100644 docs/devGuideDB/aspectj-mode.xml create mode 100644 docs/devGuideDB/aspectj-mode2.gif create mode 100644 docs/devGuideDB/devguide.xml create mode 100644 docs/devGuideDB/jbuilder-buildOptions.gif create mode 100644 docs/devGuideDB/jbuilder-building.gif create mode 100644 docs/devGuideDB/jbuilder-configs.gif create mode 100644 docs/devGuideDB/jbuilder-structureNavigation.gif create mode 100644 docs/devGuideDB/netbeans-buildOptions.gif create mode 100644 docs/devGuideDB/netbeans-building.gif create mode 100644 docs/dist/doc/ant-ajc-task.html create mode 100644 docs/dist/doc/ant-ajc10-task.html create mode 100644 docs/dist/doc/ant-tasks.html create mode 100644 docs/dist/doc/changes.html create mode 100644 docs/dist/doc/index.html create mode 100644 docs/dist/doc/porting.html create mode 100644 docs/dist/doc/quick.doc create mode 100644 docs/dist/examples/bean/BoundPoint.java create mode 100644 docs/dist/examples/bean/Demo.java create mode 100644 docs/dist/examples/bean/Point.java create mode 100644 docs/dist/examples/build.xml create mode 100644 docs/dist/examples/coordination/Condition.java create mode 100644 docs/dist/examples/coordination/CoordinationAction.java create mode 100644 docs/dist/examples/coordination/Coordinator.java create mode 100644 docs/dist/examples/coordination/Exclusion.java create mode 100644 docs/dist/examples/coordination/MethodState.java create mode 100644 docs/dist/examples/coordination/Mutex.java create mode 100644 docs/dist/examples/coordination/Selfex.java create mode 100644 docs/dist/examples/coordination/TimeoutException.java create mode 100644 docs/dist/examples/introduction/CloneablePoint.java create mode 100644 docs/dist/examples/introduction/ComparablePoint.java create mode 100644 docs/dist/examples/introduction/HashablePoint.java create mode 100644 docs/dist/examples/introduction/Point.java create mode 100644 docs/dist/examples/observer/Button.java create mode 100644 docs/dist/examples/observer/ColorLabel.java create mode 100644 docs/dist/examples/observer/Demo.java create mode 100644 docs/dist/examples/observer/Display.java create mode 100644 docs/dist/examples/observer/Observer.java create mode 100644 docs/dist/examples/observer/Subject.java create mode 100644 docs/dist/examples/observer/SubjectObserverProtocol.java create mode 100644 docs/dist/examples/observer/SubjectObserverProtocolImpl.java create mode 100644 docs/dist/examples/spacewar/Bullet.java create mode 100644 docs/dist/examples/spacewar/Debug.java create mode 100644 docs/dist/examples/spacewar/Display.java create mode 100644 docs/dist/examples/spacewar/Display1.java create mode 100644 docs/dist/examples/spacewar/Display2.java create mode 100644 docs/dist/examples/spacewar/EnergyPacket.java create mode 100644 docs/dist/examples/spacewar/EnergyPacketProducer.java create mode 100644 docs/dist/examples/spacewar/EnsureShipIsAlive.java create mode 100644 docs/dist/examples/spacewar/Game.java create mode 100644 docs/dist/examples/spacewar/GameSynchronization.java create mode 100644 docs/dist/examples/spacewar/Makefile create mode 100644 docs/dist/examples/spacewar/Pilot.java create mode 100644 docs/dist/examples/spacewar/Player.java create mode 100644 docs/dist/examples/spacewar/README.html create mode 100644 docs/dist/examples/spacewar/Registry.java create mode 100644 docs/dist/examples/spacewar/RegistrySynchronization.java create mode 100644 docs/dist/examples/spacewar/Robot.java create mode 100644 docs/dist/examples/spacewar/SWFrame.java create mode 100644 docs/dist/examples/spacewar/Ship.java create mode 100644 docs/dist/examples/spacewar/SpaceObject.java create mode 100644 docs/dist/examples/spacewar/Timer.java create mode 100644 docs/dist/examples/telecom/AbstractSimulation.java create mode 100644 docs/dist/examples/telecom/BasicSimulation.java create mode 100644 docs/dist/examples/telecom/Billing.java create mode 100644 docs/dist/examples/telecom/BillingSimulation.java create mode 100644 docs/dist/examples/telecom/Call.java create mode 100644 docs/dist/examples/telecom/Connection.java create mode 100644 docs/dist/examples/telecom/Customer.java create mode 100644 docs/dist/examples/telecom/Local.java create mode 100644 docs/dist/examples/telecom/LongDistance.java create mode 100644 docs/dist/examples/telecom/Timer.java create mode 100644 docs/dist/examples/telecom/TimerLog.java create mode 100644 docs/dist/examples/telecom/Timing.java create mode 100644 docs/dist/examples/telecom/TimingSimulation.java create mode 100644 docs/dist/examples/tjp/Demo.java create mode 100644 docs/dist/examples/tjp/GetInfo.java create mode 100644 docs/dist/examples/tracing/Circle.java create mode 100644 docs/dist/examples/tracing/ExampleMain.java create mode 100644 docs/dist/examples/tracing/README create mode 100644 docs/dist/examples/tracing/Square.java create mode 100644 docs/dist/examples/tracing/TwoDShape.java create mode 100644 docs/dist/examples/tracing/lib/AbstractTrace.java create mode 100644 docs/dist/examples/tracing/lib/TraceMyClasses.java create mode 100644 docs/dist/examples/tracing/version1/Trace.java create mode 100644 docs/dist/examples/tracing/version1/TraceMyClasses.java create mode 100644 docs/dist/examples/tracing/version2/Trace.java create mode 100644 docs/dist/examples/tracing/version2/TraceMyClasses.java create mode 100644 docs/dist/examples/tracing/version3/Trace.java create mode 100644 docs/dist/examples/tracing/version3/TraceMyClasses.java create mode 100644 docs/faq/faq.xml create mode 100644 docs/install/finish.html create mode 100644 docs/install/install-finish.html create mode 100644 docs/install/install-start.html create mode 100644 docs/install/intro.html create mode 100644 docs/install/location.html create mode 100644 docs/progGuideDB/aspectjdoc.dsl create mode 100644 docs/progGuideDB/aspects.gif create mode 100644 docs/progGuideDB/bibliography.xml create mode 100644 docs/progGuideDB/build.sh create mode 100644 docs/progGuideDB/examples.xml create mode 100644 docs/progGuideDB/figureUML.gif create mode 100644 docs/progGuideDB/gettingstarted.xml create mode 100644 docs/progGuideDB/glossary.xml create mode 100644 docs/progGuideDB/idioms.xml create mode 100644 docs/progGuideDB/language.xml create mode 100644 docs/progGuideDB/limitations.xml create mode 100644 docs/progGuideDB/overview.gif create mode 100644 docs/progGuideDB/pitfalls.xml create mode 100644 docs/progGuideDB/preface.xml create mode 100644 docs/progGuideDB/progguide.html.xsl create mode 100644 docs/progGuideDB/progguide.xml create mode 100644 docs/progGuideDB/quickreference.xml create mode 100644 docs/progGuideDB/semantics.xml create mode 100644 docs/progGuideDB/telecom.gif create mode 100644 docs/readme-docs-module.html (limited to 'docs') diff --git a/docs/build.xml b/docs/build.xml new file mode 100644 index 000000000..30b281cf9 --- /dev/null +++ b/docs/build.xml @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + +]> + + + + + + + + + + + + + + &build-properties; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +---- misc info for writing and building docbook +- link tag linkend attribute takes an id + - xsl converts as needed during output + - do NOT use ulink; this will be converted to "" + (but see param citerefentry-link: might enable this) + +- to use sensible names for the files produced, + - use an xsl wrapper to add/modify features + - set flag to use the id of the top-level element in the output + file as the filename. + xsl:param name="use.id.as.filename" select="1" + - fyi, other related parameters: html-ext, root-filename + - In this example, the top-level element in the output file + is the refentry, so set ids which become the basename of the file: + refentry id="aspectj-mode" # in aspectj-mode.xml, produces aspecj-mode.html + refentry id="ajdee" # in ajdee.xml, produces ajdee.html + +-- fyi +- related parameters: + html-ext, root-filename +- these tags did not work for me: + dbhtml filename="foo.htm" + dbhtml prefix="foo-" + +- resources + - the dtd reference for docbook + http://www.oreilly.com/catalog/docbook/chapter/book/docbook.html + - the stylesheet reference for docbook xsl + http://docbook.sourceforge.net/projects/dsssl/doc/html.html +- todo + - fyi, generate.reference.titlepage appears not to be respected. + tried to add if statement to html/refentry.xsl, but file still gen'd + + + + diff --git a/docs/devGuideDB/ajbrowser-building.gif b/docs/devGuideDB/ajbrowser-building.gif new file mode 100644 index 000000000..29767c605 Binary files /dev/null and b/docs/devGuideDB/ajbrowser-building.gif differ diff --git a/docs/devGuideDB/ajbrowser-options.gif b/docs/devGuideDB/ajbrowser-options.gif new file mode 100644 index 000000000..41ba67654 Binary files /dev/null and b/docs/devGuideDB/ajbrowser-options.gif differ diff --git a/docs/devGuideDB/ajbrowser.xml b/docs/devGuideDB/ajbrowser.xml new file mode 100644 index 000000000..f4a44597c --- /dev/null +++ b/docs/devGuideDB/ajbrowser.xml @@ -0,0 +1,222 @@ + + + AspectJ Browser + + GUI tool for compiling programs with ajc and navigating the + crosscutting structure (early-access) + + + + + Overview + + + + The AspectJ Browser is a development tool that will allow you to + compile using ajc, navigate your program's static structure, edit + source files, and graphically edit build configuration files. + + + + + + + + To use the browser launch it by typing "ajbrowser" (assuming that + you've followed the instructions for setting up ajc). You can either pass in one or more + ".lst" build configuration files as command line parameters to the + browser in order to build them and navigate the corresponding + structure, or you can open one or more ".lst" files with "File -> + Open" or with the "Open Build Configuration" button + ( + + + + ). + + + + + Compiling a Build Configuration + + + To compile click the "Build" button + ( + + + + ), or click <ctrl>F11. You may also select a + different build configuration here, as in label 1. + + + + + Navigating the Program Structure + + + Select nodes in the program structure by clicking them (as in label 2). + If one node is related to one or more other nodes by an association the + name of the association will appear below that node and will be + displayed in italics. Links to other structure nodes appear in blue + below the association. If there is no corresponding source for the + link it will appear light-blue. + + + + + + Manipulating Build Configuration + + + Build configurations can be manipulated adding, removing, and + editing build configuration files using the corresponding toolbar + buttons. The current configuration can be selected in the + configurations listbox. Build configurations are represented by + ".lst" files (which are described in the ajc documentation). + + + + + Example: Exploring the "Spacewar" sample code + + + + Launch ajbrowser + + + Choose "File -> Open" or click the "Open Build + Configuration" button + ( + + + + ) and select the configuration file for debugging + the spacewar example, in + examples/spacewar/debug.lst. + + + Click the "Build" button ( + + + + ) to + compile. The left pane should fill with a spacewar declaration + tree. If there is a compiler error, the clickable error message + shows up as in label 4. + + + Note: If you did not install in the default location, the + compile will fail with a message that you need to install + aspectjrt.jar on your compile classpath. To do that, select "Tools + -> Options" or click the "Options" button + ( + + + + ). Click the Build Options tab + to view the Build Paths pane. Edit the classpath entry to use your + install location, ok the dialog, and retry the compile. + + + + + + + + + + Different structure views: The structure tree at the + left can display different orderings and granularity for structure: + + + The package hierarchy view shows the traditional hierarchy + of package, class, and members. + + The inheritance view shows the hierarchy from topmost + parent classes through subclasses to members. + + The crosscutting view shows the aspect members + and the code they affect. + + Additional buttons in the pane can be used to change the + granularity and filter out items. + + + + + + + Whenever you select an item in the tree view, the + source pane scrolls to that item. If you select a leaf item + representing another program element, then the tree + selection will go to the corresponding node. (See below for + how to use two panes to maintain your place.) + + + + + + When working with aspects, it helps to be able to navigate + between different program elements: + + + + + When looking at a method, find the advice that + affects it. + + When looking at a pointcut, find the advice that + uses it. + + When looking at advice, find what it advises - + e.g., method calls or executions, initializers, etc. + + + When looking at a type, find any aspects that + declare members or supertypes of the type, or + vice-versa. + + + + + You can view the advice on a particular method using the + default, hierarchical view. Navigate to the tree item for + spacewar.Registry.register(SpaceObject) + in the debug.lst config file. Now, in + the lower, file view, you can see and navigate to the advice + using the subtree whose parent is the method + affected by relation. + + + You can also use crosscutting view to see the + advice using a pointcut or the methods affected by advice. + For example, to see what advice uses a particular pointcut, + navigate to the tree item for the pointcut + spacewar.Debug.allConstructorsCut() in + the debug.lst config file. You can see + and navigate to the advice that uses the pointcut using the + pointcut used by relation. + + + As an example of seeing the methods affected by advice, + while still in the same view, select the first + before advice in + spacewar.Debug. It has relation + sub-trees for both uses pointcut and + affects constructions. The + affects relations will list different + kinds of join points - constructor or method calls, etc. + + + + + + + + + + + + diff --git a/docs/devGuideDB/ajc.xml b/docs/devGuideDB/ajc.xml new file mode 100644 index 000000000..28347b90b --- /dev/null +++ b/docs/devGuideDB/ajc.xml @@ -0,0 +1,484 @@ + + + ajc + compiler for the AspectJ language + + + + + ajc + Options + + file... + @file... + -argfile file... + + + + + + Description + + The command ajc compiles AspectJ and Java + language source files into class files. Options and files may be + specified directly on the command line, or indirectly by naming a + file which contains them. + + The arguments after the options specify the file(s) to compile. + Files may be listed directly on the command line, or listed in a file. + The @file and + -argfile file forms + are equivalent, and are interpreted as meaning all the files listed in + the specified file. Each line in these files should contain one option + or filename. Comments, as in Java, start with // and + extend to the end of the line. + + + + NB: You must explicitly pass ajc all of the source files necessary + for the compilation. When you are compiling source files containing aspects + or pointcuts, be sure + to include the source files for any types affected by the aspects or + picked out by the pointcuts. + (If you wish to exclude types from the scope affected by the + aspect, change the corresponding pointcut or declaration.) + This is necessary because, unlike javac, ajc does not search the sourcepath for classes. + + + + Options + + + + + -verbose + + Output messages about what ajc is doing + + + + + -version + + Print the version of ajc + + + + + -nocomments + + Don't generate any comments into the woven code. + Only relevant with -preprocess mode. + + + + + -emacssym + + Generate symbols used by AJDE for Emacs + + + + + -usejavac + + Use javac to generate .class files + + + + + -preprocess + + Don't try to generate any .class files. + Generate regular Java code into workingdir + + + + + -workingdir Directory + + Specify where to place intermediate .java files + Directory defaults to ./ajworkingdir. + Only relevant with -usejavac or -preprocess modes. + + + + + + + + + + + + + + + + + + -O + + Optimize; may hinder debugging or enlarge class files + + + + + + + -d Directory + + Specify where to place generated .class files + Directory defaults to the current working dir + + + + + + + + + + + + -classpath Path + + Specify where to find user class files + + + + + -bootclasspath Path + + Override location of bootstrap class files + + + + + -extdirs Path + + Override location of installed extensions + + + + + -argfile File + + the file is a line-delimited list of arguments + these arguments are inserted into the argument list + + + + + -encoding Encoding + + Specify character encoding used by source files + + + + + -source 1.4 + + Specify support for assertions according to the 1.4 Java language. + This will treat assert as a keyword and will + implement assertions according to the 1.4 language spec. + + + + + -lenient + + Be extra-lenient in interpreting the java specification + This allows some statements that some compilers consider errors. + + + + + -strict + + Be extra-strict in interpreting the java specification + This signals errors for some statements that many compilers don't + catch, and generates code strictly according to the Java Language + Specification, even though such code may not run on 1.2 VMs. + + + + + + + File names + + ajc accepts source files with either the .java + extension or the .aj extension. We normally use + .java for all of our files in an AspectJ system -- files + that contain aspects as well as files that contain classes. However, if + you have a need to mechanically distinguish files that use AspectJ's + additional functionality from those that are pure Java we recommend using + the .aj extension for those files. + + We'd like to discourage other means of mechanical distinction such as + naming conventions or sub-packages in favor of the .aj + extension. + + + + Filename conventions are hard to enforce and lead to awkward names + for your aspects. Instead of TracingAspect.java we + recommend using Tracing.aj (or just + Tracing.java) instead. + + Sub-packages move aspects out of their natural place in a system + and can create an artificial need for privileged aspects. Instead of + adding a sub-package like aspects we recommend using the + .aj extension and including these files in your existing + packages instead. + + + + + + + Compatibility + + + AspectJ is a compatible extension to the Java programming language. The + AspectJ compiler adheres to the The Java Language Specfication, Second + Edition and to the The Java Virtual Machine Specification, Second + Edition and runs on any Java 2 compatible + platform. The code it generates runs on any Java 1.1 or later + compatible platform. + + + + + Examples + + + A simple example + + Compile two files: + + + ajc HelloWorld.java Trace.java + + + + + + An example using -argfile/@ + + + To avoid specifying file names on the command line, + list source files in a line-delimited text argfile. + Source file paths may be absolute or relative to the argfile, + and may include other argfiles by @-reference. + The following file sources.lst + contains absolute and relative files and @-references: + +Gui.java +/home/user/src/Library.java +data/Repository.java +data/Access.java +@../../common/common.lst +@/home/user/src/lib.lst +view/body/ArrayView.java + + Compile the files using either the -argfile or @ form: + + +ajc -argfile sources.lst +ajc @sources.lst + + + Argfiles are also supported by jikes, javac, and ajdoc, so you + can use the files in hybrid builds. However, the support varies: + + + + Only ajc accepts command-line options + Jikes and Javac do not accept internal @argfile references. + + Jikes and Javac only accept the @file form on the command line. + + + + + + + + + + The AspectJ compiler API + + The AspectJ compiler is implemented completely in Java and can be + called as a Java class. The only interface that should be considered + public is the method org.aspectj.tools.ajc.Main.main(String[] + args) + where args are the standard ajc + command line arguments. This means that an alternative way to run the + compiler is + + + java org.aspectj.tools.ajc.Main + option... + file... + + + + + To run in -usejavac mode, + you must include in your classpath the + tools.jar from your Java 2 developer's kit. + + + + + + Stack Traces and the SourceFile attribute + + Unlike traditional java compilers, the AspectJ compiler may in + certain cases generate classfiles from multiple source files. + Unfortunately, the Java class file format does not support multiple + SourceFile attributes. So, in order to make sure all source file + information is available, the AspectJ compiler may in some cases + encode multiple filenames in the SourceFile attribute. + + + Probably the only time you may see this format is when you view + stack traces, where you may encounter traces of the format + + + +java.lang.NullPointerException + at Main.new$constructor_call37(Main.java;SynchAspect.java[1k]:1030) + + + where instead of the usual + + + +File:LineNumber + + + format, you see + + + +File0;File1[Number1];File2[Number2] ... :LineNumber + + + In this case, LineNumber is the usual offset in lines plus the + "start line" of the actual source file. That means you use LineNumber + both to identify the source file and to find the line at issue. + The number in [brackets] after each file tells you the + virtual "start line" for that file (the first file has a start of 0). + + + In our example from the null pointer exception trace, + the virtual start line is 1030. Since the file SynchAspect.java + "starts" at line 1000 [1k], the LineNumber points to line 30 of + SynchAspect.java. + + + So, when faced with such stack traces, the way to find the actual + source location is to look through the list of "start line" numbers to + find the one just under the shown line number. That is the file where + the source location can actually be found. Then, subtract that "start + line" from the shown line number to find the actual line number within + that file. + + + Of course, AspectJ tools will do this decoding for you, and in a + class file that comes from only a single source file, the AspectJ + compiler generates SourceFile attributes consistent with + traditional Java compilers. + + + + + + + + + + + + + diff --git a/docs/devGuideDB/ajdb.xml b/docs/devGuideDB/ajdb.xml new file mode 100644 index 000000000..832002823 --- /dev/null +++ b/docs/devGuideDB/ajdb.xml @@ -0,0 +1,312 @@ + + + ajdb + debugger for .class files produced by ajc (early-access) + + + + + ajdb + -classpath path + -Dname=value + -help + -gui + -read file + -sourcepath dir + + + -v + -verbose + + :class + :gc + :jni + + + + workingdir dir + -Xoption + class + arguments + + + + + + Description + + The command ajdb is used to debug AspectJ and + Java programs. In addition to its command line interface, + adjb also has a standalone, Swing-based GUI + interface. + + + Note: As of the 1.0.3 release, AspectJ supports JSR-45, which provides + source-level debugging from many source files per class + and non-Java source files. + JSR-45 is implemented in the J2SE 1.4 debugger support, so + you may be able to use your existing debugger to step through + AspectJ source code if both the source and target VM's are + running under Java 1.4 or later. + However, existing debuggers will display synthetic methods + in the stack frame. + + + + -classpath path + Specify where to find user class files. + + + -Dname=value + + Define the property name to have the value + value. + + -help + Print out ajdb's usage summary. + + -read file + Read this file for initializatoin commands. + + -sourcepath path + Search this directory for source files. + + -gui + + + -v | -verbose [:class | :gc | :jni] + Print out class loading, garbage collection or dynamic library + loading information. Defaults to class loading. + + + -workingdir directory + Set ajdb's working directory. + + -Xoption + Pass a non-standard option to the VM + + + + Capabilities + + The AspectJ debugger implements all of jdb's + commands. In addition, the command workingdir + allow you to set the AspectJ working directory, and the breakpoint + command, stop on, has been extended to allow the + setting of breakpoint on a source file line. + + + + + Examples + + + Command line use + + Suppose you want to debug the file spacewar/Ship.java found in + the examples directory. At the command line start up the debugger: + + + ajdb + + + + + + The debugger will first look for initialization files in your + home or current directory called either + ajdb.ini or .ajdbrc and + execute the commands contained in them. A useful command to have + in this file is the source-path command which + tells the debugger where to find source files. + + + For this example, we need to set the source path by: + + + use C:\src + + + + To view the file to debug, type list + spacewar/Ship.java which generates the following + output: + + 209 void fire() { + 210 // firing a shot takes energy + 211 if (!expendEnergy(BULLET_ENERGY)) + 212 return; + 213 + 214 //create a bullet object so it doesn't hit the ship that's firing it + 215 double xV = getXVel() + BULLET_SPEED * (Math.cos(orientation)); + 216 double yV = getYVel() + BULLET_SPEED * (Math.sin(orientation)); + 217 + 218 // create the actual bullet + 219 new Bullet( + 220 getGame(), + 221 (getXPos() + ((getSize()/2 + 2) * (Math.cos(orientation))) + xV), + 222 (getYPos() + ((getSize()/2 + 2) * (Math.sin(orientation))) + yV), + 223 xV, + 224 yV); + 225 } + + + This is different from jdb because it allows + one to view files before the debugger has started. The + list command has the following syntax: + + + list + list the source containing the location at which we are + currently stopped (can only be used with a running VM) + + list + source + list the entire file source + + list source line + list source line line of file source + + + list source start-line + end-line + + + list the lines from start-line to + end-line of file + source + + + + + To set a breakpoint in the method Ship.fire, we + would could type stop in spacewar.Ship.fire. + + + The following message appears notifying the user that the + breakpoint has been noted but will not be set until the class has + been loaded by the VM: + + Deferring breakpoint spacewar.Ship.fire() + It will be set after the class is loaded. + + + + To start Spacewar we type run spacewar.Game. + + + + When the breakpoint is set, the following message appears: + + Set deferred breakpoint spacewar.Ship.fire() + + + + We are notified that we've hit the breakpoint: + + + Breakpoint hit: thread="Thread-2", spacewar.Ship.fire(), line=174, bci=0 209 void fire() { + + + + The prompt changes to present the thread that has broken, and we + can view the current stack with the where + command, as follows: + + Thread-2[1] where + [1] fire (spacewar\Ship.java:209) + [2] run (spacewar\Robot.java:100) + [3] run [class java.lang.Thread] + + + + + Next, to stop on line 216 we + type stop on spacewar/Ship.java:216 + + + + The following message tells us the breakpoint was set: + + Set breakpoint Ship.java:216 + + + + To continue execution, we type cont and the + breakpoint at line 216 is hit + + Breakpoint hit: thread="Thread-2", spacewar.Ship.fire(), line=216, bci=28 + 216 double yV = getYVel() + BULLET_SPEED * (Math.sin(orientation)); + + + + To view the visible local variables, we type + locals and ajdb responds with: + + Local variables + xV = 12.242462584304468 + + + + To change the value of the local variable i to 15, we type + set xV = 16.1 + + + Changed 'xV' from '12.242462584304468' to '16.1' + + + + To see our changes we can print the value of i + by the following: + + print xV + Value for printing 'xV' = 12.242462584304468 + + + We can now type exit or quit to leave the debugger, and we + receive the following message: + + + The application has exited. + + + + + + + The AspectJ debugger API + + + The AspectJ debugger is implemented completely in Java and can be + called as a Java class. The only interface that should be + considered public is the method + org.aspectj.tools.debugger.Main.main(String[] + args) where args are the standard + ajc command line arguments. This means that an + alternative way to run the compiler is + + + + java org.aspectj.tools.debugger.Main + + option + class + arguments + + + + + You must additionally include tools.jar from + your Java developer's kit in your classpath. + + + + + + + + + + + + diff --git a/docs/devGuideDB/ajdee.gif b/docs/devGuideDB/ajdee.gif new file mode 100644 index 000000000..e50832d0a Binary files /dev/null and b/docs/devGuideDB/ajdee.gif differ diff --git a/docs/devGuideDB/ajdee.xml b/docs/devGuideDB/ajdee.xml new file mode 100644 index 000000000..7c42a90fd --- /dev/null +++ b/docs/devGuideDB/ajdee.xml @@ -0,0 +1,452 @@ + + + AJDEE + JDEE support for XEmacs and GNU Emacs + + + + AJDE for Emacs User's Guide + + This guide describes AspectJ-mode extensions of JDEE for GNU Emacs and + XEmacs, which + provides enhanced editing and management of AspectJ code via a minor + mode extension of JDE mode. AJDEE's AspectJ support builds on + aspectj-mode's extension of + java-mode, also provided with the release. + Included in this document are guidance for AJDEE's use, including an exploration of spacewar, and installation and compatibility. See + the README file in AJDEE's distribution directory for + release-specific details. + + + + In addition to the java-mode extensions provided by + aspectj-mode, AJDEE provides + (see graphic): + + + + Viewing and navigation of aspect structures via the + the speedbar and Classes menu. + + + + + + Basic support for completion. + + + + + + Integrated Javadoc support. + + + + + + + + + + + + + + + + + AJDEE Features and Usage + + The AJDEE extensions of JDE require no special effort to use. + The speedbar and Classes menus provide additional sublists showing + crosscutting structure. Selecting items in those lists navigates to + the referenced item. + + + + Aspect Structure and Navigation + + + Enhancements to Speedbar in JDE Mode + + As a minor mode of JDE mode, AJDEE enhances the speedbar to + show the location of aspect, advice, and inter-type declarations. + The affects/affected-by relationships are shown in the speedbar + rather than embedding tags in the text (available as an option), + and selecting the items in the speedbar will perform the expected + navigation. The speedbar symbols have been extended for AspectJ as + follows (see right side of figure): + + + + Enhancements to Speedbar in JDE Mode + + + + Indication + Meaning + + + + + + + (+) + name + + + A class, interface, or aspect; double mouse-1 will + display its declarations + + + + + + + methodSignature + + + Method has an advice that applies to it; double mouse-1 + will display the relevant advice. + + + + + + + adviceSignature + + + Advice declared by the containing aspect; double mouse-1 + will display affected methods. + + + + + + + introductionSig + + + Inter-type declaration declared by the containing class; double + mouse-1 will display affected methods or classes. + + + + + | | + methodOrFieldSig + + + Method or field has been declared by an aspect; + double mouse-1 on text will navigate to the declaration; a + + within the bars means that it has an advice that applies + to it. + + + + +
+ + + A minus (-) is displayed on the item when the + crosscutting items are displayed. AspectJ structure information is + derived from the last compile of your AspectJ program. + +
+
+ + + Compilation and JavaDoc + + + The option + can be customized from the Customize options + under the AspectJ menu, changing the default + compile specification given to ajc. + See installation instructions + for examples and other customizations. + + + + AspectJ JavaDoc support is + enabled by setting to + invoke ajdoc. These are the default settings + provided in the installation instructions. + + + +
+ + + Exploring the Spacewar Source Code + + To begin exploring Spacewar within emacs using JDE and AspectJ mode: + + + + Compile spacewar. + + + + Change into the spacewar + directory. + + + + Type emacs Ship.java. + + + + + Pull down the JDE menu and select the + Speedbar entry to show the AspectJ + files in the directory. Note that Ship.java + is shown in red to denote that it is currently shown in the main + buffer. + + + + + + Double-click with the left mouse button on the + + in front of the + Ship.java entry. It should display an entry + for the class Ship. + + + + + + Double-clicking on Ship will navigate to its declaration in + the buffer. Note that declarations of advice are annotated to + note the types of objects that they advise, declarations of + methods that are advised are annotated with the aspects that + advise them, and so forth. + + + + + + Double-clicking on the + in front of either + will show the declared fields, methods, inter-type declarations, and + advice. A + in front of any field or method + means that it is introduced or advised; double-clicking will list + entries for the introducers/advisers; double-clicking on them + will navigate to their declarations. A + in + front of any inter-type declarations or advice will will display its + targets. + + + + + + + + Installation and Compatibility + + AJDEE requires the installation of + JDE 2.2.9beta4 or + higher and small edits to your .emacs file to + configure AJDEE and enable autoloading AJDEE when a + .java file is loaded. + + + + Installation for enhancement of JDE mode + + + + The first and last steps, with enhancements, can be found in the + example Emacs initialization file + sample.emacs and the sample JDE project + file sample.prj in the distribution. The + latter also demonstrates a way to enable AspectJ mode on a + per-project basis. + + + + + + + Make sure AJDEE, aspectj-mode, JDE, and supporting packages are on + your load-path and are ``required''. This is an + example for the 1.0 release: + + ;; I keep my emacs packages in C:/Emacs + (setq load-path + (append + '( + "C:/Emacs/aspectj-emacsMode-1.0" ; for AJDEE + "C:/Emacs/aspectj-emacsAJDEE-1.0" + "C:/Emacs/jde-2.2.9beta6/lisp" + "C:/Emacs/elib-1.0" ; for JDEE + "C:/Emacs/speedbar-0.14beta2" ; for JDEE + "C:/Emacs/semantic-1.4beta12" ; for JDEE/speedbar + "C:/Emacs/eieio-0.17beta3" ; for JDEE + ) + load-path)) + + (require 'jde) + (require 'ajdee) ; can also appear in prj.el + + + + + + [Optional] add -emacssym + switch to the ajc and ajc.bat + files in your AspectJ tools installations (in the + /bin directory). If you invoke the compiler + outside Emacs, this will + ensure that your compiles always generate information for annotations + and the jump menu in the form of .ajesym files. + + + + + + Customize AJDEE's compile options by + putting a version of the following in your + .emacs file or in a JDE project file + prj.el in your project's hierarchy (see the + option for the latter). + Here is a simple example: + + + ;; A default version for simple projects, maybe good for + ;;; .emacs file. + (custom-set-variables + '(jde-compiler '("ajc" "ajc")) + '(jde-javadoc-command-path "ajdoc") + + ;; ajc requires all files to be named for a compile + '(aspectj-compile-file-specification "*.java")) + + Here is an example for spacewar, in + examples/spacewar. + + ;;; These options are for the spacewar, in examples/spacewar. + (custom-set-variables + '(jde-compiler '("ajc" "ajc")) + '(jde-javadoc-command-path "ajdoc") + + ;; ajc provides an ``argfile'' mechanism for specifying all files. + '(aspectj-compile-file-specification "-argfile demo.lst") + + ;; *if* compiling packages, name root dir for package hierarchy + ;; to tell ajc where .class files should go. + '(jde-compile-option-directory "..") + '(jde-run-working-directory "..")) + '(jde-run-application-class "spacewar.Game") + + + + + [XEmacs only] If you're installing JDE + yourself, be sure to closely follow the JDE installation + directions for XEmacs, otherwise you may get out of date JDE + .jar files. + + + + + + + + Customizing Options + + Selecting Customize options from the + AspectJ menu displays a number of options that + customize AspectJ mode. These control whether annotations are shown + by default, and whether the bovinator set up by JDE runs. + , specifies a + compilation argument as + an alternative to the current buffer's file or the run class's file. + Example customizations are shown above and in the sample files + discussed above. + + + + + + + + Usage and Upgrade Problems + + Please see the documentation for + aspectj-mode for problems not + specific to AJDEE's features. + + + + + Symptom: Get + standard speedbar menus in JDE; no annotations display. Message: + + +AspectJ Mode Warning: Can't find declarations file for... + + + + + AspectJ file has not been compiled with ajc and the -emacssym + flag, + or was compiled with an obsolete version of ajc. After compilation, + there should be a <file>.ajesym for every <file>.java in the + build. If .ajsym files are present but error persists, recompile. Note + that aspectj-mode for JDE has a fallback view for uncompiled files. + + + + + Symptom: Navigations via the speedbar and + the jump menu are off, annotations are misplaced in the code. + + AspectJ mode operates by querying data + derived from the most recent compile that includes the + -emacssym flag. Recompile the entire program with + ajc including the switch. Consider permanently installing the switch + by editing the ajc and ajc.bat files in the /bin file in your + distribution. + + + + Symptom: Java files that are part of a Java project not written + in AspectJ come up in aspectj-mode. + + Emacs uses the file suffix (.java) to + determine which mode to invoke. You can either globally toggle the + AspectJ features from the AspectJ menu, or you can prevent AJDEE + from coming up by moving the (require 'ajdee) expression from + your .emacs file to a prj.el file in each AspectJ project's directory + (see sample.prj in the distribution). + + + + + Symptom: Reported bug fixes and new features + to AJDEE are not seen, or ajdee.el cannot be found or loaded, with + message: + + +Error in init file: File error: "Cannot open load file", "ajdee" + + + + Your load-path variable (set in your .emacs) + is referring to an old release. Change your load-path to + point at the directory for the current release. See the sample.emacs + files in the distribution, for example. + + + +
+ + + + + + + diff --git a/docs/devGuideDB/ajdeforte.xml b/docs/devGuideDB/ajdeforte.xml new file mode 100644 index 000000000..910f62d81 --- /dev/null +++ b/docs/devGuideDB/ajdeforte.xml @@ -0,0 +1,215 @@ + + + + AspectJ Development Environment (AJDE) support for Forte + + + Module extension to Sun's Forte + for Java and + NetBeans IDEs. + + + + + Overview + + For release-specific documentation refer to the changes file. + + + + AJDE for Forte will allow you to: + + + compile AspectJ and Java files within the + IDE + + browse the structure of your AspectJ + program + + set up a compile configuration that determine which + files will be passed to the compiler + + + + + + + Installation + + + + use the installer to place the "ajdeForForte.jar" and + "aspectjrt.jar" into the modules directory. This will also install + the two html files "LICENCE-AJDEFORTE.html" and + "README-AJDEFORTE.html". + + start up, and in the "Tools" menu select "Global + Options" + + right-click the "Modules" item and select "New Module + from File..." + + find the ajdeForForte.jar in the directory that you + installed into (e.g. c:/forte4j/modules) and select it + + + + + + To uninstall follow Forte's documentation on un-installing modules, or + simply remove the file modules/aspectjForForte.jar from Forte's + install directory. + + + + + Running AJDE for Forte + + 3.1 Setting up the AspectJ Examples (in + NetBeans 3.3.1) + + + + + + + + in the "Project" menu select "Project Manager" + + + Click "New..." and enter "AspectJ Examples" as the + projects' name and click "OK". + + In the "Filesystems" Explorer tab right click + "Filesystems", then select "Mount -> Local Directory". + + + browse into the AspectJ install directory (e.g. + "C:/apps/aspectj1.0") + + select "examples" and click "Finish" + + + + In the "Tools" menu select "AspectJ -> Start AJDE" + or just click on the "AJDE" + ( + + + + ) + button (shown as label 1 of the screenshot). + + + + + + 3.2 Compiling the Spacewar Example + + + + After AJDE is started, a new "AspectJ" tab is added + to the explorer window. Click it. The next thing to do is to choose + a particular build, since there are many in the examples + distribution. To the right of the "Build" button + ( + + + + ) + there is a downward arrow. Click it, and select "spacewar/demo.lst" + (as in label 2 of the screenshot). This will start a build of the + demo configuration of spacewar. Clicking the "Build" button will + rebuild. + + When the compile is finished and the "AspectJ + Explorer" structure is present navigate the structure by clicking + nodes (as shown in label 3 of the screenshot). Note that + associations between nodes appear with UML-style arrow icons and + italicized names and reperesent how a particular node in the + structure relates to others. In order to navigate these associations + expand the notes and click the corresponding links (in blue). These + links represent structure nodes elsewhere in the tree. + + + If there are compilation errors, clickable messages + will appear (as in label 4 of the screenshot). + + + + + + + + 3.3 Running the Spacewar Example + + + In the "Filesystems" Explorer tab open the "spacewar" + directory, right click "spacewar/Game.java", and the select + "Execute". + + + When finished executing switch back to the "Editing" + mode. + + Select and build the "debug.lst" configuration as + described in 3.2 and execute again--you will notice that the debug + configuration adds a debug window used for tracing by including the + "Debug.java" aspect in the compile. + + + + + 3.4 Debugging the Spacewar Example + + + + You must first add the filesystem to the project so + that the debugger can see the main class. Do this in + the "Project AspectJ Examples" tab in the explorer by + right clicking the root node and selecting "Add + Existing...". + + + You may now need to add the AspectJ Runtime to the + project so that the debugger can see it. In the same way as described + in 3.1 select "Mount -> Archive (JAR, Zip)". + + Browse to the your lib/ext/aspectjrt.jar file within + your NetBeans install directory and click "Finish". + + + Select "Project -> Set Project Main Class..." in the + menu bar, browse to "spacewar/Game.java" in the + examples directory that you created and click "OK". + + + + In the "Filesystems" Explorer tab open the "spacewar" + directory, click "Game.java", and the select "Debug + -> Strat" from the menu bar. + + + + + AspectJ-related options can be modified in the AJDE settings window. + + + + + + + + + + + + + + + + + + + diff --git a/docs/devGuideDB/ajdejbuilder.xml b/docs/devGuideDB/ajdejbuilder.xml new file mode 100644 index 000000000..a201dd48d --- /dev/null +++ b/docs/devGuideDB/ajdejbuilder.xml @@ -0,0 +1,266 @@ +r + + + AspectJ Development Environment (AJDE) support for JBuilder + + + OpenTool extension Borland's JBuilder IDE. + + + + Overview + + For release-specific documentation refer to the changes file. + + + AJDE for JBuilder will allow you to: + + + compile AspectJ and Java files within the + IDE + + + browse the structure of your AspectJ + program + + + set up a compile configuration that determine which + files will be passed to the compiler + + + + + + Installation and Project Setup + + Install procedure: use the installer to place the + "ajdeForJBuilder.jar" and "aspectjrt.jar" into JBuilder's lib/ext + directory. This will also install the two html files + "LICENCE-AJDEJBUILDER.html" and "README-AJDEJBUILDER.html". + + + Uninstall procedure: remove "ajdeForJBuilder.jar" + and "aspectjrt.jar" (and the two html files, if you like) from the + "lib/ext" directory. + + + Project setup: follow the normal procedure for + JBuilder project setup (for an example of this please refer to the + example below). However, note that all of the source files to be + passed to the compiler must be added to your project either as files or + within a package that is added to the project. This is necessary + because -- unlike a pure Java compiler -- ajc does not search the + SOURCEPATH for classes. + + + + + + Starting and stopping AJDE: select "Start AJDE" in + the "AspectJ" section of the "Tools" menu, or just click on the "AJDE" + ( + + + + ) button (label 1 in the first screenshot). This + will enable AJDE commands and will replace JBuilder's structure view + with the AspectJ Browser. To disable AJDE select "Stop AJDE" in the + same menu, or click the "AJDE" button again. + + + + Compiling and Running the Project + + To compile the project select "Build project with ajc" from the AspectJ + toolbar, or click <ctrl>F11 while the editor pane is active. All + of the files contained in your project and within any packages and + subpackages that have been added to your project will be compiled. You + may also select a different configuration (as with label 2 in the first + screenshot). Then, structure of the currently visited file is shown + (see label 3 in the first scrrenshot). If there is a compile error, + the clickable error message is available (as with label 4 in the first + screenshot). + + + To run the project select "Run Project" from the AspectJ toolbar, or + click <ctrl>F12 while the editor pane is active. Note that the + "AspectJ Runtime" library must be added to your project in order to + run. If the library is not added you will see a "java.lang.NoClassDefFoundError: org/aspectj/lang/Signature" error. The library is created automatically for you from the runtime + in "jbuilderdir/lib/ext". You can also create a new library + to use the runtime from a different location. If you have not added the + library to the "Required Libraries" of your project it will be added + automatically when you restart JBuilder. + + + JBuilder7 users please note: when you set up a run/debug configuration + you must select the "Build Target" (at the bottom of the + "Runtime Properties" dialog) to be "<None>". This will ensure + that the Java compiler is not invoked on your AspectJ sources + before running or debugging the project. + + + + Navigating the Program Structure + + + + + Navigation of program structure is provided by the AspectJ Browser, so apart from a JBuilder + look and feel, the extra navigation AspectJ allows work as described + there. In particular, you can use views with labels 1, 2 and 4 of the + second screenshot to navigate structure using the blue links, and you + can set filtering and navigate history using the toolbar shown by label + 3 of the second screenshot. + + + + Manipulating Build Configurations + + Build configurations can be manipulated adding, removing, and + editing build configuration files. The AspectJ Browser is used to select the + current build configuration. Configurations are represented by + ".lst" files which are described in the ajc documentation. + + + + + + Adding and Removing Build Configurations + + By default all of the files contained in your project and + within any packages and subpackages that have been added to + your project will be compiled. In order to compile a different + configuration first add it to the project (by selecting + "Add Files / Packages..." in the "Project" + menu, and selecting the desired build configuration file (see + label 1 in the third screenshot). + + + + Editing Build Configurations + + Double click a build configuration file in JBuilder's + "Project Pane" in order to edit it. Configurations + can be edited as either text or in the graphical designer (see + labels 2 and 3 in the third screenshot) + + + + + Example: Setting up the "Spacewar" Sample Project + + To set up the Spacewar example first download it the examples distribution. Then + + + + launch JBuilder + + + in the "File" menu select "New + project" + + + Select the location of the "aspectj/examples" + directory for the project. This is because the Spacewar + example uses both the "spacewar" and "coordination" + packages, so we set up the project where it can get at both + packages. + + + + + Choose a "jpr" project, either by typing in "Spacewar.jpr" + as the project name, or by typing "Spacewar" as the project + name and "jpr" as the type. Make sure "aspectj/examples" + is still the directory for the project. + + + click "Finish" + + + in the "Project" menu select "Project + properties..." + + + set the "Output path" entry to be the directory + where you want your classes to go + + + set the "Output path" entry to be the directory + where you want your classes to go + + + add "aspectjrt.jar" as a required library for + the project. This library is located in + "<jbuilder-install-directory>/lib/ext". + + + + + in the "Source" tab select the entry and click + "Edit" (by default JBuilder will set this directory to be + "examples/src" which does not exist) + + + + Select the "examples" directory for the + Souce. + + + click "OK" to close the "Project + Properties"dialog + + + 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". + + + <cntrl> select the "spacewar" and + "coordination" packages and then click "OK"; this will add + the two packages to your project + + + click the "Build Project" button + ( + + + + ) + to compile the project + + + open the Structure View to browse the structure + of the program + + + click the "Run Project" button to play + Spacewar (make sure that you have set up the runtime + library as described above) + + + if you have not selected a class to run, you + will be prompted to do so: select the class + "spacewar.Game". + + + AspectJ related build options can be + manipulated in the "AJDE settings" window + + + + + + + + + + + + + + + + diff --git a/docs/devGuideDB/ajdoc.xml b/docs/devGuideDB/ajdoc.xml new file mode 100644 index 000000000..be13c897c --- /dev/null +++ b/docs/devGuideDB/ajdoc.xml @@ -0,0 +1,155 @@ + + + ajdoc + generate HTML API documentation, including crosscutting structure (early-access) + + + + + + ajdoc + + -bootclasspath classpathlist + + + -classpath classpathlist + + -d path + -help + -package + -protected + -private + -public + -overview overviewFile + + -sourcepath sourcepathlist + + -verbose + -version + + sourcefiles... + packages... + @file... + -argfile file... + + + + + + Description + + Similar to javadoc, + ajdoc renders HTML documentation for pointcuts, + advice, and inter-type declarations, as + well as the Java constructs that Javadoc renders. + ajdoc also links + advice from members affected by the advice and + the inter-type declaration for members declared from aspects. + The aspect will be fully documented, + as will your target classes, including links to any + advice or declarations that affect the class. + That means, for example, that + you can see everything affecting a method when reading + the documentation for the method. + + + + To run ajdoc, use one of the scripts in the + AspectJ bin directory. + The ajdoc implementation builds on Sun's javadoc + command line tool, and you use it in the same way with many of + the same options + (javadoc options are not documented here; + for more information on javadoc usage, see the + Javadoc homepage.) + + + + As with ajc (but unlike javadoc), + you pass ajdoc all your aspect source files + and any files containing types affected by the aspects; + it's often easiest to just pass all the .java files + in your system. + Unlike ajc, + ajdoc will try to find package sources using the + specified sourcepath if you list packages on the command line. + + + + + To provide an argfile listing the source files, you can use + use the same argfile (@filename) conventions + as with ajc. + For example, the following documents all the source files listed + in argfile.lst, sending the output to + the docDir output directory. + + ajdoc -d docDir @argfile.lst + + See the ajc documentation + for details on the text file format. + + + + ajdoc currently requires the + tools.jar from J2SE 1.3 to be on the classpath. + Normally the scripts set this up, assuming that your JAVA_HOME + variable points to an appropriate installation of Java. + You may need to provide this jar when using a different + version of Java or a JRE. + + + + + Examples + + Documenting Spacewar + + + + Change into the examples directory. + + + + + + Type mkdir doc to create the + destination directory for the documentation. + + + + + Type ajdoc -private -d doc spacewar + coordination to generate the documentation. + + + + + (Use -private to get all members, since + may of the interesting ones in spacewar are not public.) + + + + + + + Type ajdoc -private -d doc @spacewar/demo.lst + to use the argfile associated with Spacewar. + + + + + To view the documentation, open the file index.html + in the doc directory using a web browser. + + + + + + + + + + + + diff --git a/docs/devGuideDB/antsupport.xml b/docs/devGuideDB/antsupport.xml new file mode 100644 index 000000000..1b97968aa --- /dev/null +++ b/docs/devGuideDB/antsupport.xml @@ -0,0 +1,23 @@ + + + Ant Support + Support of Ant + + + + + ant + + + + + Description + + + + + + + + + diff --git a/docs/devGuideDB/aspectj-mode.gif b/docs/devGuideDB/aspectj-mode.gif new file mode 100644 index 000000000..9b07fdb33 Binary files /dev/null and b/docs/devGuideDB/aspectj-mode.gif differ diff --git a/docs/devGuideDB/aspectj-mode.xml b/docs/devGuideDB/aspectj-mode.xml new file mode 100644 index 000000000..b54837964 --- /dev/null +++ b/docs/devGuideDB/aspectj-mode.xml @@ -0,0 +1,354 @@ + + + AspectJ-mode + support for XEmacs and GNU Emacs + + + + + AspectJ-mode User's Guide + + This guide describes aspectj-mode for GNU Emacs and XEmacs, which + provides enhanced editing and management of AspectJ code via a minor + mode extension of java-mode. Included in this document + are guidance for aspectj-mode's use, and + installation and compatibility. + See the README file in the aspectj-mode's distribution directory for + release-specific details. + + + + AspectJ minor mode provides (see graphic): + + + + Viewing and navigation of aspect structures, permitting + navigation between aspect code and the code that it affects, via + a `jump' menu (and in the speedbar and Classes menu for JDE + users). + + + + + + Source code annotation of inter-type and advice declarations, + as well as the code they affect. + + + + + + AspectJ-style compilation, using .lst files to generate a + compilation submenu. + + + + + + Highlighting of AspectJ keywords and declaration names. + + + + + + + + The first two are derived from ajc's last build of the AspectJ program. + An example usage is given below. + + + + + + + + + + + + + Features and Usage + + All commands governing AspectJ mode are available from the AspectJ menu + on the toolbar. Besides those described below, there is a menu item + Customize options for viewing and customizing + the options of the mode and AJ Mode user guide + to view this file. Keyword and declaration highlighting is enabled above + the minimal level of highlighting. + + + + By default, AspectJ mode is automatically turned on when a buffer + named with a .java suffix is entered. + The command + M-x aspectj-mode-in-force-toggle globally toggles + the features of the mode, easing quickly moving between + AspectJ and Java projects (also available as AspectJ mode + extensions in the AspectJ menu). + + + + Aspect Structure and Navigation + + + AspectJ minor mode highlights aspect relationships in the text with + textual annotations on the program source (optionally can be turned + off), such as the [Player, Robot, Ship] marking after the advice in EnsureShipIsAlive + at the bottom of the figure, + which indicates that the advice refers to join points within Ship + objects. The following commands (also available from the menu) manage + annotations and navigation: + + + + + AspectJ Minor Mode Commands for Annotations and Navigation + + + + + Command (keyboard shortcut) + Description + + + + + + M-x aspectj-jump-menu (C-x C-j) + + Display popup menu of advisers, advisees, and inter-type declarations. + Navigate to item by selecting with mouse + (see figure below). + + + + M-x aspectj-show-annotations + + Add crosscut annotations on the text on current buffer. + + + + + M-x aspectj-dont-show-annotations + + Remove crosscut annotations from text on current buffer. + + + + +
+ + + The default for whether annotations are shown or not can be + customized by selecting Customize options + from the AspectJ menu. + + + + + + + + + + +
+ + + Compilation + + + The Compile submenu + accessible from the AspectJ menu presents the + known .lst files for the project. Selecting + one compiles the project with that .lst file + and remembers that for future compiles. The + Compile... command accessible from the + Emacs Tools menu is customized through the + project customization option , customizable from the + AspectJ menu. + + + + +
+ + + Installation and Compatibility + + AspectJ mode requires the installation of GNU Emacs 20.3.1 + or XEmacs 21.1.14 (Unix/Linux), + or XEmacs 21.4 (Windows), + or higher. In general, the most recent non-alpha/beta versions of these + are recommended. A web browser is required to view this documentation + via Emacs. Small modifications to the .emacs file + configures AspectJ mode and enables autoloading AspectJ mode when a + .java file is loaded. + + + + + Installation + + + + + Step 1, with enhancements, can be found in the example Emacs + initialization file sample.emacs in the + distribution. + + + + + + + The files in this package need to be in the load-path and + ``required''. For example, for the 1.0 release: + + ;; I keep my emacs packages in C:/Emacs + (setq load-path (cons "C:/Emacs/aspectj-emacsMode-1.0" load-path)) + (require 'aspectj-mode) + + + + + + [Optional] add -emacssym + switch to the ajc and ajc.bat + files in your AspectJ tools installations (in the + /bin directory). If you invoke the compiler + outside Emacs, this will + ensure that your compiles always generate information for annotations + and the jump menu in the form of .ajesym files. + + + + + + + [XEmacs only] Go to the + xemacs-packages/lisp directory of your + XEmacs distribution and move the jde + directory to someplace harmless. Otherwise, Java files will come + up in JDE mode. + + + + + + + + Customizing Options + + Selecting Customize options from the + AspectJ menu displays a number of options that + customize AspectJ mode. These control whether annotations are shown + by default, as well as a + number of options controlling compilation and beanshell for + java-mode. + Example customizations are given in the file + sample.emacs in the distribution. + + + + + + + Usage and Upgrade Problems + + + + + Symptom: No annotations show. Message: + + +AspectJ Mode Warning: Can't find declarations file for... + + + + + AspectJ file has not been compiled with ajc and the -emacssym + flag, + or was compiled with an obsolete version of ajc. After compilation, + there should be a <file>.ajesym for every <file>.java in the + build. If .ajsym files are present but error persists, recompile. Note + that aspectj-mode for JDE has a fallback view for uncompiled files. + + + + + Symptom: Annotations are misplaced in the + code. + + AspectJ mode operates by querying data + derived from the most recent compile that includes the + -emacssym flag. Recompile the entire program with + ajc including the switch. Consider permanently installing the switch + by editing the ajc and ajc.bat files in the /bin file in your + distribution. + + + + Symptom: New customization option settings were saved + for future sessions, but do not show up when Emacs is restarted. + + + You may have two sets of saved settings in + your .emacs file, and Emacs updated the first one, which may be shadowed + by the second. + + + + Symptom: Java files that are part of a Java project not written + in AspectJ come up in aspectj-mode. + + Emacs uses the file suffix (.java) to + determine which mode to invoke. You can either globally toggle the + AspectJ features from the AspectJ menu. + + + + + Symptom: Reported bug fixes and new features + to aspectj-mode are not seen, or aspectj-mode.el cannot be found or + loaded, with message: + + +Error in init file: File error: "Cannot open load file", "aspectj-mode" + + + + Your load-path variable (set in your .emacs) + is referring to an old release. Change your load-path to + point at the directory for the current release. See the sample.emacs + files in the distribution, for example. + + + + Symptom: When trying to get a jump menu, + I get the message "No crosscut elements at point" even though + there is a [list] on the same line. + + + The caret (point) is probably on or after the list. + To see the crosscut elements you need to hit the jump menu + on the same line that the annotated elements appear as a list + of items surrounded by '[' and ']' on the same line as the + affected declaration. If the caret is on the same line as the + elements and before the list (i.e. not at the end of the + list of elements) the jump menu should work. + + + + +
+ + + + + + + diff --git a/docs/devGuideDB/aspectj-mode2.gif b/docs/devGuideDB/aspectj-mode2.gif new file mode 100644 index 000000000..f9e718385 Binary files /dev/null and b/docs/devGuideDB/aspectj-mode2.gif differ diff --git a/docs/devGuideDB/devguide.xml b/docs/devGuideDB/devguide.xml new file mode 100644 index 000000000..5b2b1ba30 --- /dev/null +++ b/docs/devGuideDB/devguide.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + +]> + + + + The AspectJ<superscript>tm</superscript> Development Environment Guide + + + + the AspectJ Team + + + + + Copyright (c) 1998-2001 Xerox Corporation, + 2002 Palo Alto Research Center, Incorporated. + All rights reserved. + + + + + + This user's guide describes the tools which are part of the + AspectJ development environment. A companion guide describes the + AspectJ language. + + + + + + The Command Line Tools + &ajc; + &ajdb; + &ajdoc; + + + + The GUI Tools + &ajbrowser; + &ajdejbuilder; + &ajdeforte; + &aspectj-mode; + &ajdee; + + + + + diff --git a/docs/devGuideDB/jbuilder-buildOptions.gif b/docs/devGuideDB/jbuilder-buildOptions.gif new file mode 100644 index 000000000..5a34c9309 Binary files /dev/null and b/docs/devGuideDB/jbuilder-buildOptions.gif differ diff --git a/docs/devGuideDB/jbuilder-building.gif b/docs/devGuideDB/jbuilder-building.gif new file mode 100644 index 000000000..63fe151a2 Binary files /dev/null and b/docs/devGuideDB/jbuilder-building.gif differ diff --git a/docs/devGuideDB/jbuilder-configs.gif b/docs/devGuideDB/jbuilder-configs.gif new file mode 100644 index 000000000..1a262c1cf Binary files /dev/null and b/docs/devGuideDB/jbuilder-configs.gif differ diff --git a/docs/devGuideDB/jbuilder-structureNavigation.gif b/docs/devGuideDB/jbuilder-structureNavigation.gif new file mode 100644 index 000000000..bdd7ce815 Binary files /dev/null and b/docs/devGuideDB/jbuilder-structureNavigation.gif differ diff --git a/docs/devGuideDB/netbeans-buildOptions.gif b/docs/devGuideDB/netbeans-buildOptions.gif new file mode 100644 index 000000000..5cd5e75d2 Binary files /dev/null and b/docs/devGuideDB/netbeans-buildOptions.gif differ diff --git a/docs/devGuideDB/netbeans-building.gif b/docs/devGuideDB/netbeans-building.gif new file mode 100644 index 000000000..7ef8f4500 Binary files /dev/null and b/docs/devGuideDB/netbeans-building.gif differ diff --git a/docs/dist/doc/ant-ajc-task.html b/docs/dist/doc/ant-ajc-task.html new file mode 100644 index 000000000..602c48938 --- /dev/null +++ b/docs/dist/doc/ant-ajc-task.html @@ -0,0 +1,389 @@ + + + + + + + AjcTask Ant Support for AspectJ 1.1 + + + +

+AjcTask Ant Support for AspectJ 1.1

+ +

+Description

+ +This task uses the AspectJtm 1.1 compiler +ajc. + +The AspectJ compiler can be used like + Javac +to compile Java sources, but it can also compile AspectJ sources or +weave binary aspects with Java bytecode. It can run in normal "batch" mode +or in an "incremental" mode, where it only recompiles files it has to revisit. +For more information on ajc, see the links from +the AspectJ docs home. The main things to remember: + +This task is named iajc now to avoid conflict with the +1.0 task ajc, but the name may change to ajc in +the future. +

+See below for +an introduction to handling compiler messages programmatically. + +

+

+Parameters

+ +

Parameters supported by ajc

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
Specifying source and destination files
sourcerootsa list of base directories of the source files. +All source files (.java and .aj) in the base directories are compiled. + May also be specified as a nested element. +Yes, in incremental mode.
outjarPath to an output jar to generate with all output classes.No
destdirSpecify where to place the generated class files.No
classpaththe classpath required by the source files to compile. + May also be specified as a nested element. +No
srcdirthe nested source base directory to compile, + specified as a nested element. +No
aspectpaththe aspectpath to use -- like classpath, only for +read-only, binary aspect libraries (only accepts jar/zip files, no directories). +May also be specified as a nested element. +No
bootclasspathlocation of bootstrap class files.No
classpathrefthe classpath to use, given as a +reference to a PATH defined elsewhere.No
bootclasspathreflocation of bootstrap class files, given as a reference +to a PATH defined elsewhere.No
Specifying compiler behavior
noweaveIf true, produce binaries for the -injars option (only) -- +defaults to false.No
incrementalbuild once, then recompile on demand only required files; + defaults to false. + By default, files are recompiled based on input passed to stdin + (see tagfile)No
tagfileFile that controls when incremental builds are done + and when the task completes.No
XSet experimental option(s), using comma-separated list + of accepted options (unlisted here -- for XLint, use + the xlint entries). Options should not contain the leading X. No
Specifying compiler side-effects and messages
verbosewhether to emit compiler status messages during the compile; +defaults to false.No
versionif true, do not compile - just print AspectJ version; +defaults to false.No
helpif true, just print help for the command-line compiler; +defaults to false.No
Xlintenabledsame as xlint:all, +whether to emit language usage messages during the compile; +defaults to false.No
Xlintfilespecify property file containing name:level associations +for any overrides to the default associations for language usage +messaged emitted during the compile.No
failonerrorwhether the build continues notwithstanding compile errors; + defaults to trueNo
messageholderclassSpecify a class to use as the message holder for the compile +process. The entry must be a fully-qualified name of a class resolveable +from the task classpath complying with the org.aspectj.bridge.IMessageHolder +interface and having a public no-argument constructor.No
Eclipse compiler options
nowarnsame as warn:none; + defaults to falseNo
deprecationsame as warn:deprecation; + defaults to falseNo
warnone or more comma-separated warning specifications: +constructorName, +packageDefaultMethod, +deprecation, +maskedCatchBlocks, +unusedLocals, +unusedArguments, +unusedImports, +syntheticAccess, or +assertIdentifier.No
debugsame as debug:lines,vars,sourceNo
debuglevelcomma-separated list lines, vars, or source, + indicating to add debugging information for lines, + variables, or source No
PreserveAllLocalscode gen preserve all local variables (for debug purposes); + defaults to falseNo
noimporterrorno errors for unresolved imports; + defaults to falseNo
referenceinfocompute reference info; + defaults to falseNo
logFile to log compiler messages to.No
encodingdefault source encoding formatNo
proceedonerrorkeep compiling when error, dumping class files with problem methods; + defaults to falseNo
progressshow progress (requires log); + defaults to falseNo
timedisplay speed information; + defaults to falseNo
noexitdisable System.exit (kills Ant -- use failonerror); + defaults to trueNo
targetSpecify target class file format (must be "1.1" or "1.2"); + defaults to 1.1 class file. No
complianceSet "1.3" or "1.4" source compliance level + (e.g., no import from default package in 1.4); + defaults to 1.3 compliance level. No
sourcesource assertion mode ("1.3" or "1.4"); + default depends on compliance mode. No
+ + +

Nested Elements

+This taskdef should support nested elements as the old one did; +see taskdef-ajc10.html#nestedElements. + + +

Programmatically handling compiler messages

+ +Users may specify a message holder which is passed all +messages generated by the compiler synchronously. This overrides all of the normal +message printing, but does not prevent the task from failing if failonerror is true +and errors or exceptions were encountered. + +Handling messages programmatically could be useful +when using the compiler to inspect code. +If aspects consist of declare [error|warning], then +the compiler can act to detect invariants in the code being processed. +For code to compare expected and actual messages, see the AspectJ +testing module (which is not included in the binary distribution). + + +
+
+
+ + + diff --git a/docs/dist/doc/ant-ajc10-task.html b/docs/dist/doc/ant-ajc10-task.html new file mode 100644 index 000000000..03d4b3e88 --- /dev/null +++ b/docs/dist/doc/ant-ajc10-task.html @@ -0,0 +1,383 @@ + + + + + + + Ajc10 Ant Task + + + +

+Ajc10 Ant Task

+ +

+Description

+This task is provided for backwards compatibility with build scripts +created for the AspectJ 1.0 ajc task. Developers using only +AspectJ 1.1 should upgrade their scripts to use the newer task. +This task is deprecated and may not be supported in the future. +Options no longer supported in 1.1 are still accepted, but have +no effect, other than to be listed in a warning emitted by the task. +

+This task compiles using the AspectJtm compiler ajc; +you can use it in place of the + Javac task. + +The interface is like the Javac task interface, except it also accepts +parameters unique to ajc. +Of these, most no longer have any effect (nocomments, preprocess, workingdir, +maxmemory, jvmarg), but argfiles are still supported. (For more information +on argfiles, see below.) +

+ +

+Parameters

+ +

Parameters supported by ajc

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
srcdirthe base directory of the java files. (See note)Yes, unless you use argfile +or nested <src> elements. +
destdirSpecify where to place the generated class files.No
includescomma-separated list of patterns of files that must be included; +no +files are included when omitted.No
includesfilethe name of a file that contains include patterns.No
excludescomma-separated list of patterns of files that must be excluded; +no files (except default excludes) are excluded when omitted.No
excludesfilethe name of a file that contains exclude patterns.No
defaultexcludeswhether default excludes should be used (yes +| no); default excludes are used when omitted.No
classpaththe classpath to use.No
bootclasspathlocation of bootstrap class files.No
classpathrefthe classpath to use, given as a +reference to a PATH defined elsewhere.No
bootclasspathreflocation of bootstrap class files, given as a reference +to a PATH defined elsewhere.No
extdirslocation of installed extensions No
debugwhether debug information should be included in classes output; +defaults to false.No
deprecationwhether compiler should emit messages about +usage of deprecated API; defaults to false.No
verbosewhether to emit compiler status messages during the compiler; +defaults to false.No
versionprint ajc version and exitNo
failonerrorwhether the build continues notwithstanding compile errors; + defaults to trueNo
sourceValue of -source option - ignored unless "1.4"No
+ +

+Parameters that used to be ignored by +the ajc taskdef, but now are supported or cause failures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionSupport
encodingencoding of source files.Yes?
optimizewhether source should be compiled with optimizationYes?
targetgenerate class files for specific VM version (e.g., 1.1 +or 1.2).Yes
dependenables dependency-tracking No
includeAntRuntimewhether to include the Ant run-time librariesNo
includeJavaRuntimewhether to include the run-time libraries from the +executing VMNo
threadsMulti-threaded compilationNo
+ + +

+Parameters unique to ajc

+Note: Many of the unique parameters in AspectJ 1.0 are no longer supported, +and fork is not supported yet. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
Xcomma-delimited list of extended (-X...) options, + entered without -X + (e.g., X="lint" for + -Xlint). No
emacssymGenerate symbols for Emacs IDE support + (defaults to off)No
argfilesa comma-delimited list of argfiles that + contain a line-delimited list of source file paths + (absolute or relative to the argfile) No
+ + +

argfiles - Argument list files

+An argument file is a file (usually <file>.lst) containing a list of source file +paths (absolute or relative to the argfile). +You can use it to specify all source files to be compiled, which ajc requires +to avoid searching every possible source file in the source path when building aspects. +If you specify an argfile to the ajc task, it will not include all files in any specified +source directory (which is the default behavior for the Javac task when no includes are +specified). Conversely, if you specify excludes, they will be removed from the list of +files compiled even if they were specified in an argument file. + +
  + +

+Parameters specified as nested elements

+This task forms an implicit FileSet +and supports all attributes of <fileset> (dir becomes +srcdir) +as well as the nested +<include>, <exclude>, +<patternset>, +and <argfile> elements. +

+src, classpath, bootclasspath and extdirs

+ajc's srcdir, classpath, +bootclasspath, extdirs +and jvmarg attributes are path-like +structures and can also be set via nested +<src>, +<classpath>, +<bootclasspath>, +<extdirs> and <jvmarg> elements, respectively. +

+

+Examples

+ +See ../examples/builds.xml +for an example build script. +

+This build script snippet + +

  <ajc srcdir="${src}"
+       destdir="${build}"
+       argfiles="demo.lst"
+  />
+compiles all .java files specified in the demo.lst and +stores the .class files in the ${build} directory.  +Unlike the Javac task, the +includes attribute is empty by default, so only those +files specified in demo.lst are included. +

This next example +

  <ajc srcdir="${src}"
+       destdir="${build}"
+       includes="spacewar/*,coordination/*"
+       excludes="spacewar/Debug.java"
+  />
+compiles .java files under the ${src} directory in the +spacewar +and +coordination packages, and stores the +.class files in the +${build} directory.  All source files under +spacewar/ and +coordination/ are used, except Debug.java. + + +
+ + diff --git a/docs/dist/doc/ant-tasks.html b/docs/dist/doc/ant-tasks.html new file mode 100644 index 000000000..f09bbc7e5 --- /dev/null +++ b/docs/dist/doc/ant-tasks.html @@ -0,0 +1,230 @@ + + + +AspectJ Ant Tasks + + + + +

AspectJ Ant Tasks

+ +

Version @build.version.long@ released on @build.date@.

+ +

About the AspectJ Ant tasks

+ +AspectJ contains a compiler, ajc, that can be run from Ant. + +Included in the aspectjtools.jar are Ant binaries to support +three ways of running the compiler: +
    +
  1. Ajc10 (options), + a task to run build scripts compatible with the AspectJ 1.0 tasks,
  2. +
  3. AjcTask (options), + a task to run the new AspectJ 1.1 compiler, which supports + all the eclipse and ajc options, including incremental mode; +
  4. Ajc11CompilerAdapter, + an adapter class to run the new compiler using Javac tasks + by setting the build.compiler property.
  5. +
+ +This describes how to install and use the tasks and the adapter. +For an example Ant script, +see ../examples/build.xml. + +

Installation

+

Install Jakarta Ant 1.5.1:  + Please see the official + Jakarta + Ant website for more information and + the 1.5.1 + distribution. +This release is source-compatible with Ant 1.3 and Ant 1.4, but +the task sources must be +compiled with those versions of the Ant libraries to be used under those +versions of Ant. Sources are available under the Common Public License v. 1.0 +at @aspectj.home.url@. + +

In Ant, third-party tasks can be declared using a taskdef entry +in the build script, to identify the name and classes. + +When declaring a task, include the aspectjtools.jar +either in the taskdef classpath +or in ${ANT_HOME}/lib +where it will be added to the system class path by the ant script. + +You may specify the task script names directly, or use +the "resource" attribute to specify the default names: +

+  <taskdef 
+      resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
+
+The current resource file retains the name "ajc" for the Ajc10 task, +using "iajc" for the AspectJ 1.1 task. +This may change in the final release of AspectJ 1.1. +

+

For more information on using Ant, please refer to +Jakarta's documentation +on integrating user-defined Ant tasks into builds.

+

+ +

Ajc10 (script name: ajc)

+This task handles the same arguments as those used by the AspectJ 1.0 task. +This should permit those with existing build scripts using +the Ajc Ant task to continue using the same scripts +when compiling with 1.1. + +This will list any use of options no longer supported +(e.g., fork, lenient, strict, workingdir, preprocess, usejavac,...), +and does not provide access to the new features of AspectJ 1.1. +(Developers using AspectJ 1.1 only should +upgrade their scripts to use AjcTask instead.) +

+Following is a declaration for the ajc task and a sample invocation +that uses the ajc compiler to compile the files listed in +default.lst into the dest dir. +

+<project name="example" default="compile" >
+  <taskdef name="ajc"
+    classname="org.aspectj.tools.ant.taskdefs.Ajc10" >
+    <!-- declare classes needed to run the tasks and tools -->
+    <classpath>
+      <pathelement location="${home.dir}/tools/aspectj/lib/aspectjtools.jar"/>
+    </classpath>
+  </taskdef>
+
+  <target name="compile" >
+    <mkdir dir="dest" />
+    <ajc destdir="dest" argfiles="default.lst" >
+      <!-- declare classes needed to compile the target files -->
+      <classpath>
+        <pathelement location="${home.dir}/tools/aspectj/lib/aspectjrt.jar"/>
+      </classpath>
+    </ajc>
+  </target>
+</project>
+
+ +

AjcTask (script name: iajc)

+This task handles all the ajc 1.1 compiler options, +as well as an incremental "tag" file to avoid depending +on Ant input/output for controlling Ant-based incremenal compilation. + +

Below is an example of incrementally compiling src + and testsrc root source directories, using tagfile.txt + to control recompilation and halting. +When this script is run, the compiler will build once and +then wait for incremental builds, recompiling each time the +last-modified date changes on the tag file. When the tag file no longer +exists, the build will complete. Messages are printed as usual. +

+<project name="incremental-example" default="compile" >
+  <taskdef 
+      resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
+    <classpath>
+      <pathelement location="${home.dir}/tools/aspectj/lib/aspectjtools.jar"/>
+    </classpath>
+  </taskdef>
+
+  <target name="compile" >
+    <mkdir dir="dest" />
+    <inc-ajc destdir="dest" 
+            tagfile="tagfile.txt" 
+            sourceroots="src${path.separator}testsrc" >
+      <!-- declare classes needed to compile the target files -->
+      <classpath>
+        <pathelement location="${home.dir}/tools/aspectj/lib/aspectjrt.jar"/>
+      </classpath>
+    </inc-ajc>
+  </target>
+</project>
+
+ + +

Ajc11CompilerAdapter

+This CompilerAdapter can be used in javac tasks calls +by setting the build.compiler +property to the class name. This enables users to +to easily switch between Javac and the AspectJ compiler. + +To build this way, install aspectjtools.jar in ${ANT_HOME}/lib +and define the build.compiler +property as the fully-qualified name of the class: + +
+    cp aspectj1.1/lib/aspectjtools.jar ant/lib
+    ant/bin/ant -Dbuild.compiler=org.aspectj.tools.ant.taskdefs.Ajc11CompilerAdapter ...
+
+ +The AspectJ compiler should run for any compile using the Javac task +(for options, see the Ant documentation for the Javac task). + +

+To pass ajc-specific arguments, use a compilerarg entry. +For example, + +

+
+-- command
+
+  Ant -Dbuild.compiler=org.aspectj.tools.ant.taskdefs.Ajc11BuildCompiler
+
+-- build script
+
+  <property name="ajc" 
+              value="org.aspectj.tools.ant.taskdefs.Ajc11BuildCompiler"/>
+
+  <javac srcdir="src" destdir="dest" >
+    <compilerarg compiler="$${ajc}" line="-argfile src/args.lst"/>
+  <javac >
+
+ +Beware of using regular source lists with this; javac may prune unchanged +files, which excludes them from the compile process for ajc, which requires +that all files affected by any aspects be listed explicitly. + +
+ +

4. What to do if you encounter problems

+

If you have problems with the tasks not solved by the documentation, +please try to see if you have the same problems when running ajc +directly on the command line. +

+ +

  • If the problem occurs on the command line also, then the problem is +not in the task. +(It may be in the tools; please send bug reports, but only if the code +is pure-Java.)
  • + + +
  • If the problem does not occur on the command line, +then it may lie in the parameters you are supplying in Ant or in +the task's handling of them.
  • + +
  • If the build script looks correct and the problem only occurs when building +from Ant, then please send a report (including your build file, if possible).
  • + +

    Known Problems +
    For the most up-to-date information on known problems, see the + bug database for + compiler bugs + or task bugs. + +

  • Memory and forking: +Users email most often about the ajc task running out of memory. This is +not a problem with the task; some compiles take a lot of memory, +often more than the same compiles using javac. +Forking is not supported in this release, so the only solution is to +increase the memory available to Ant (see the Ant documentation, searching for ANT_OPTS, +the variable they use in their scripts to pass VM options, e.g., ANT_OPTS=-Xmx128m). +
  • +
  • Messages suppressed: In the incremental task, +messages from the compiler are printed but not segregated. +
  • + +

    +You can send email to users@aspectj.org. +(Do join the list to participate!) We also welcome any bug reports; you can +submit them to @aspectj.home.url@/bugs. + + + diff --git a/docs/dist/doc/changes.html b/docs/dist/doc/changes.html new file mode 100644 index 000000000..0d4d304fd --- /dev/null +++ b/docs/dist/doc/changes.html @@ -0,0 +1,1502 @@ + + + + + +AspectJ 1.0.6 Reference -- Recent Changes + + + + +

    +© Copyright 1998-2002 Palo Alto Research Center Incorporated. All rights reserved. +
    + +

    Recent Changes in AspectJ 1.0

    + + + +
    + +

    1.0.6

    + +

    This release contains mainly bug fixes for ajde and ajdoc. + +

    Compiler

    + +

    We fixed a bug with switch statements, thanks largely +to Jason Rimmer's diligence in helping us isolate the problem. +Also, to help Log4J parse stack traces, we changed class file +symbolic line references to use [] instead of () for the +virtual start lines of each file. +

    + +

    AJDE

    + +

    AJDE Framework, AJBrowser, and AJDE for Forte/NetBeans

    + +

    The memory use of the structure model has been streamlined in order to reduce +footprint when working with large systems.  Error tolerance has also been +improved for dealing with a structure model that is out of synch with resources +on disk.

    + +

    AJDE for JBuilder

    + +

    JBuilder 7 is now supported.  All known bugs have been fixed including:

    + + + +

    In addition, thanks to user feedback that indicated trouble building JBuilder +OpenTools with AJDE/JBuilder, the OpenTool is now being built with itself.

    + +

    Ajdoc

    + + +
    + +

    1.0.5

    + + +

    This release includes significant improvements to AspectJ Development +Environment (AJDE) support. The entire user interface has been revised and +streamlined. The AJDE features are more tightly integrated into JBuilder and +NetBeans/Forte support. JBuilder support now includes graphical configuration +file editing and an integrated AspectJ Browser tool.

    + + + +

    Compiler

    + +

    This was another compiler release primarily concerned with fixing +corner cases in the language implementation. Our handling of nested +classes, the assert statement, and cflow were the principal offenders +this time. Thanks to Nicholas Alex Leidenfrost and Patrick Chan for +their clear and concise bug reports on some of these issues.

    + +

    AJDE

    + +

    This release includes significant +improvements to AspectJ Development Environment (AJDE) support. All known bugs +have been fixed, and the core framework quality has been significantly increased +thanks to the adoption of a unit test suite. The following changes apply +to all of the AJDE NetBeans/Forte, JBuilder, and the AspectJ Browser support. +NetBeans/Forte and JBuilder-specific changes are listed below.

    + + + + +

    AJDE for JBuilder

    + + +

    Integration into the JBuilder IDE is more streamlined. In addition:

    + + + + + +

    AJDE for Forte/NetBeans

    + + +

    Integration into the NetBeans IDE is more streamlined. In addition:

    + + + + + +

    AJBrowser

    + + + + + +

    Ajdoc

    +

    Bug fixes: +

    + + +

    Ant tasks

    +

    Bug fixes: +

    + + +
    + +

    1.0.4

    + + + +

    Compiler

    + + +

    Incompatible changes

    + +

    Two potentially surprising incompatible changes have been made to +ajc in order to bring the compiler into compliance with the 1.0 +language design. These changes will be signalled by clear warning or +error messages at compile-time and will not cause any run-time +surprises. We expect most users to never notice these changes.

    + + + +

    AJDE

    + + +

    This is the first release of AJDE support with significant external +contribution. A big thanks goes out to Phil Sager for porting the AJDE for +Forte/NetBeans support to NetBeans 3.3.1 and improving the integration into +NetBeans.

    + + +

    AJDE for JBuilder

    + + + +

    AJDE for Forte/NetBeans

    + + + +

    AJDE for Emacs

    + + + + + +

    Ajdoc

    +

    Ajdoc now runs under J2SE 1.4, but still requires the tools.jar + from J2SE 1.3 be on the classpath. +

    + +

    Ant tasks

    + +

    Documentation

    +

    Added a 1-page quick reference guide. Improved javadoc documentation for + the org.aspectj.lang package. +

    + + +
    + +

    1.0.3

    + + + +

    Compiler

    +

    This release fixes a single significant bug in 1.0.2 where ajc +could generate unreachable code in -usejavac or +-preprocess mode. This would happen when around advice +was placed on void methods whose body consisted solely of a +while (true) {} loop. We now properly handle the +flow-analysis for this case and generate code that is acceptable to +javac. Thanks to Rich Price for reporting this bug. +

    + +

    Ant taskdefs

    +

    Added support to the Ajc taskdef for the -source 1.4 and -X options generally. +

    + +
    + +

    1.0.2

    + +

    This release is mainly about keeping up with the Joneses. To keep +up with SUN's release candidate for J2SE1.4, we now officially support +the new 1.4 assertions and running on the 1.4 VM. In honor of the +public review of JSR-45 Debugging Support for Other Languages we +implement this spec for AspectJ. We support Borland's recent release +of JBuilder 6, and since some of our users are starting to work on Mac +OSX, AJDE now works nicely on this platform. We also fixed almost all of +the bugs you reported in 1.0.1. +

    + + + +

    Compiler

    + + + +

    AJDE

    + +

    This is a bug fix release only.

    + + + +

    AJDE for JBuilder

    + + + + + +

    AJDE for Forte

    + + + + +

    AJDB

    + +

    Some minor bug fixes, but this is still early-access software. + Please try using another JPDA-compliant debugger. If it uses + JDI correctly, then it should navigate to line numbers + when the classes are run under J2SE1.4, based on + the new JSR-45 debugging support described above. + We would appreciate any reports of success or failure. +

    + +
    + +

    1.0.1

    + + + +

    Compiler

    + +

    This release fixes a significant performance issue in the +compiler, reported by Rich Price, that could lead to extremely long +compiles in systems with many aspects and classes. Several other +small bugs related to reporting compilation errors have also been +fixed, see this +bug report for an example. +

    + +

    A new experimental flag has been added, +-XaddSafePrefix, that will cause the prefix +aspectj$ to be inserted in front of all methods generated +by ajc. This mode should be helpful when using aspectj with tools +that do reflection based on method names, such as EJB tools. Thanks +to Vincent Massol for pointing out the importance of this. It is +expected that this prefix will either become the default compiler +behavior in the future or a non-experimental flag will replace it. +

    + + +

    AJDE

    + +

    Minor bug fixes, including: AJDE for JBuilder failed to preserve +application parameters from project settings when executing the application.

    + +

    Source builds were cleaned up for JBuilder and Forte sources.

    + +

    AJDB

    + +

    Two bugs were reported and have been fixed in this release. + (Note that ajdb is still considered early-access software.)

    + + + +

    1.0.0

    + + + +

    Language

    + +

    There were no language changes for this release.

    + +

    Compiler

    + +

    Several minor bugs primarily in error handling were reported and +have been fixed in this release. The two most serious bugs are +described below:

    + + + +

    AJDE

    + +

    Numerous user interface refinements were made to the browser and +core AJDE functionality. Error handling and reporting has been improved. +All of the AJDE tools now support the ".aj" file extension.

    + +

    AJDE for JBuilder

    + + + + + +

    AJDE for Forte

    + + + + + +

    AJBrowser

    + + + + + +

    Emacs Support: aspectj-mode and AJDEE

    + + + +

    AJDoc

    + + + +

    Ant taskdefs

    + + +

    1.0rc3

    + +

    Language

    + +

    There have been several minor clarifications/changes to the +language.

    + + + +

    Compiler

    + +

    This release saw several changes to the compiler in order to +work-around known bugs in different JVMs, or to otherwise mimic the +behavior of javac rather than necessarily following the Java Language +Specification.

    + + + +

    AJDE

    + + + +

    AJDE for JBuilder

    + + + + + +

    AJDE for Forte

    + + + + + +

    AJBrowser

    + + + + + +

    Emacs Support: aspectj-mode and AJDEE

    + + + +

    AJDoc

    + +

    Some of the more obvious NullPointerException bugs in Ajdoc were fixed, but +Ajdoc does not implement all the functionality of Javadoc and has some bugs:

    + +

    Further, Ajdoc has not been testing on variants of the J2SE (it uses javadoc classes). + +

    Ant taskdefs

    +

    The Ajc taskdef was updated to support the new compiler options and the .aj extension, +and some NullPointerException bugs were fixed (thanks to Vincent Massol for a bug +report listing the line number of the fix). The AJDoc cannot be run repeatedly +in a single Ant run, and has trouble loading the doclet unless the libraries +are installed in ${ant.home}/lib. +

    +


    +

    1.0rc2

    + + + +

    Language

    + +

    There are no language changes in this release. This is a bug fix release +only.

    + +

    Compiler

    + +

    A bug in handling inner type names that conflict with enclosing +type names was fixed. Many error messages were improved.

    + +

    AJDE

    + + + +

    AJDE for JBuilder

    + + + +

    AJDE for Forte

    + + + +

    AJBrowser

    + + + +

    Emacs Support: aspectj-mode and AJDEE

    + +

    This release now properly displays annotations for call sites and + introductions. Robustness has been improved in several dimensions, + including performance at startup. The compile menu now recomputes + properly when changing directories.

    + +
    + +

    1.0rc1

    + + + +

    Language

    + +

    Some of the details of the specification for perthis and pertarget +have changed. These changes make these language constructs +implementable on current JVMs without memory leaks (this wasn't true +of the previous version). Most people will probably not notice these +changes, but the correct semantics are described in +the semantics section of the programming +guide. +

    + +

    In a related change, aspects are not allowed to implement either +the java.io.Serializable or the +java.lang.Cloneable interface. It is unclear what the +correct behavior of a system should be when an aspect is serialized or +cloned, and rather than make an arbitrary choice right now we've +chosen to leave the most room to design them right in a future +release.

    + +

    Compiler

    + +

    ajc now directly generates .class files without using javac as a +back-end. This should result in improved compiler performance, better +error messages and better stack-traces and debugging info in those +.class files. -preprocess mode is still available for those who want +to generate legal Java source code and a new -usejavac mode is +available if you have a requirement to continue to use javac as a +back-end.

    + +

    ajc now officially supports source files with the .aj extension. +We plan to extend this support to the rest of our tools as time +permits. +

    + +

    This release of ajc includes support for the "-source 1.4" option +that enables the new 'assert' keyword in jdk1.4. This option only +works correctly when compiling against the jdk1.4 libraries. In +addition, this release of ajc will run under SUN's jdk1.4beta2. +However, we still strongly recommend that most users use the non-beta +jdk1.3.

    + +

    AJDE

    + + + +

    AJDE for JBuilder

    + + + +

    AJDE for Forte

    + + + +

    AJBrowser

    + + + +

    Aspectj-mode and AJDEE: AspectJ support in Emacs

    + +

    This release of AspectJ support for Emacs includes corrections to the +documentation and the appearance of annotations and jumps in the editing +view. Also, advice are now shown on non-declarations, when appropriate, +such as call advice. The internal event model has been revised to reduce +computational overhead.

    + +
    + +

    1.0beta1

    + + + +

    Language

    + +

    There is one language change since 1.0alpha1. The static modifier is +no longer needed or allowed on pointcut declarations. Name binding +for pointcut declarations works like class methods now. Thanks to +Robin Green for encouraging us to look at this one last time.

    + +

    The current implementation of perthis/pertarget has the possibility of +memory leaks (thanks to Arno Schmidmeier for pointing this out). The +design of this part of the language will almost certainly see some +changes in the next release to address issues of implementability on +the JVM as well as related issues.

    + +

    Compiler

    + +

    The ajc compiler should now catch all errors in source code and you +should no longer see errors coming from files in 'ajworkingdir'. +Please report any errors in 'ajworkingdir' as bugs.

    + +

    All reported bugs in 1.0alpha1 have been fixed. Thanks to everyone +for your bug reports. Most notably, the 'if' pcd that was added in +1.0alpha1 should work correctly in this release. Thanks to Morgan +Deters for a very thorough bug report on this broken feature days +after the 1.0alpha1 release.

    + +

    AJBrowser

    + + + +

    AJDE

    + + + +

    AJDE for JBuilder

    + + + +

    AJDE for Forte

    + + + +

    Aspectj-mode and AJDEE: AspectJ support in Emacs

    + +

    AspectJ Development Environment for Emacs has been split into two pieces, +aspectj-mode (an extension of java-mode), and AJDEE (an extension of JDE). +Additionally, a switch, -emacssym, has been added to ajc that generates +AspectJ declarations information directly, thus beanshell is no longer +required for use of these modes. +

    + +
    + +

    1.0alpha1

    + +

    This is the first alpha release of the 1.0 language and tools. +There have been many changes in the language, and many improvements to +the tools. We wish to thank our users for putting up with the high +volatility of AspectJ in the push to 1.0.

    + + + +

    Language

    + +

    There have been many changes to make the 1.0 language both simpler +and more powerful. User feedback has driven most of these design +changes. Each email we've received either making a suggestion or just +asking a question about a confusing part of the language has played a +part in shaping this design. We'd like to thank all of our users for +their contributions. + +

    While we don't have room to thank all of our users by name, we'd +like to specifically mention a few people for their high-quality +sustained contributions to the users@aspectj.org mailing list as well +as through their feature requests and bug reports. Robin Green +(who'll be very happy to see declare error), Stefan +Hanenberg (who should appreciate the '+' wildcard in type patterns), +and Rich Price (who suggested final pointcuts, more flexible +dominates, and many other improvements).

    + +

    Note that entries into the porting +notes for this release are linked from the various language +changes.

    + +

    Pointcuts

    + +

    Perhaps the least interesting -- but most pervasive -- change is +that the names of the single-kinded pointcut designators (the ones +that pick out only one kind of join point)

    + +
    calls executions gets sets handlers initializations +staticinitializations
    + +

    have been +changed to be +singular rather than plural nouns

    + +
    call execution get set handler initialization +staticinitialization
    + +

    Although a side benefit is that the names are one character +shorter, the real benefit is that their combination with the +&& and || operators now reads much +more naturally. No longer does "and" mean "or" and "or" mean "and". +

    + +

    You'll notice that receptions doesn't appear on the +table as being shortened to reception. That's because +call and reception join points have been merged, and the +receptions pointcut declaration has been +eliminated. Now, +call join points describe the action of making a call, +including both the caller and callee. Eliminating reception join +points makes AspectJ much simpler to understand (reception join points +were a commonly misunderstood feature) without giving up expressive +power.

    + +

    We have changed +the mechanism for accessing state at join points, which has the +benefit of making our treatment of signatures +cleaner and easier to +read. As a part of this, the instanceof pointcut +designator has now been +split into two +different pointcut designators, this and +target, corresponding to a join point's currently +executing object and target object, respectively.

    + +

    The new args pointcut adds expressive power to the +language by allowing you to capture join points based on the actual +type of an argument, rather than the declared type of its formal. So +even though the HashSet.removeAll method takes a +Collection as an argument, you can write advice that only +runs when it is actually passed a HashSet object.

    + +

    AspectJ's notion of object construction and initialization, a +complicated process in Java, has been clarified. This affects some +uses of the +initializations +pointcut and +constructor calls +pointcut.

    + +

    The little-used pointcuts +hasaspect and +withinall have +been removed.

    + +

    The returns keyword is +no longer +necessary for user-defined pointcuts.

    + +

    Pointcuts may now be declared static, and +only static +pointcuts may be declared in classes and referred to with +qualified references (such as MyAspect.move()).

    + +

    Non-abstract pointcuts may now be declared final. +

    + +

    We have finally added an extremely general pointcut, +if(BooleanExpression), that picks out +join points programatically.

    + + +

    Type patterns

    + +

    Our treatment of +* and .. in type +patterns is cleaner.

    + +

    Type patterns now have the ability to include array types, and +there is a new wildcard, +, to pick out all subtypes of a given type. +Previously, the subtypes operator was only allowed in introduction, +and was spelled +differently.

    + +

    Advice

    + +

    Around advice is treated much more like a method, with a +return value and an +optional throws clause. +

    + +

    The advice precedence rules have been +changed. Now, for +example, a piece of after advice that appears lexically later than +another piece of after advice will run later, as well. Previously, +the relationship was the other way around, which caused no small +amount of confusion.

    + +

    After returning advice has lost a +useless set of +parentheses when not using the return value.

    + +

    The thisStaticJoinPoint reflective object has been +renamed, and +the thisJoinPoint object hierarchy has been +simplified.

    + +

    Introduction and static crosscutting

    + +

    On the static side of the language, introduction hasn't changed, +but there is now a new keyword, declare, that is used to +declare various statically-crosscutting properties. One of these +properties is subtyping, so we've +gotten rid of +the ugly keywords +implements and ++extends.

    + +

    We have provided two new forms, declare error and +declare warning, for the often-asked-for property of +compile-time error detection based on crosscutting properties.

    + +

    AspectJ's interaction with checked exceptions is now firmly on the +side of static crosscutting, since Java treats such exceptions at +compile-time. A new form, declare soft, can be used to +"soften" checked exceptions into an unchecked form. This may affect +some uses of around +advice that previously mucked with the exception checking +system.

    + +

    Aspects

    + +

    The "of each" modifiers have been +renamed. Apart from the +spelling, the main interesting difference is the splitting up of +of eachobject into two different modifiers, parallel with +the split of instanceof into this and +target.

    + +

    The dominates keyword now takes a type pattern, +rather than a type. This allows an aspect A, for example, to declare +that its advice should dominate the advice of another aspect B as well +as its subtypes, with the new + subtypes operator: aspect A +dominates B+. +

    + +

    Compiler

    + +

    The most important change in the compiler is that it supports the +new language. In addition, all reported bugs in the last release have +been fixed. Thanks for your bug reports.

    + +

    The compiler also gets a new -encoding flag in this +release for handling source files that are not in standard US-ASCII +format. Thanks to Nakamura Tadashi for both suggesting this feature +and for submitting a nice patch to implement it. + +

    Known Limitations

    + +

    The previous compiler's limitations regarding join points that +occurred in anonymous classes have all been eliminated. +Unfortunately, eliminating this restriction has resulted in +preprocessed source code that is less readable than in previous +releases. More care will be taken in the next release to mitigate +this effect.

    + +

    Many semantic errors are not caught by ajc but fall through to +javac. Moreover, some errors regarding the initialization of final +fields might never show up when using ajc. This will be fixed +shortly.

    + + +

    Documentation

    + +

    Although we spent much of our time this release cycle updating the +documentation to the new language rather than improving its content, +we did make some structural improvements. The old Primer has been +split into a Programming Guide, covering the language, and a +Development Environment Guide, covering the develompent tools. In +addition, printable versions of both guides (in PDF) are finally +included in the documentation package.

    + +

    Ajdoc

    + +

    Ajdoc was rewritten to conform with the language changes and provide support +for other AspectJ/Java compilers. Our doclet is used by default creating +AspectJ-specific documentation, or Sun's standard doclet can be used by +passing the '-standard' flag to Ajdoc to produce regular Javadoc documentation +(excluding AspectJ-specifics). +

    + +

    Ant

    + +

    An Ajdoc task is now available. The Ajc ant task was improved to +be completely back-compatible with the Javac task.

    + +

    AJBrowser

    + +

    The "AspectJ Browser" is a new standalone source code browsing application. +It will let you compile ".lst" files, view the structure for those files and +navigate the corresponding source code.

    + +

    AJDE

    + +

    AJDE for JBuilder

    + +
    Installation
    + + +
    Key Improvements
    + + + +
    Known Bugs & Limitations
    + + + + +

    AJDE for Forte

    + + +
    Installation
    + + + +
    Key Improvements
    + + + +
    Known Bugs & Limitations
    + + + +

    AJDE for Emacs

    + +

    AspectJ-mode now includes a toggle in the AspectJ menu that +disables its intrusive functions, enabling easy switching between Java +and AspectJ projects. See the README and CHANGES files in the +distribution for additional details.

    + +

    AJDEE is now compatible with JDEE 2.2.7.1, JDEE 2.2.8beta4, and speedbar +0.14alpha. It a toggle in the AspectJ menu that disables its intrusive +functions, enabling easy switching between Java and AspectJ projects. See +the README and CHANGES files in the distribution for additional details. +

    + + +
    + +

    Previous Versions

    + +

    Changefiles for previous versions can be found in +doc/oldversions in the documentation distribution. +

    + + + + diff --git a/docs/dist/doc/index.html b/docs/dist/doc/index.html new file mode 100644 index 000000000..b3977f439 --- /dev/null +++ b/docs/dist/doc/index.html @@ -0,0 +1,329 @@ + + + + +AspectJ Documentation and Resources + + + +

    AspectJ Documentation and Resources

    +

    + AspectJ tm + is a seamless aspect-oriented extension to + Javatm. + The compiler and development tools are available under + an open-source license, require Java 2 to run, and produce + code that runs in JDK 1.1 and later VM's. + For the latest materials, see + @aspectj.home.url@, + especially the FAQ. +

    + + + +
    SectionContents
    docs + FAQ, + Quick Reference, + programming and + development guides, + API and + + (local) + + examples +
    distributions + compiler, AJDE, docs, and Ant taskdefs + (binary + - source) +
    resources + aosd.net; + aspectj.org + bug db and + email, + mail lists for + users and + support +
    paths for those new to AspectJ +
    +

    + + +

    AspectJ documentation

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DocumentationDescription
    AspectJ Quick Reference + + (web) + + This is a two-page quick reference for the AspectJ language. +
    Programming Guide + (printable pdf or html + + - web + + ) + This introduces AOP and the AspectJ language. + Getting Started + describes basic semantics, and shows development- and production-time applications. + The AspectJ Language + describes join points, pointcuts, advice, and introduction, all features new to AOP. + Examples walks you through the + examples included with the documentation, and there are two short + chapters on useful Idioms and a + few Pitfalls + The appendices have reference information: + the Quick Reference + summarizes AspectJ syntax, + the Language Semantics + best describes AspectJ usage, and + Implementation Limitations notes that + the current version is limited to code the compiler controls.
    Development Environment Guide
    + + (printable html + + - web + + ) +
    Find here a guide to the command-line compiler ajc + and API doc tool ajdoc, as well as + the AspectJ Development Environment (AJDE) for managing crosscutting + structure in JBuilder, Forte, Emacs, and the stand-alone ajbrowser. + (For using ajc and ajdoc in + Ant builds, + see the taskdefs distribution.) +
    AspectJ API + + (web) + + API documentation for AspectJ runtime classes. JoinPoint + shows the state automatically available at each join point. +
    FAQ + + (web) + + Frequently-asked questions about the AspectJ language, tools, and project. +
    Porting guide + + (web) + + How users can convert code from pre-1.0 versions + of AspectJ to 1.0. +
    Changes + + (web) + + Changes between the latest releases. +
    Examples + + (local) + + AspectJ code to demonstrate some language features and implement + JavaBean properties, the Observer pattern, a tracing library, + and a game application where aspects handle display updating. +
    + + +

    AspectJ distributions

    + + + + + + + + + + + + + + + + + + + + + + +
    DistributionsDescription
    AspectJ + The AspectJ distribution contains binaries for the + compiler, structure browser, and Ant taskdefs, + as well as the documentation and examples. + (Source code for AspectJ is available from the CVS + repositories for the AspectJ project.) +
    AspectJ for Eclipse + AspectJ Development Environment support for + Eclipse is available under the Common Public License 1.0 + from the eclipse.org project site + + http://eclipse.org/ajdt +
    + AspectJ for Emacs + AspectJ Development Environment support for + Emacs is available under the GPL + from the sourceforge project site + + http://aspectj4emacs.sourceforge.net +
    + AspectJ for JBuilder + AspectJ Development Environment support for + JBuilder is available under the Mozilla Public License 1.1 + from the sourceforge project site + + http://aspectj4jbuildr.sourceforge.net +
    + AspectJ for Netbeans + AspectJ Development Environment support for + Netbeans is available under the Mozilla Public License 1.1 + from the sourceforge project site + + http://aspectj4netbean.sourceforge.net +
    + + +

    Other AspectJ resources

    + + + + + + + + + + + + + + + + + +
    ResourcesDescription
    + user + email + list + Developers use the + users@aspectj.org + mail list to discuss tips and + best practices for developing with AspectJ. +
    + announce + email + list + + announce@aspectj.org + has notices about releases and AspectJ team events. +
    + email us + + Email support@aspectj.org + to contact the AspectJ team directly. + (As a small team, we cannot reply as fast as + users + can for usage questions.) +
    Bug + DB + and email + Please send AspectJ bugs! (as a small program + that reproduces the problem) +
    http://aosd.net - the AOSD web site + This site has discussion and announcements related to + aspect-oriented software development (AOSD) in general. + Use announce@aosd.net + to get and publish notices about AOSD + workshops, conferences, and technology releases. + Use discuss@aosd.net + for general AOSD discussions. +
    + +

    + +

    Suggested paths for those new to AspectJ

    +

    + To learn the AspectJ language, read the + Programming Guide, + keeping the Semantics appendix + nearby as the best reference for AspectJ usage. + Focus initially on the join point model and + pointcuts, concepts AOP adds to OOP. + To see how the code works, tour your + + local + + examples as described in the + Examples section of the + Programming Guide. + View and navigate the crosscutting structure using + the ajbrowser structure viewer, as described in + the ajbrowser section of + the Development Environment Guide. +

    + To start using AspectJ with your own code, + modify the example aspects to apply to your classes. + The Development Environment Guide + shows how to build using the command-line tools. + As you learn, + use the compiler's -Xlint flag to catch some common + mistakes. (Understand that the + current implementation + is limited to code the compiler controls.) +

    + To plan how to adopt AspectJ into a project, read the + Programming Guide + on development- and production-time aspects + and the FAQ entries for + How should I start using AspectJ?, + Deciding to adopt AspectJ, + the Development tools sections + (one, + two), + AspectJ as open-source and + available support and consulting. +

    +

    + Otherwise, see + the FAQ, + view or + email the + AspectJ users list, and enjoy the language! +

    +

    +The AspectJ Team +

    + +
    + +Top + + diff --git a/docs/dist/doc/porting.html b/docs/dist/doc/porting.html new file mode 100644 index 000000000..0a4d558a3 --- /dev/null +++ b/docs/dist/doc/porting.html @@ -0,0 +1,1785 @@ + + + + + +AspectJ 1.0.6 Reference - Porting Notes + + + + +
    +© Copyright 1998-2002 Palo Alto Research Center Incorporated. All rights reserved. +
    + +

    Porting Notes

    + + + +

    Porting pre-1.0.4 code

    + +

    In versions of AspectJ prior to 1.0.4, the compiler was not +correctly implementing the AspectJ-1.0 language design for some uses +of after returning advice. +

    + +

    The main change that was made was of after returning advice for +constructor execution join points. Previously, this advice was legal: +

    + +
    +after() returning (Foo f): execution(Foo.new(..)) { ... }
    +
    + +

    However, it has always been a part of the 1.0 language design (and +of Java's language design) that constructors themselves (as opposed to +constructor calls) do not return the value of the new object. Rather, +this is bound to the new object, and the constructor +behaves like a void method. With that in mind, any code like the +above should be conveted to the form.

    + +
    +after(Foo f) returning: this(f) && execution(Foo.new(..)) { ... }
    +
    + +

    In compilers prior to 1.0.4, the following advice could pick out +join points +

    + +
    +after() returning (String s): call(void foo()) { ... }
    +
    + +

    This is no longer picked out. This pattern was most commonly used +in highly polymorphic contexts, such as +

    + +
    +after() returning (String s): call(* foo()) { ... }
    +
    + +

    If you want to capture all calls, binding null objects for those +that would otherwise have no value, you must use the +Object type. +

    + +
    +after() returning (Object o): call(* foo()) { ... }
    +
    + +

    Uses of both of these forms are highleted with compiler warnings +in the 1.0.4 compiler. +

    + + +
    + +

    Porting pre-1.0rc1 code

    + +

    Aspects can no longer be declared to implement the +Serializable or Cloneable interfaces. If +you previously used serializable or cloneable aspects, you should +refactor your code to keep the state you need to serialize or clone in +objects associated with the aspects. +

    + +
    + +

    Porting pre-1.0beta1 code

    + +

    The static modifier is no longer allowed on pointcut +declarations anywhere. Porting is simple; just remove the static +declarations when you find them. +

    + +

    Also, though the returns modifier on pointcuts has +not been part of the language since 1.0alpha1, the compiler still +accepted them until now. If you used this feature, now is the right +time to remove the returns modifier when the compiler +complains about it. +

    + +
    + +

    Porting pre-1.0alpha1 code

    + + +

    The release of AspectJ 1.0alpha1 involved sweeping cleanups of the +language to bring it to 1.0 status.

    + + + +

    Pointcuts

    + +

    Removing the "s" from pointcuts

    + +

    One of the most pervasive changes in porting code written before +1.0alpha1 is the change in some of the pointcut names from plural to +singular, that is, they lose an "s". In one sense, making this change +in your programs is easy: just go through and whever you see uses of +the pointcuts +

    + +
    calls executions gets sets handlers initializations +staticinitializations
    + +

    Just take off the final "s", to make one of +

    + +
    call execution get set handler initialization +staticinitialization
    + +

    Often, there will be other changes you should make for each of +these pointcuts, but as for the name, just take off the "s".

    + +

    One risk you will have when doing this is creating name conflicts. +If, for example, you named a parameter of a pointcut "set", you should +(for your own sanity -- the compiler doesn't require it) rename it in +the rewritten pointcut.

    + +
    +pointcut sort(Collection set): calls(void addAll(set));
    +==>
    +pointcut sort(Collection mySet): call(void addAll(mySet));
    +
    + +

    While converting to use singular nouns for the primitive +pointcuts, you may also want to remove the "s" from your user-defined +pointcuts.

    + +
    +pointcut publicCalls(): calls(public * *(..));
    +==>
    +pointcut publicCall(): call(public * *(..));
    +
    + +

    Of course, your naming conventions are your own, but throughout +these porting notes we will be making these changes in our example +ports.

    + + +

    Removing the receptions pointcut

    + +

    Perhaps the largest semantic change in the 1.0 language is the +removal of receptions join points. They have been merged with call +join points in AspectJ 1.0, so now a call join point doesn't represent +the "caller-side" of a call, but the call itself, both caller and +receiver.

    + +

    Changing code that used the receptions pointcut should be +fairly straightforward, depending on whether the pointcut exposed state or +not.

    + +
    Not exposing state
    + +

    Receptions pointcuts that did not expose state can simply be +replaced by the new call and target pointcuts:

    + +
    +receptions(void Foo.m())
    +==>
    +target(Foo) && call(void m())
    +
    + +
    Exposing state
    + +

    Some receptions pointcuts exposed the receiving object by +replacing the receiving type with a pointcut formal. These PCDs +should be rewritten to use the new target pointcut to expose +the receiving object.

    + +
    +pointcut fooCallees(Foo f): receptions(void f.m());
    +==>
    +pointcut fooCallee(Foo f): target(f) && call(void m());
    +
    + +

    Like other pointcuts, +receptions pointcuts that exposed one or more arguments should be +rewritten to use the args pointcut:

    + +
    +pointcut intPassers(int i, int j): receptions(void Foo.m(i, j));
    +==> 
    +pointcut intPasser(int i, int j):
    +    args(i, j) && target(Foo) && call(void m(int, int));
    +
    + +
    Constructor receptions
    + +

    There are two issues with constructor receptions in +particular.

    + +

    Like constructor calls, +constructor receptions pointcuts had a dynamic character, in that +receptions(C.new()) would capture constructions of not +only C classes, but also of classes that extended C.

    + +

    If you want this behaviour, then you need to use the new subtypes +operator, +, on the type name in question. So, +

    + +
    +receptions(C.new())  
    +==>
    +call(C+.new())
    +
    + +

    Also like constructor calls, +constructor receptions allowed access to the constructed object in the +same way as any other object. Since the only advice possible on +constructor receptions join points was after returning +advice, the object was always guaranteed to be there. But since +constructor call join points allow all kinds of advice it may be that +the object isn't constructed yet (say, in before or around advice). +This is a benefit, in that it allows caching constructed objects

    + +
    +aspect Singleton {
    +    private C theC = null;
    +
    +    C around(): call(C.new(..)) {
    +        if (c == null) theC = proceed();
    +        return theC;
    +    }
    +}
    +
    + +

    but it does require some rewriting. The new object can be +accessed as the return value in after returning advice. So,

    + +
    +after(Point p) returning (): receptions(p.new(int, int)) { ... }
    +==>
    +after() returning (Point p): call(Point+.new(int, int)) { ... }
    +
    + +

    Fixing state access

    + +

    In previous versions of AspectJ, state such as the currently +executing object or a particular argument of a method call could be +accessed from the signatures of many pointcuts, leading to +difficult-to-read forms. In AspectJ 1.0, all state accesses now use +only three pointcuts

    + +
    args this target
    + +

    which pick out argument values, the currently executing object, +and the target object of a method call or field operation, +respectively.

    + +
    Using args
    + +

    Any time you have a pointcut that has a signature where one of the +arguments was a pointcut or advice formal, just replace that formal +with its type and add an args pointcut. +

    + +
    +pointcut intPassers(int i, int j): calls(void Foo.m(i, j));
    +==>
    +pointcut intPasser(int i, int j): args(i, j) && call(void Foo.m(int, int));
    +
    + +
    +pointcut stringPassers(String s): receptions(void Foo.m(s, ..));
    +==>
    +pointcut stringPasser(String s): args(s, ..) && call(void Foo.m(String, ..));
    +
    + +
    Rewriting calls
    + +

    If a calls pointcut exposed the the receiving object, such as

    + +
    +pointcut fooCallees(Foo f): calls(void f.m());
    +
    + +

    then the new version should use the target pointcut +to get at that object +

    + +
    +pointcut fooCallee(Foo f): target(f) && call(void Foo.m());
    +
    + +

    AspectJ's calls pointcut previously allowed the new object to be +exposed, even though it may not have been constructed yet. AspectJ +1.0 no longer allows this; you can access the new instance only in +after returning advice, when it is guaranteed that the object was +successfully constructed. So instead of using the target +pointcut to expose the value, you should use the normal after +returning mechanism: +

    + +
    +after(Point p) returning (): calls(p.new(int, int)) { ... }
    +==>
    +after() returning (Point p): call(Point+.new(int, int)) { ... }
    +
    + + +
    Rewriting gets and sets
    + +

    Exposing the target object of a gets or +sets pointcut should be done the same way it was for +calls pointcuts, with the new target +pointcut.

    + +
    +before(Frame f): gets(Color f.color) { ... }
    +==>
    +before(Frame f): target(f) && get(Color Frame.color) { ... }
    +
    + +
    +before(Frame f): sets(Color f.color) { ... }
    +==>
    +before(Frame f): target(f) && set(Color Frame.color) { ... }
    +
    + +

    In addition, the clumsy syntax for getting the old value of the +field has been eliminated. For before advice, the port is simple; +just access the field yourself in the body. Depending on the rest of +your system, you may need to restrict the advice from the aspect body +to eliminiate the circularity.

    + +
    +aspect A {
    +    before(Frame f, Color c): gets(Color f.color)[c] { ... }
    +}
    +==>
    +aspect A {
    +    before(Frame f):
    +            target(f) && get(Color Frame.color) && !within(A) {
    +        Color c = f.color;
    +        ...
    +    }
    +}
    +
    + +

    The same can be done for around advice. However, the +only way to port after advice that needs the old value is to convert +it to around advice. +

    + +
    +aspect A {
    +    after(Frame f, Color c) returning (): gets(Color f.color)[c] { ... }
    +}
    +==>
    +aspect A {
    +    void around(Frame f):
    +            target(f) && get(Color Frame.color) && !within(A) {
    +        Color c = f.color;
    +        proceed(f);
    +        ...
    +    }
    +}
    +
    + +

    When porting sets pointcuts, the new value of a field +is still available, but not the way it was previously. Instead of +using the square bracket syntax, we use an args pointcut. +All set join points are assumed to have exactly one argument, which +holds the new value. So,

    + +
    +after(Color newColor): sets(Color Frame.color)[][newColor] { ... }
    +==>
    +after(Color newColor): args(newColor) && set(Color Frame.color) { ... }
    +
    + +

    Also, if the field was declared private, in order to get at its +old value the aspect must be declared privileged. +

    + +
    Rewriting handlers
    + +

    The value of the exception at an exception handler join point is +now accessed through the args pointcut; all exception +handler join points are treated as having exactly one argument, the +exception value. So, +

    + +
    +before(NotFoundException e): handlers(e) { ... }
    +==> 
    +before(NotFoundException e): args(e) && handler(NotFoundException) { ... }
    +
    + +
    Rewriting within
    + +

    The within pointcut was not typically used to export +context. Though it was accidentally possible to do so in versions of +AspectJ before 1.0, it often didn't do what users expected it to. +This loophole has now been closed, and within can only take type +patterns, not pointcut or advice formals. A use of the +this pointcut will capture what previous implementations +did:

    + +
    +pointcut usesFoo(Foo f): within(f);
    +==>
    +pointcut usesFoo(Foo f): this(f) && within(Foo);
    +
    + +

    Understanding signatures

    + +

    Now that we have this, target, and +args pointcuts, all of our signatures are composed of +just types, names, and wildcards; there are no more parameters. +

    + +

    Also, now that we have the + wildcard to pick out +subtypes, we can make signature +matching much more uniform.

    + +

    Previously, some signatures matched based on subtypes, some based +on instanceof, and some exactly. Now, we have made all signatures +match exactly. +

    + +

    What does this mean for your program? Well, it means that you +may have to add + to some of your signatures, depending +on what you meant them to match. +

    + +

    For example, the pointcut +

    + +
    +calls(void m(Object))
    +
    + +

    previously picked out all method calls to a method named m that +took one argument, which was a subtype of Object. Now, however, it +will only pick out method calls to methods that are defined to take +exactly the type Object, which may be a lot fewer join points. If you +want the old behaviour, simply convert to

    + +
    +call(void m(Object+))
    +
    + +

    Removing the instanceof pointcut

    + +

    The intanceof pointcut has been split into two different +pointcuts, this and target.

    + +

    Typically, the instanceof pointcut would only exist in a compound +pointcut, composed (with &&) with another +pointcut. If the other pointcut was a receptions +pointcut, then instanceof should be converted to +target (and receptions converted to +call). So,

    + +
    +pointcut stateChanges(Subject s): 
    +    instanceof(s) && receptions(void Button.click());
    +==>
    +pointcut stateChange(Subject s): 
    +    target(s) && call(void Button.click());
    +
    + +

    In all other cases, instanceof referred to the +currently executing object, and so should be converted into +this

    + +
    +before(Point p): instanceof(p) && executions(* makePolar(..)) { ... }
    +==>
    +before(Point p): this(p) && execution(* makePolar(..)) { ... }
    +
    + +
    +pointcut setup(Client c): instanceof(c) && calls(Remote Naming.lookup(String));
    +==>
    +pointcut setup(Client c): this(c) && calls(Remote Naming.lookup(String));
    +
    + +

    Rewriting the initializations pointcut

    + +

    Object initialization join points are now more complicated, and +more true to Java's execution model. Now they bracket all of the +initialization that a class can do, after the return of its super +constructor call (before which no initialization can happen). Previous +versions of AspectJ had object initialization join points that only +included initialization that was made in dynamic initializers and +fields.

    + +

    The old behaviour can be recovered with a simple rewrite. +

    + +
    +initializations(A)
    +==>
    +initialization(A.new(..)) && !execution(A.new(..))
    +
    + +

    Understanding constructor calls

    + +

    Previously, constructor call join points were matched by subtypes, +so calls(Foo.new()) would match both calls to create new +Foo objects, and new SubFoo objects. The +new call pointcut designator matches types exactly, so if +you want the old behaviour, you should write +call(Foo+.new()).

    + +

    Similarly, constructor execution join points were matched by +subtypes. So the old executions(Foo.new()) is now +represented by execution(Foo+.new()). +

    + +

    In both of these cases, think before using the + operator; it may +be that you didn't intend subtype matching in the first place.

    + +

    Removing the hasaspect pointcut

    + +

    The hasaspect pointcut is no longer defined, but you +can get the same behaviour using the new if pointcut. +

    + +

    If the aspect whose presense you are checking for was defined +of eachcflow, of eachcflowbelow, or, more +unlikely, of eachJVM(), then the conversion is simple: +

    + +
    +hasaspect(A)
    +==>
    +if(A.hasAspect())
    +
    + +

    If the aspect was defined of eachobject, then you +will have to expose the current object in your pointcut or advice +parameters:

    + +
    +pointcut cut(): hasaspect(A) ... ;
    +==>
    +pointcut cut(Object o): this(o) && if(A.hasAspect(o)) ... ;
    +or
    +pointcut cut(Object o): target(o) && if(A.hasAspect(o)) ... ;
    +
    + +

    If you were using the hasaspect pointcut to expose +the state of the aspect, then you can get the same state by using +A.aspectOf() in the body of the advice. For example, if +the aspect A were defined of eachcflow, then +

    + +
    +before(A myA): hasaspect(myA) {
    +    myA.checkStatus();
    +}
    +==>
    +before(): if(A.hasAspect()) {
    +    A myA = A.aspectOf();
    +    myA.checkStatus();
    +}
    +
    + +

    Removing the withinall pointcut

    + +

    The withinall poinctut is no longer defined. You can use a +combination of within and the new +subtypes operator, +, instead. You'll save two characters and be +using a simpler and more orthogonal language.

    + +
    +withinall(Foo)
    +==>
    +within(Foo+)
    +
    + +

    Removing returns modifier from pointcuts

    + +

    The returns keyword is no longer necessary for user-defined +pointcuts. Simply remove it when you find it.

    + +
    +pointcut publicIntCalls() returns int: calls(public int *(..));
    +==>
    +pointcut publicIntCall(): call(public int *(..));
    +
    + +

    Making some pointcuts static

    + +

    In Java, only static members may be accessed by their declaring +type name, like the static method Math.max() can be +accessed.

    + +

    Pointcuts now have that property too. Pointcuts may be declared +to be static, in which case they can be accessed like +MyAspect.move(), or they can be left non-static, in which +case they can be overridden by a subaspect.

    + +

    In addition, while pointcuts can still be defined in classes, only +static pointcuts can be defined in classes.

    + +

    Porting should be straightforward; just make all your pointcuts in +classes static, and make any pointcut with a qualified +reference static. +

    + +

    Type patterns

    + +

    Understanding * and .. in type patterns

    + +

    Previous versions of AspectJ treated * and .. too cleverly in type +patterns, placing restrictions based on what is a package and what is +a type, and basing their meanings on the definition of a package +hierarchy.

    + +

    In AspectJ 1.0, both of these wildcards are defined simply, and +textually: +

    + + + +

    That's it. +

    + +

    This change won't affect most programs, but it will make +understanding programs easier. There is one ugly idiom, however, that +this change disposes of. If your program includes the type pattern +*..*, which used to match all types, you can replace it with the +much simpler *.

    + +
    +pointcut unaryVoidMethods(): call(void *(*..*));
    +==>
    +pointcut unaryVoidMethod(): call(void *(*));
    +
    + +

    Fixing subtypes in introduction

    + +

    The new + operator is used to normalize the many places you want +to use subtypes of some types. +

    + +

    In introduction forms, you will need to replace +subtypes(TypePattern) type patterns with the +new subtype operator, +. In the case where you wrote +subtypes(Foo), i.e., the subtypes of a single type, +simply replace this with Foo+. Otherwise, use the ++ operator as appropriate in TypePattern.

    + +
    +public void (subtypes(Target0 || Target1)).accept(Visitor v) {
    +    v.visit(this);
    +}
    +==>
    +public void (Target0+ || Target1+).accept(Visitor v) {
    +    v.visit(this);
    +}
    +
    + +

    Advice

    + +

    Moving the return type of around

    + +

    The returns keyword is no longer used for around advice. Instead, +the return type is declared as it is for methods. So,

    + +
    +around(Point p) returns void: setters(p) { ... }
    +==>
    +void around(Point p): setter(p) { ... }
    +
    + +

    Adding a throws clause to around

    + +

    Around advice must now declare the checked exceptions it throws +with a throws clause, much like a method. +

    + +
    +char around(char c) throws java.io.CharConversionException: converter(c) {
    +    char result;
    +    try { result = proceed(); }
    +    catch (Exception e) {
    +        throw new java.io.CharConversionException();
    +    }
    +    if (result == 0) throw new java.io.CharConversionException();
    +    return result;
    +}
    +
    + +

    Understanding advice precedence

    + +

    In previous versions of AspectJ, advice precedence within an +aspect was simple: if a piece of advice appeared before another piece, +it was more precedent. This made perfect sense for +before and around advice, but was the cause +of confusion (even among the AspectJ designers, more than once) for +after advice, as it seemed backward.

    + +

    In addition, advice was ordered by kind, in that around advice +always surrounded before and after advice. +

    + +

    AspectJ 1.0 has changed this; precedence for after +advice is inverted, and advice is no longer ordered by kind. +

    + +

    This won't matter to you unless you write pieces of advice in the +same aspect that apply to the same join point.

    + +

    If you do, here's what to think about: If you're looking at two +pieces of advice and want to know which has precedence, if either is +after advice, then the second one has precedence. +Otherwise, the first does.

    + +

    This allows interesting advice interaction. In the following +advice, for example, the after throwing advice will catch +the exception thrown by the before advice

    + +
    +aspect A {
    +    before(): call(void main(..)) {
    +        throw new RuntimeException();
    +    }
    +    after() throwing(RuntimeException e): call(void main(..)) {
    +         System.err.println("caught you!");
    +    }
    +}
    +
    + +

    But reversing the order will give the before advice +more precedence, making its exception uncatchable by the after +throwing advice +

    + +
    +aspect A {
    +    after() throwing(RuntimeException e): call(void main(..)) {
    +         System.err.println("missed you!");
    +    }
    +    before(): call(void main(..)) {
    +        throw new RuntimeException();
    +    }
    +}
    +
    + +

    Advice in different aspects is ordered by the normal aspect +precedence rules of subtyping and the dominates modifier. +

    + +

    Fixing after returning

    + +

    If you use after returning advice and do not need to expose the +return value, you no longer need to write an empty set of parentheses +to indicate that fact. So,

    + +
    +after(Formals) returning (): Pointcut { ... }
    +==>
    +after(Formals) returning: Pointcut { ... }
    +
    + +

    The same syntax is now available for after throwing advice, in +case you do not care what Throwable is thrown. +

    + +
    +after(Formals) throwing: Pointcut { ... }
    +
    + +

    Renaming thisStaticJoinPoint

    + +

    thisStaticJoinPoint has been renamed +thisJoinPointStaticPart, to reflect that it is now +exactly the static part of thisJoinPoint: It will return +the same object as thisJoinPoint.getStaticPart().

    + +

    Converting access to thisJoinPoint

    + +

    The JoinPoint object hierarchy has been folded into a +single class, org.aspectj.lang.JoinPoint. A common +pattern in logging, for example, was

    + +
    +before() executions(* myMethod()) {
    +    ExecutionJoinPoint jp = (ExecutionJoinPoint)thisJoinPoint;
    +    CodeSignature jp = (CodeSignature)jp.getSignature();
    +    System.err.println(jp.getParameters());
    +    System.err.println(jp.getParameterNames());
    +}    
    +
    + +

    While there is still a rich hierarchy for signatures, there is +only one JoinPoint type, so this can be rewritten as: +

    + +
    +before() executions(* myMethod()) {
    +    JoinPoint jp = thisJoinPoint;
    +    CodeSignature jp = (CodeSignature)jp.getSignature();
    +    System.err.println(jp.getArgs());
    +    System.err.println(jp.getParameterNames());
    +}    
    +
    + +

    Some of the method names of JoinPoint have been +reorganized, as well.

    + +

    Introduction and static crosscutting

    + +

    Removing +implements and +extends

    + +

    The keywords +implements and +extends no +longer exist. Instead, AspectJ uses the declare +form for exactly the same functionality.

    + +
    +Point +implements Serializable;
    +=> 
    +declare parents: Point implements Serializable;
    +
    + +
    +MyButton +extends ButtonAdaptor;
    +=> 
    +declare parents: MyButton extends ButtonAdaptor;
    +
    + +

    Using declare soft

    + +

    Around advice advice no longer effects the static exception +checking of Java. This means that the following code previously +compiled:

    + +
    +class C {
    +    void noExceptionDeclared() {
    +        exceptionDeclared();
    +    }
    +    void exceptionDeclared() throws IOException {}
    +}
    +aspect A {
    +    around(): call(void C.exceptionDeclared()) {
    +        try { proceed(); }
    +        catch (IOException e) {}
    +    }
    +}
    +
    + +

    even though the class C is not compilable on its own (because +noExceptionDeclared actually throws an Exception). +

    + +

    AspectJ now firmly places everything that affects the type system +of Java, including the declared-exception checking system, into the +space of introduction and declare. So, in order to state that the +call to exceptionDeclared() will not, actually, throw an exception, we +now "soften" that exception, that is, take it out of the space of +declared exceptions.

    + +
    +declare soft: ExceptionType: Pointcut;
    +
    + +

    The pointcuts allowed here are limited; you cannot use pointcuts +that would require runtime information. But picking out method calls +is just fine. So in order to make the above example work, one new +declaration is needed: +

    + +
    +declare soft: IOException:
    +    call(void C.exceptionDeclared()) &&
    +    withincode(void noExceptionDeclared());
    +
    + +

    Aspects

    + +

    The syntax of "of each" modifiers has changed. For of +eachcflow and of eachcflowbelow, you can simply +replace "of each" with "per". So,

    + +
    +aspect A of eachcflow(...) { ... }
    +==>
    +aspect A percflow(...) { ... }
    +
    + +

    If you have any aspects defined of eachJVM(), then +you should either remove that declaration entirely (because this is +the default behaviour), or replace the of eachJVM() +declaration with an issingleton declaration. +

    + +
    +aspect of eachJVM() { ... }
    +==>
    +aspect A { ... }
    +or
    +aspect A issingleton { ... }
    +
    + +

    The of eachobject(Pointcut) modifier has +been split into two different forms, of +perthis(Pointcut) and of +pertarget(Pointcut). Which one you replace with +depends on the Pointcut you use. +

    + +

    If you use a pointcut that picked out reception join points, then +use pertarget, and rewrite the pointcut to pick out call +join points. So +

    + +
    +aspect Shadow
    +        of eachobject(receptions(void Point.setX(int)) ||
    +                      receptions(void Point.setY(int))) {
    +    ...
    +}
    +==>
    +aspect Shadow pertarget(call(void Point.setX(int)) ||
    +                        call(void Point.setY(int))) {
    +    ...
    +}
    +
    + +

    Otherwise, in most cases, use perthis. When you +convert, remember the meaning of each of these modifiers. +perthis(Pointcut) indicates that an instance +of the aspect should be associated with every object that is +this at each of the join points picked out by +Pointcut, while pertarget(Pointcut) +associates with every object that is the target object at such join +points.

    + + + + + +
    + +

    Porting pre-0.8beta3 code

    + + + + +

    The following changes are only required when porting code written +prior to the 0.8beta3 release of AspectJ.

    + +

    Changing cflow terminology

    + +

    Changing pre-0.8beta3 code that uses AspectJ's control-flow-based +features only requires rewriting occurrences of +eachcflowroot, cflow, and +cflowtop. No editing of other aspect code is +necessary.

    + +

    eachcflowroot

    + +

    The aspect modifier "of +eachcflowroot(Pointcut)" should now be written more +as "percflow(Pointcut)".

    + +

    cflow

    + +

    In previous versions of AspectJ, the pointcut +cflow(Pointcut) picked out all join points in +the cflow below the join points of Pointcut. That is, it +did not include the join points of Pointcut, only the join +points in their control flow. +

    + +

    As of version 0.8beta3, +cflowbelow(Pointcut) has that behavior. +cflow(Pointcut) includes the join points of +Pointcut.

    + +

    In many cases, you may not care whether the points of +Pointcut are included or not, and so can safely leave +cflow(Pointcut) pointcut designators alone. +However, if you use the idiom +

    + +
    +Pointcut && ! cflow(Pointcut)
    +
    + +

    to capture the non-recursive entries to a particular pointcut, you +will definitely want to rewrite that as +

    + +
    +Pointcut && ! cflowbelow(Pointcut)
    +
    + +

    cflowtop

    + +

    The primitive pointcut designator +cflowtop(Pointcut) has been removed from the +language, as it is expressible with cflow or +cflowbelow. All uses of +cflowtop(Pointcut) can be rewritten as: +

    + +
    +cflowbelow(Pointcut && ! cflowbelow(Pointcut))
    +
    + +

    Though in most cases the following is sufficient +

    + +
    +cflow(Pointcut && ! cflowbelow(Pointcut))
    +
    + +

    Overriding abstract pointcuts

    + +

    In previous versions of AspectJ, a concrete aspect would +implicitly override all of its abstract pointcuts with an empty +pointcut. AspectJ 0.8beta3 enforces the restriction that a concrete +aspect may not have any abstract pointcuts. Thus the following +extension:

    + +
    +abstract aspect A {
    +    abstract pointcut pc();
    +}
    +
    +aspect B {}
    +
    + +

    will no longer compile. +

    + +

    Adding the new empty pointcut designator +

    + +
    +pointcut Id();
    +
    + +

    in the declaration of the concrete aspect fixes this problem. +

    + +
    +abstract aspect A {
    +    abstract pointcut pc();
    +}
    +
    +aspect B {
    +    pointcut pc();
    +}
    +
    + +

    Limiting recursive advice

    + +

    Previously, the compiler silently refrained from applying a piece +of advice to join points within its own advice body. So, for example, +in

    + +
    +class C {
    +    static int i;
    +}
    +
    +aspect A {
    +    before(): gets(int C.i) {
    +        System.err.println("C.i was " + C.i)
    +    }
    +}
    +
    + +

    The advice would trace all references of the static field +C.i except those in the body of the before.

    + +

    The compiler has now removed this special case, and so running the +above example will now cause a StackOverflowException to +be thrown.

    + +

    Most cases of this error can be fixed by correctly specifying the +desired pointcut: In the above example, the intention is clearly not +to trace all references of C.i, just those +outside the aspect. +

    + +
    +class C {
    +    static int i;
    +}
    +
    +aspect A {
    +    before(): get(int C.i) && ! within(A) {
    +        System.err.println("C.i was " + C.i)
    +    }
    +}
    +
    + +

    In a very few cases, you may want the advice to be applicable to +other code in the aspect, but not in the particular piece of advice. +In such cases, you can pull the body of the advice into a method and +restrict away from that method (and away from calls to that method): +

    + +
    +class C {
    +    static int i;
    +}
    +
    +aspect A {
    +    public static int getCi() {
    +        return C.i;                          // will be traced
    +    }
    +
    +    before(): get(int C.i) &&
    +              ! withincode(void A.traceCi())
    +              ! call(void A.traceCi())      {
    +        traceCi();
    +    }
    +    private void traceCi() {
    +        System.err.println("C.i was " + C.i) // will not be traced
    +    }
    +}
    +
    + + + + +
    +

    Porting pre-0.8beta1 code

    + + + +

    The following changes are only required when porting code written +prior to the 0.8beta1 release of AspectJ.

    + +

    Rewriting introductions

    + +

    Syntax

    + +

    The syntax of introduction has changed. Porting most programs +should require some simple editing. Anywhere you have an introduction +block

    + +
    +introduction GTN {
    +    ...
    +}
    +
    + +

    simply move the GTN down into the introduction +declarations and remove the block.

    + +

    For method introduction, place the GTN in front of the +method name, For field introduction, place the GTN in front +of the field name, and for constructor introduction, place the +GTN in front of the new identifier.

    + +
    +introduction Foo {
    +    public void doStuff() { this.doStuffLater(); }
    +    public int calorieCount = 3;
    +    public new(int x) { super(); calorieCount = x; }
    +}
    +
    +==>
    +
    +public void Foo.doStuff() { this.doStuffLater(); }
    +public int Foo.calorieCount= 3;
    +public Foo.new(int x) { super(); calorieCount = x; }
    +
    + +

    For implements and extends introduction, move the GTN +in front of the new identifiers implements or +extends, and place that in a declare parents +form. +

    + +
    +introduction Foo {
    +    implements Comparable;
    +    extends Goo;
    +}
    +
    +==>
    +
    +declare parents: Foo implements Comparable;
    +declare parents: Foo extends Goo;
    +
    + +

    In all cases, if the GTN is just a type name, it can be +moved down on its own. However, if the GTN uses any of +&&, ||, and !, it must +be parenthesized.

    + +
    +introduction subtypes(Foo) && !Goo {
    +    int x;
    +}
    +
    +==>
    +
    +int (Foo+ && !Goo).x;
    +
    + + +

    Access

    + +

    If you had an introduction that was referring to private or +protected members of the target class, this will no longer work. You +will either need to modify your code to avoid this accessibility +issue, or you will need to use the privileged modifier on +the aspect that contains the introduction.

    + +
    +class Counter {
    +    private int count = 2;
    +}
    +
    +aspect ExposeCountersPrivates {
    +    introduction Counter {
    +        public int getCount() { return count; }
    +    }
    +}
    +
    +==>
    +// in 0.8, only privileged aspects can expose a class's privates
    +privileged aspect ExposeCountersPrivates {
    +    public int Counter.getCount() { return count; }
    +}
    +
    + + +

    If you have introduced private or package-protected members, you +will probably have to re-write some code. Most previous uses of +introducing privates can be improved by using private introduction +instead.

    + +
    +class C {
    +}
    +
    +aspect AddCounter {
    +    introduction C {
    +        private int count;
    +        public int getCount() { return count; }
    +    }
    +}
    +
    +==>
    +aspect AddCounter {
    +    private int Counter.count;
    +    public int Counter.getCount() { return count; }
    +}
    +
    + +

    There is one case that we know of where the inability to perform +the introduction of private members makes 0.7 code difficult to +port to 0.8. If you were using the introduction of a private +void writeObject(..) or a private void +readObject(..) method to interact with Java's serialization +API, you will need to come up with an alternative design. Using some +combination of Externalizable, +writeReplace(..) and/or readResolve(..) +methods should allow you to port your code. If you find this isn't +the case, we'd like to hear about it. + + +

    If you were introducing either a protected member or a +package-private member onto a class in order to override a protected +member that was inherited from a superclass, you will have to make +this introduction public.

    + + +

    Removing static advice

    + +

    Static advice has been removed from the language. Now, every +piece of advice is non-static, meaning that it will run in the context +of an aspect instance. +

    + +

    If you have an aspect that only contains static advice, has no +"of" clause or is declared "of eachJVM()", and is not extended by +another aspect, simply remove the keyword "static" from all pieces of +advice, and make sure the aspect is not defined with the "abstract" +modifier.

    + +
    +aspect Tracing {
    +    static before(): executions(* *(..)) {
    +        System.out.println("Got Here! " + thisJoinPoint);
    +    }
    +}
    +
    +==>
    +
    +aspect Tracing {
    +    before(): execution(* *(..)) {
    +        System.out.println("Got Here! " + thisJoinPoint);
    +    }
    +}
    +
    + +

    Otherwise, if you have an aspect contains both static and +non-static advice, is extended, or is "of eachObject(...)" or "of +eachcflowroot(...)", you should group your static advice together and +put it in a new aspect, possibly even an inner aspect.

    + +
    +aspect ComplexTracing of eachobject(cflow(executions(void Main.main(..)))) {
    +    static before(): executions(* *(..)) {
    +        System.out.println("Got Here! " + thisJoinPoint);
    +    }
    +    static after(): executions(* *(..)) {
    +        System.out.println("Returned! " + thisJoinPoint);
    +    }
    +
    +    // some other dynamic advice, fields, etc
    +}
    +
    +==>
    +
    +aspect ComplexTracing of eachobject(cflow(executions(void Main.main(..)))) {
    +    static aspect AlwaysTracing {
    +        before(): execution(* *(..)) {
    +            System.out.println("Got Here! " + thisJoinPoint);
    +        }
    +        after(): execution(* *(..)) {
    +            System.out.println("Returned! " + thisJoinPoint);
    +        }
    +    }
    +
    +    // some other dynamic advice, fields, etc
    +}
    +
    + +

    Fixing aspect-aspect inheritance

    + +

    Aspects can now only extend abstract aspects. This restriction +may cause some redesign of aspect hierarchies. You will probably find +that for the majority of your code the most serious change this +requires is to add an explicit abstract modifier to a +super-aspect that was already implicitly abstract.

    + +
    +aspect BaseTracing {
    +    abstract pointcut traced();
    +    before(): traced() {
    +        System.out.println("Got Here! " + thisJoinPoint);
    +    }
    +}
    +
    +==>
    +
    +// make this abstract aspect explicitly abstract
    +abstract aspect BaseTracing {
    +    ...
    +}
    +
    + + +

    This change has also affected the getAspect static +method. Now, getAspect is only defined on non-abstract +aspects. Previously, you could call getAspect on an +abstract superaspect and (sometimes) get an instance of a subaspect +back.

    + +

    This pattern was used in the Spacewar example in the AspectJ +distribution. We had the class hierarchy

    + +
    +  SpaceObject (abstract)
    +    |- Ship
    +    |- Bullet
    +    |- EnergyPellet
    +
    + +

    And the aspect hierarchy +

    + +
    +  SpaceObjectDA (abstract)
    +    |- ShipDA of eachobject(instanceof(Ship))
    +    |- BulletDA of eachobject(instanceof(Ship))
    +    |- EnergyPacketDA of eachobject(instanceof(Ship))
    +
    + +

    And we would call SpaceObjectDA.getAspect(SpaceObject) to access +the aspect associated with a ship, bullet, or energy pellet. This +pattern depended on the SpaceObjectDA aspect hierarchy +exactly mirroring the SpaceObject hierarchy, and being +maintained that way.

    + +

    A better way to implement this kind of design aspect is to use +private introduction, a new feature of AspectJ. +

    + +

    Using private introduction

    + +

    A common pattern for AspectJ programs that need to associate some +state with every object of a particular type has been to use aspects +that are defined of eachobject(instanceof(...)). A prime +example of this was the BoundPoint aspect of the bean +example: which needed to associate each point with a +PropertyChangeSupport object.

    + +
    +aspect BoundPoint of eachobject(instanceof(Point)) {
    +
    +    java.beans.PropertyChangeSupport support = null;
    +
    +    after() returning(Point p): receptions(p.new(..)){
    +        support = new PropertyChangeSupport(myPoint);
    +    }
    +
    +    around(Point p) returns void: receptions(void p.set*(*)) {
    +        // code that uses support
    +    }
    +}
    +
    + +

    In the new version of AspectJ, a better way of accomplishing many +of these state association is to use privately introduced fields. +Instead of creating an aspect instance for every Point +object, store the PropertyChagneSupport object in the +Point objects themselves. +

    + +
    +aspect BoundPoint {
    +    private PropertyChangeSupport Point.support = new PropertyChangeSupport(this);
    +
    +    void around(Point p): setters(p) {
    +        // code that uses p.support
    +    }
    +}
    +
    + +

    Just as in the past, the PropertyChangeSupport object is not +accessable to anyone but the aspect, but now less mechanism is needed. +

    + +

    There are times when changing aspects that are defined of +eachobject(instanceof(...)) may not be reasonable. If the +aspect instance is stored or passed to other methods, then having a +real of eachobject(instanceof(...)), now written +perthis(this(...)), association may capture the +crosscutting concern best.

    + + + +
    +

    Porting pre-0.7beta11 code

    + + + +

    The following changes are only required when porting code written +prior to the 0.7beta11 release of AspectJ.

    + +

    Removing two-argument calls

    + +

    In AspectJ 0.7beta11, the two-argument calls +primitive pointcut designator was deprecated. Removing these +designators will require different cases depending on what the +original pointcut did.

    + +

    Calls to static methods

    + +

    For pointcuts denoting calls to particular static methods, such as +

    + +
    +calls(String, static String valueOf(int)) // deprecated
    +
    + +

    the transformation is easy. Simply make the desired signature +explicit. Instead of catching all calls to any static method that +happens to have the signature String valueOf(int), catch +calls to that exact method defined in the String class.

    + +
    +call(static String String.valueOf(int))
    +
    + +

    Pointcuts denoting calls to classes of static methods can also be +rewritten with these rules. For example,

    + +
    +calls(my.package.*, static * get*(..)) // deprecated
    +
    + +

    should now be written

    + +
    +call(static * my.package.*.get*(..))
    +
    + +

    Calls to non-static methods

    + +

    Many pointcuts denoting calls to non-static methods can be +fixed the same way that those pointcuts denoting calls to static +methods are fixed. So, +

    + +
    +calls(Thread, int getPriority()) // deprecated
    +
    + +

    which denotes all calls to nullary int methods named getPriority +when the called object is an instance of the Thread type, +can almost always be rewritten

    + +
    +call(int Thread.getPriority())
    +
    + +

    which denotes all calls to the nullary int Thread.getPriority() +method. +

    + +

    Expanding the signature picks out slightly different join points +than the original two-argument form. This won't matter for most +programs, but in some cases the differences may be noticable. In +particular, the expanded-signature form only picks out those calls +where the called object is statically typed to Thread +when its int getPriority() method is called. If you want +to capture calls to the int Thread.getPriority() method, +regardless of how the called object is statically typed, you shoud use +the different translation:

    + +
    +call(int getPriority()) && target(Thread)
    +
    + +

    This will capture all call join points of methods with signature +int Thread.getPriority().

    + +

    It will also denote any join points if the Thread type does not +define (possibly abstractly) some int getPriority() +method, though.

    + + +

    Removing advice from Class declarations

    + +

    The simplest way to remove an advice declaration from a class is +to simply define the advice declaration in an inner aspect. So, +instead of

    + +
    +class C {
    +    static before(): executions(C.new()) { ... } // deprecated
    +}
    +
    + +

    write

    + +
    +class C {
    +    static aspect ConstructionProtocol {
    +        static before(): executions(C.new()) { ... }
    +    }
    +}
    +
    + +

    If your advice doesn't refer to any inner classes or interfaces of +C, you can move the inner aspect out of the class entirely.

    + +
    +class C { ... }
    +
    +aspect ConstructionProtocol {
    +    static before(): execution(C.new()) { ... }
    +}
    +
    + +

    Your code will be clearer if you consider the purpose of each +piece of advice when you make this change. It may be that some of the +advice naturally belongs to another aspect, perhaps already existing. +Or it may be that some pieces of advice in a class are associated to +one concern and some to another; in which case more than aspect would +be appropriate.

    + + +
    +

    Porting pre-0.7beta10 code

    + + + +

    The following changes are only required when porting code written +prior to the 0.7beta10 release of AspectJ.

    + + +

    Changing access to thisJoinPoint

    + +

    In AspectJ 0.7beta10, access to the reflective object +thisJoinPoint substantially changed. The two parts of +this change were the elimination of the runNext() static +method, and the use of an interface hierarchy represent the join point +object.

    + +

    thisJoinPoint.runNext() to +proceed()

    + +

    The elimination of the runNext() static method +requires almost no porting work. An automatic replacement of the +string +

    + +
    thisJoinPoint.runNext
    + +

    with the string +

    + +
    proceed
    + +

    will do the job. However, if any around advice used the +identifier "proceed" as a formal parameter or local +variable, it must be renamed, and if any aspect used it as a field, +then references to the field in around advice should be made explicit +(prefixing the reference with the aspect name or "this", +depending on whether the field is static or not).

    + +

    Using thisJoinPoint

    + +

    While access to reflective information through +thisJoinPoint is more powerful and regular through its +interface hierarchy, the previous uses must be rewritten. Changing +your code will likely require manual editing, but in doing so your +code should get simpler and cleaner.

    + + + +

    Many existing uses of the fields on join points can be re-written +to use one of: +

    + + + +

    For example: +

    + +
    +System.out.println(thisJoinPoint.className + "." +
    +                   thisJoinPoint.methodName)
    +
    + +

    can be replaced with +

    + +
    System.out.println(thisJoinPoint)
    + +

    or +

    + +
    System.out.println(thisJoinPoint.getSignature().toShortString())
    + +

    with comparable behavior. +

    + + + +

    Accesses to the parameters field of join points should be changed +as follows. A field access like: +

    + + +
    thisJoinPoint.parameters
    + +

    must be changed to: +

    + + + + +

    Accesses to the methodName and className fields of join points +that are not suitable for replacement with a toString method, +should be changed as follows. Field accesses like: +

    + + + +

    must be changed to: +

    + + + + + +

    Accessses to the parameterNames and parameterTypes fields of +join points, that are not suitable for conversion to one of the +toString() methods should be changed as follows. Field access +like: +

    + + + +

    must be changed to: +

    + + + + + diff --git a/docs/dist/doc/quick.doc b/docs/dist/doc/quick.doc new file mode 100644 index 000000000..89857a0b8 Binary files /dev/null and b/docs/dist/doc/quick.doc differ diff --git a/docs/dist/examples/bean/BoundPoint.java b/docs/dist/examples/bean/BoundPoint.java new file mode 100644 index 000000000..c247ca9cd --- /dev/null +++ b/docs/dist/examples/bean/BoundPoint.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1998-2002 Xerox Corporation. All rights reserved. + * + * Use and copying of this software and preparation of derivative works based + * upon this software are permitted. Any distribution of this software or + * derivative works must comply with all applicable United States export + * control laws. + * + * This software is made available AS IS, and Xerox Corporation makes no + * warranty about the software, its performance or its conformity to any + * specification. + */ +package bean; + +import java.beans.*; +import java.io.Serializable; + +/* + * Add bound properties and serialization to point objects + */ + +aspect BoundPoint { + /* + * privately introduce a field into Point to hold the property + * change support object. `this' is a reference to a Point object. + */ + private PropertyChangeSupport Point.support = new PropertyChangeSupport(this); + + /* + * Introduce the property change registration methods into Point. + * also introduce implementation of the Serializable interface. + */ + public void Point.addPropertyChangeListener(PropertyChangeListener listener){ + support.addPropertyChangeListener(listener); + } + + public void Point.addPropertyChangeListener(String propertyName, + PropertyChangeListener listener){ + + support.addPropertyChangeListener(propertyName, listener); + } + + public void Point.removePropertyChangeListener(String propertyName, + PropertyChangeListener listener) { + support.removePropertyChangeListener(propertyName, listener); + } + + public void Point.removePropertyChangeListener(PropertyChangeListener listener) { + support.removePropertyChangeListener(listener); + } + + public void Point.hasListeners(String propertyName) { + support.hasListeners(propertyName); + } + + declare parents: Point implements Serializable; + + /** + * Pointcut describing the set methods on Point. + * (uses a wildcard in the method name) + */ + pointcut setter(Point p): call(void Point.set*(*)) && target(p); + + /** + * Advice to get the property change event fired when the + * setters are called. It's around advice because you need + * the old value of the property. + */ + void around(Point p): setter(p) { + String propertyName = + thisJoinPointStaticPart.getSignature().getName().substring("set".length()); + int oldX = p.getX(); + int oldY = p.getY(); + proceed(p); + if (propertyName.equals("X")){ + firePropertyChange(p, propertyName, oldX, p.getX()); + } else { + firePropertyChange(p, propertyName, oldY, p.getY()); + } + } + + /* + * Utility to fire the property change event. + */ + void firePropertyChange(Point p, + String property, + double oldval, + double newval) { + p.support.firePropertyChange(property, + new Double(oldval), + new Double(newval)); + } +} diff --git a/docs/dist/examples/bean/Demo.java b/docs/dist/examples/bean/Demo.java new file mode 100644 index 000000000..767409878 --- /dev/null +++ b/docs/dist/examples/bean/Demo.java @@ -0,0 +1,83 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +*/ +package bean; + +import java.beans.*; +import java.io.*; + +public class Demo implements PropertyChangeListener { + + static final String fileName = "test.tmp"; + + /** + * when Demo is playing the listener role, + * this method reports that a propery has changed + */ + public void propertyChange(PropertyChangeEvent e){ + System.out.println("Property " + e.getPropertyName() + " changed from " + + e.getOldValue() + " to " + e.getNewValue() ); + } + + /** + * main: test the program + */ + public static void main(String[] args){ + Point p1 = new Point(); + p1.addPropertyChangeListener(new Demo()); + System.out.println("p1 =" + p1); + p1.setRectangular(5,2); + System.out.println("p1 =" + p1); + p1.setX( 6 ); + p1.setY( 3 ); + System.out.println("p1 =" + p1); + p1.offset(6,4); + System.out.println("p1 =" + p1); + save(p1, fileName); + Point p2 = (Point) restore(fileName); + System.out.println("Had: " + p1); + System.out.println("Got: " + p2); + } + + /** + * Save a serializable object to a file + */ + static void save(Serializable p, String fn){ + try { + System.out.println("Writing to file: " + p); + FileOutputStream fo = new FileOutputStream(fn); + ObjectOutputStream so = new ObjectOutputStream(fo); + so.writeObject(p); + so.flush(); + } catch (Exception e) { + System.out.println(e); + System.exit(1); + } + } + + /** + * Restore a serializable object from the file + */ + static Object restore(String fn){ + try { + Object result; + System.out.println("Reading from file: " + fn); + FileInputStream fi = new FileInputStream(fn); + ObjectInputStream si = new ObjectInputStream(fi); + return si.readObject(); + } catch (Exception e) { + System.out.println(e); + System.exit(1); + } + return null; + } + + +} diff --git a/docs/dist/examples/bean/Point.java b/docs/dist/examples/bean/Point.java new file mode 100644 index 000000000..d5040c2bf --- /dev/null +++ b/docs/dist/examples/bean/Point.java @@ -0,0 +1,76 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +*/ + +package bean; + +class Point { + + protected int x = 0; + protected int y = 0; + + /** + * Return the X coordinate + */ + public int getX(){ + return x; + } + + /** + * Return the y coordinate + */ + public int getY(){ + return y; + } + + /** + * Set the x and y coordinates + */ + public void setRectangular(int newX, int newY){ + setX(newX); + setY(newY); + } + + /** + * Set the X coordinate + */ + public void setX(int newX) { + x = newX; + } + + /** + * set the y coordinate + */ + public void setY(int newY) { + y = newY; + } + + + /** + * Move the point by the specified x and y offset + */ + public void offset(int deltaX, int deltaY){ + setRectangular(x + deltaX, y + deltaY); + } + + + /** + * MAke a string of this + */ + public String toString(){ + return "(" + getX() + ", " + getY() + ")" ; + } + + + +} diff --git a/docs/dist/examples/build.xml b/docs/dist/examples/build.xml new file mode 100644 index 000000000..08d7cdc05 --- /dev/null +++ b/docs/dist/examples/build.xml @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + This script builds the AspectJ examples. + + Relevant targets: + spacewar build and run spacewar with debugging (default) + all build and run each example + {example} build and run any {example} + (use -projecthelp to list {example} names) + + Setup: + - Run from the examples directory. + - Put aspectj-ant.jar in ../lib with aspectjtools.jar and aspectjrt.jar + + Variants: + - To avoid running (i.e., compile only), define variable "norun" + - To define a variable, use the Ant -D option - e.g., on Windows: + + ant -f build.xml -DJAVA_HOME=c:\jdk1.3.1 -Dnorun=skip + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/dist/examples/coordination/Condition.java b/docs/dist/examples/coordination/Condition.java new file mode 100644 index 000000000..18bbafee2 --- /dev/null +++ b/docs/dist/examples/coordination/Condition.java @@ -0,0 +1,37 @@ +/* -*- Mode: Java; -*- + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package coordination; + + +/** + * Interface for pre-conditions that are passed to guardedEntry methods of + * Coordinator. + * Conditions should be passed as anonymous classes that simply implement + * the checkit method. + * + */ +public interface Condition { + + /** + * This method is called automatically by Coordinator.guardedEntry(...) + * and it's called everytime the coordination state changes. + */ + + public boolean checkit(); +} diff --git a/docs/dist/examples/coordination/CoordinationAction.java b/docs/dist/examples/coordination/CoordinationAction.java new file mode 100644 index 000000000..7825b95b7 --- /dev/null +++ b/docs/dist/examples/coordination/CoordinationAction.java @@ -0,0 +1,37 @@ +/* -*- Mode: Java; -*- + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package coordination; + + +/** + * Interface for coordination actions that are passed to guardedEntry methods of + * Coordinator. + * Coordination actions should be passed as anonymous classes that simply + * implement the doit method. + * + */ +public interface CoordinationAction { + /** + * This method is called by Coordinator.guardedEntry(...) and + * Coordinator.guardedExit(...). Use it for changing coordination state + * upon entering and exiting methods. + */ + + public void doit(); +} diff --git a/docs/dist/examples/coordination/Coordinator.java b/docs/dist/examples/coordination/Coordinator.java new file mode 100644 index 000000000..ea0522d6b --- /dev/null +++ b/docs/dist/examples/coordination/Coordinator.java @@ -0,0 +1,449 @@ +/* -*- Mode: Java; -*- + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package coordination; + +import java.util.*; //!!! + +/** + * The Coordinator class provides the basic functionality for synchronizing + * and coordinating different threads upon entering and exiting methods. + * It can be used in two different ways: + * 1) by instantiating regular coordinator objects that are used by aspects; or + * 2) by extending it (sub-classing) with coordinator aspects. + *

    + * Method invocations are the smallest units for defining critical sections + * and pre-conditions. The use of coordinators, either regular objects or aspect + * instances, should always end up by invoking guardedEntry(...) in a + * before weave and guardedExit(...) in an after weave for all methods that + * need coordination. guardedEntry and guardedExit are the methods that + * actually manage the synchronization and coordination constraints given + * by their parameters and by pre-existent exclusion markers. + *

    + * The synchronization of threads for the execution of critical section + * methods in an object is done by marking those methods as self- and/or + * mutually-exclusive (addSelfex, addMutex). + * Just by itself, addSelfex("M") does not enforce the self-exclusion + * of method M - enforcement is done by invoking guardedEntry before + * M is executed. Similarly, addMutex(new String[] {"M1", "M2"}) does + * not enforce the mutual exclusion between methods M1 and M2. + *

    + * A guardedEntry on a method that has been marked as self-exclusive + * ensures that the method is executed in the invoked object by only one thread + * at a time. A guardedEntry on a method that has been marked has mutually- + * exclusive with other methods ensures that the execution of that method + * by a thread in the invoked object temporarily blocks the execution by + * other threads of the methods that are in the same mutex set. + *

    + * The coordination of threads, i.e. their explicit suspension and + * resumption, is done through the use of pre-conditions and coordination + * actions that are passed as parameters to guardedEntry and guardedExit + * with the form of anonymous classes. + */ +public abstract aspect Coordinator { + private Hashtable methods = null; + private Vector exclusions = null; + + abstract protected pointcut synchronizationPoint(); + + public Coordinator() { + methods = new Hashtable(); + exclusions = new Vector(5); + } + + before (): synchronizationPoint() { + this.guardedEntry(thisJoinPointStaticPart.getSignature().getName()); + } + + after (): synchronizationPoint() { + this.guardedExit(thisJoinPointStaticPart.getSignature().getName()); + } + + /** + * Takes a multi-part method name (eg "BoundedBuffer.put") + * and marks that method as self-exclusive. + * No checks are made with respect to the existence of the method + * whose name is given. + */ + public synchronized void addSelfex(String methName) { + Selfex sex = new Selfex (methName); + + // update db of all exclusions in this coordinator + exclusions.addElement(sex); + + // update local info in method + Method aMeth = getOrSetMethod(methName); + aMeth.addExclusion(sex); + } + + /** + * Takes a multi-part method name (e.g. "BoundedBuffer.put") + * and removes that method from the list of self-exclusive methods. + */ + public synchronized void removeSelfex(String methName) { + for (int i = 0; i < exclusions.size(); i++) { + Exclusion sex = (Exclusion)exclusions.elementAt(i); + if ((sex instanceof Selfex) && + (((Selfex)sex).methodName.equals(methName))) { + + // update db of all exclusions in this coordinator + exclusions.removeElementAt(i); + + // update local info in method + Method aMeth = getOrSetMethod(methName); + aMeth.removeExclusion(sex); + } + } + } + + /** + * Takes an array of multi-part method names and marks those + * methods as mutually exclusive. + * No checks are made with respect to the existence of the methods + * whose names are given. + */ + public synchronized void addMutex(String[] methNames) { + Mutex mux = new Mutex(methNames); + + // update db of all exclusions in this coordinator + exclusions.addElement(mux); + + // update local info in each method + for (int i = 0; i < methNames.length; i++) { + Method aMeth = getOrSetMethod(methNames[i]); + aMeth.addExclusion(mux); + } + } + + /** + * Takes an array of multi-part method names that correspond + * to an existing mutex set and remove the mutual exclusion constraint. + * If the given mutex set does not exist, removeMutex does nothing. + */ + public synchronized void removeMutex(String[] methNames) { + for (int i = 0; i < exclusions.size(); i++) { + Exclusion mux = (Exclusion)exclusions.elementAt(i); + if (mux instanceof Mutex) { + boolean same = true; + for (int j = 0; j < methNames.length; j++) + if (!methNames[j].equals(((Mutex)mux).methodNames[j])) + same = false; + if (same) { + // update db of all exclusions in this coordinator + exclusions.removeElementAt(i); + + // update local info in each method involved + for (int j = 0; j < methNames.length; j++) { + Method aMeth = getOrSetMethod(methNames[j]); + aMeth.removeExclusion(mux); + } + } + } + } + } + + /** + * This method is the guard for enforcing all synchronization and + * coordination constraints of a given method, and it should be called + * just before the method is executed. + * In this form, only the method name is given. The only constraints + * checked are the exclusion constraints. + * If the method was previousely marked as selfex (through addSelfex), + * guardedEntry ensures that the method is executed only when no other + * thread is executing it. + * If the method was previousely marked as being in one or more mutex + * sets, guardedEntry ensures that the method is executed only when no other + * thread is executing any of the methods with which the give method is + * mutexed. + */ + public synchronized void guardedEntry(String methName) { + guardedEntry(methName, new Condition() { + public boolean checkit() { + return true; + } + }, null); + } + + /** + * Just like guardedEntry(String methName), but the given method is executed + * only when the given condition is true. + * guardedEntry is the guard for enforcing all synchronization and + * coordination constraints of a given method, and it should be called + * just before the method is executed. + * In this form, the method name is given along with a condition. + * The constraints checked are the exclusion constraints and whether + * the given condition is true. + * If the method was previousely marked as selfex (through addSelfex), + * guardedEntry ensures that the method is executed only when no other + * thread is executing it. + * If the method was previousely marked as being in one or more mutex + * sets, guardedEntry ensures that the method is executed only when no other + * thread is executing any of the methods with which the give method is + * mutexed. + * If the condition is false, guardedEntry suspends the current thread. + * That thread remains suspended until the condition becomes true, in + * which case all constraints are rechecked before the method is executed. + * When all exclusion constraints are checked and the given condition is + * true, the given method is executed. + */ + public synchronized void guardedEntry(String methName, Condition condition) { + guardedEntry(methName, condition, null); + } + + /** + * Just like guardedEntry(String methName), but with an additional + * coordination action that is executed before the given method is + * executed. + * guardedEntry is the guard for enforcing all synchronization and + * coordination constraints of a given method, and it should be called + * just before the method is executed. + * In this form, the method name is given along with a coordination action. + * The only constraints checked are the exclusion constraints. + * If the method was previousely marked as selfex (through addSelfex), + * guardedEntry ensures that the method is executed only when no other + * thread is executing it. + * If the method was previousely marked as being in one or more mutex + * sets, guardedEntry ensures that the method is executed only when no other + * thread is executing any of the methods with which the give method is + * mutexed. + * The given coordination action is executed just before the given method + * is executed. + */ + public synchronized void guardedEntry(String methName, + CoordinationAction action) { + guardedEntry(methName, new Condition() { + public boolean checkit() { + return true; + } + }, + action); + } + + /** + * Just like guardedEntry(String methName), but the given method is executed + * only when the given condition is true; the additional + * coordination action that is executed before the given method is + * executed. + * guardedEntry is the guard for enforcing all synchronization and + * coordination constraints of a given method, and it should be called + * just before the method is executed. + * In this form, the method name is given along with a condition and + * a coordination action. + * The constraints checked are the exclusion constraints and whether the + * given condition is true. + * If the method was previousely marked as selfex (through addSelfex), + * guardedEntry ensures that the method is executed only when no other + * thread is executing it. + * If the method was previousely marked as being in one or more mutex + * sets, guardedEntry ensures that the method is executed only when no other + * thread is executing any of the methods with which the give method is + * mutexed. + * If the condition is false, guardedEntry suspends the current thread. + * That thread remains suspended until the condition becomes true, in + * which case all constraints are rechecked before the method is executed. + * When all exclusion constraints are checked and the given condition is + * true, the given method is executed. + * The given coordination action is executed just before the given method + * is executed. + */ + public synchronized void guardedEntry(String methName, + Condition condition, + CoordinationAction action) { + Method aMeth = getOrSetMethod(methName); + boolean canGo = false; + + // test pre-conditions for entering the method + while (!canGo) { + canGo = true; + for (int i = 0; i < aMeth.exes.size() && canGo; i++) + if (!((Exclusion)aMeth.exes.elementAt(i)).testExclusion(aMeth.name)) { + canGo = false; + } + if (canGo && !condition.checkit()) { + canGo = false; + } + if (!canGo) + try { + wait(); + } catch (InterruptedException e) { } + } + + // OK. + enterMethod(aMeth, action); + } + + /** + * This method is similar to guardedEntry, but it takes + * an additional parameter - the milliseconds after which any suspension + * will abort with a timeout. + */ + public synchronized void guardedEntryWithTimeout(String methName, + long millis) + throws TimeoutException { + guardedEntryWithTimeout(methName, new Condition() { + public boolean checkit() { + return true; + } + }, null, millis); + } + + /** + * This method is similar to guardedEntry, but it takes + * an additional parameter - the milliseconds after which any suspension + * will abort with a timeout. + */ + public synchronized void guardedEntryWithTimeout(String methName, + Condition condition, + long millis) + throws TimeoutException { + guardedEntryWithTimeout(methName, condition, null, millis); + } + + /** + * This method is similar to guardedEntry, but it takes + * an additional parameter - the milliseconds after which any suspension + * will abort with a timeout. + */ + public synchronized void guardedEntryWithTimeout(String methName, + CoordinationAction action, + long millis) + throws TimeoutException { + guardedEntryWithTimeout(methName, new Condition() { + public boolean checkit() { + return true; + } + }, action, millis); + } + + /** + * This method is similar to guardedEntry, but it takes + * an additional parameter - the milliseconds after which any suspension + * will abort with a timeout. + */ + public synchronized void guardedEntryWithTimeout(String methName, + Condition condition, + CoordinationAction action, + long millis) + throws TimeoutException { + + Method aMeth = getOrSetMethod(methName); + boolean canGo = false; + long waitTime = millis; + long startTime = System.currentTimeMillis(); + + // test pre-conditions for entering the method + while (!canGo) { + canGo = true; + for (int i = 0; i < aMeth.exes.size() && canGo; i++) + if ((!((Exclusion)aMeth.exes.elementAt(i)).testExclusion(aMeth.name)) || + (!condition.checkit())) { + canGo = false; + } + if (!canGo) { + try { + wait(waitTime); + } catch (InterruptedException e) {} + + long now = System.currentTimeMillis(); + long timeSoFar = now - startTime; + if (timeSoFar >= millis) // timeout! + throw new TimeoutException(timeSoFar); + else // adjust time + waitTime = millis - timeSoFar; + } + } + + // OK. + enterMethod(aMeth, action); + } + + /** + * This method provides the means for updating all synchronization and + * coordination state after the execution of a given method, and it should be + * called after the method is executed. + * In this form, only the method name is given. + * The synchronization state for self- and mutual-exclusion is + * automatically upadted. + */ + public synchronized void guardedExit(String methName) { + guardedExit(methName, null); + } + + /** + * Just like guardedExit(String methName) but with an additional + * coordination action that is executed. + * guardedExit provides the means for updating all synchronization and + * coordination state after the execution of a given method, and it should be + * called after the method is executed. + * In this form, the method name is given along with a coordination action. + * The synchronization state for self- and mutual-exclusion is + * automatically upadted. + * The given coordination action is executed. + */ + public synchronized void guardedExit(String methName, + CoordinationAction action) { + Method aMeth = getOrSetMethod(methName); + + for (int i = 0; i < aMeth.exes.size(); i++) + ((Exclusion)aMeth.exes.elementAt(i)).exitExclusion(methName); + if (action != null) action.doit(); + notifyAll(); + } + + private Method getOrSetMethod(String methName) { + Method aMeth = null; + if (!methods.containsKey(methName)) { + methods.put(methName, (aMeth = new Method(methName))); + } + else { + aMeth = (Method) methods.get(methName); + } + return aMeth; + } + + private void enterMethod(Method aMeth, CoordinationAction action) { + for (int i = 0; i < aMeth.exes.size(); i++) + ((Exclusion)aMeth.exes.elementAt(i)).enterExclusion(aMeth.name); + + if (action != null) action.doit(); + } + + + +} + +class Method { + String name; + Vector exes = new Vector(3); + + Method(String n) { + name = n; + } + + void addExclusion(Exclusion ex) { + exes.addElement(ex); + } + + void removeExclusion(Exclusion ex) { + for (int i = 0; i < exes.size(); i++) { + if (exes.elementAt(i) == ex) + exes.removeElementAt(i); + } + } +} + diff --git a/docs/dist/examples/coordination/Exclusion.java b/docs/dist/examples/coordination/Exclusion.java new file mode 100644 index 000000000..9179cd6e0 --- /dev/null +++ b/docs/dist/examples/coordination/Exclusion.java @@ -0,0 +1,33 @@ +/* -*- Mode: Java; -*- + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package coordination; + + +interface Exclusion { + + boolean testExclusion(String methodName); + + void enterExclusion(String methodName); + + void exitExclusion(String methodName); + + // for debug !!! + void printNames(); +} + diff --git a/docs/dist/examples/coordination/MethodState.java b/docs/dist/examples/coordination/MethodState.java new file mode 100644 index 000000000..03a44378a --- /dev/null +++ b/docs/dist/examples/coordination/MethodState.java @@ -0,0 +1,45 @@ +/* -*- Mode: Java; -*- + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package coordination; + +import java.util.Vector; +import java.util.Enumeration; + + +class MethodState { + + Vector threads=new Vector(); + + void enterInThread (Thread t) { + threads.addElement(t); + } + + void exitInThread(Thread t) { + threads.removeElement(t); + } + + boolean hasOtherThreadThan(Thread t) { + Enumeration e = threads.elements(); + while (e.hasMoreElements()) + if (e.nextElement() != t) + return(true); + return (false); + } + +} diff --git a/docs/dist/examples/coordination/Mutex.java b/docs/dist/examples/coordination/Mutex.java new file mode 100644 index 000000000..2472137c6 --- /dev/null +++ b/docs/dist/examples/coordination/Mutex.java @@ -0,0 +1,86 @@ +/* -*- Mode: Java; -*- + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package coordination; + +import java.lang.String; + + +class Mutex implements Exclusion { + String[] methodNames; + MethodState[] methodStates; + + String prettyName; + + Mutex (String[] _methodNames) { + methodNames = _methodNames; + methodStates = new MethodState[methodNames.length]; + for (int i = 0; i < methodNames.length; i++) { + methodStates[i] = new MethodState(); + } + } + + private boolean isMethodIn (String _methodName) { + for (int i = 0; i < methodNames.length; i++) { + if (_methodName.equals(methodNames[i])) + return(true); + } + return(false); + } + + private MethodState getMethodState (String _methodName) { + for (int i = 0; i < methodNames.length; i++) { + if (_methodName.equals(methodNames[i])) + return(methodStates[i]); + } + return(null); + } + + public boolean testExclusion (String _methodName) { + Thread ct = Thread.currentThread(); + // + // Loop through each of the other methods in this exclusion set, to be sure + // that no other thread is running them. Note that we have to be careful + // about selfex. + // + for (int i = 0; i < methodNames.length; i++) { + if (!_methodName.equals(methodNames[i])) { + if (methodStates[i].hasOtherThreadThan(ct)) + return(false); + } + } + return (true); + } + + public void enterExclusion (String _methodName) { + MethodState methodState = getMethodState(_methodName); + methodState.enterInThread(Thread.currentThread()); + } + + public void exitExclusion (String _methodName) { + MethodState methodState = getMethodState(_methodName); + methodState.exitInThread(Thread.currentThread()); + } + + public void printNames() { + System.out.print("Mutex names: "); + for (int i = 0; i < methodNames.length; i++) + System.out.print(methodNames[i] + " "); + System.out.println(); + } +} diff --git a/docs/dist/examples/coordination/Selfex.java b/docs/dist/examples/coordination/Selfex.java new file mode 100644 index 000000000..ff73afd61 --- /dev/null +++ b/docs/dist/examples/coordination/Selfex.java @@ -0,0 +1,55 @@ +/* -*- Mode: Java; -*- + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package coordination; + + +import java.lang.String; + +class Selfex implements Exclusion { + String methodName; + Thread thread; + int count = 0; + + Selfex (String _methodName) { + methodName = _methodName; + } + + public boolean testExclusion (String _methodName) { + if (count == 0) + return(true); + return (thread == Thread.currentThread()); + } + + public void enterExclusion (String _methodName) { + count++; + thread = Thread.currentThread(); // note that if count wasn't 0 + // we aren't changing thread + } + + public void exitExclusion (String _methodName) { + count--; + if (count == 0) // not stricly necessary, but... + thread = null; + } + + public void printNames() { + System.out.println("Selfex name: " + methodName); + } + +} diff --git a/docs/dist/examples/coordination/TimeoutException.java b/docs/dist/examples/coordination/TimeoutException.java new file mode 100644 index 000000000..e16aa7f09 --- /dev/null +++ b/docs/dist/examples/coordination/TimeoutException.java @@ -0,0 +1,27 @@ +/* -*- Mode: Java; -*- + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package coordination; + + +public class TimeoutException extends Exception { + long time; + TimeoutException(long _time) { + time = _time; + } +} diff --git a/docs/dist/examples/introduction/CloneablePoint.java b/docs/dist/examples/introduction/CloneablePoint.java new file mode 100644 index 000000000..85fa4faf0 --- /dev/null +++ b/docs/dist/examples/introduction/CloneablePoint.java @@ -0,0 +1,42 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +*/ +package introduction; + +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 ); + } +} diff --git a/docs/dist/examples/introduction/ComparablePoint.java b/docs/dist/examples/introduction/ComparablePoint.java new file mode 100644 index 000000000..a2893dba0 --- /dev/null +++ b/docs/dist/examples/introduction/ComparablePoint.java @@ -0,0 +1,46 @@ +/* +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. +*/ + +package introduction; + +public aspect ComparablePoint { + + declare parents: Point implements Comparable; + + public int Point.compareTo(Object o) { + return (int) (this.getRho() - ((Point)o).getRho()); + } + + public static void main(String[] args){ + Point p1 = new Point(); + Point p2 = new Point(); + + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.setRectangular(2,5); + p2.setRectangular(2,5); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p2.setRectangular(3,6); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.setPolar(Math.PI, 4); + p2.setPolar(Math.PI, 4); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.rotate(Math.PI / 4.0); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.offset(1,1); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + } +} diff --git a/docs/dist/examples/introduction/HashablePoint.java b/docs/dist/examples/introduction/HashablePoint.java new file mode 100644 index 000000000..39eb33ba4 --- /dev/null +++ b/docs/dist/examples/introduction/HashablePoint.java @@ -0,0 +1,47 @@ +/* +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. +*/ + +package introduction; + +import java.util.Hashtable; + +public aspect HashablePoint { + + public int Point.hashCode() { + return (int) (getX() + getY() % Integer.MAX_VALUE); + } + + public boolean Point.equals(Object o) { + if (o == this) { return true; } + if (!(o instanceof Point)) { return false; } + Point other = (Point)o; + return (getX() == other.getX()) && (getY() == other.getY()); + } + + public static void main(String[] args) { + Hashtable h = new Hashtable(); + Point p1 = new Point(); + + p1.setRectangular(10, 10); + Point p2 = new Point(); + + p2.setRectangular(10, 10); + + System.out.println("p1 = " + p1); + System.out.println("p2 = " + p2); + System.out.println("p1.hashCode() = " + p1.hashCode()); + System.out.println("p2.hashCode() = " + p2.hashCode()); + + h.put(p1, "P1"); + System.out.println("Got: " + h.get(p2)); + } +} diff --git a/docs/dist/examples/introduction/Point.java b/docs/dist/examples/introduction/Point.java new file mode 100644 index 000000000..609a0488c --- /dev/null +++ b/docs/dist/examples/introduction/Point.java @@ -0,0 +1,98 @@ +/* + Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + + Use and copying of this software and preparation of derivative works based + upon this software are permitted. Any distribution of this software or + derivative works must comply with all applicable United States export control + laws. + + This software is made available AS IS, and Xerox Corporation makes no warranty + about the software, its performance or its conformity to any specification. +*/ + +package introduction; + +public class Point { + + protected double x = 0; + protected double y = 0; + protected double theta = 0; + protected double rho = 0; + + protected boolean polar = true; + protected boolean rectangular = true; + + public double getX(){ + makeRectangular(); + return x; + } + + public double getY(){ + makeRectangular(); + return y; + } + + public double getTheta(){ + makePolar(); + return theta; + } + + public double getRho(){ + makePolar(); + return rho; + } + + public void setRectangular(double newX, double newY){ + x = newX; + y = newY; + rectangular = true; + polar = false; + } + + public void setPolar(double newTheta, double newRho){ + theta = newTheta; + rho = newRho; + rectangular = false; + polar = true; + } + + public void rotate(double angle){ + setPolar(theta + angle, rho); + } + + public void offset(double deltaX, double deltaY){ + setRectangular(x + deltaX, y + deltaY); + } + + protected void makePolar(){ + if (!polar){ + theta = Math.atan2(y,x); + rho = y / Math.sin(theta); + polar = true; + } + } + + protected void makeRectangular(){ + if (!rectangular) { + x = rho * Math.sin(theta); + y = rho * Math.cos(theta); + rectangular = true; + } + } + + public String toString(){ + return "(" + getX() + ", " + getY() + ")[" + + getTheta() + " : " + getRho() + "]"; + } + + public static void main(String[] args){ + Point p1 = new Point(); + System.out.println("p1 =" + p1); + p1.setRectangular(5,2); + System.out.println("p1 =" + p1); + p1.setPolar( Math.PI / 4.0 , 1.0); + System.out.println("p1 =" + p1); + p1.setPolar( 0.3805 , 5.385); + System.out.println("p1 =" + p1); + } +} diff --git a/docs/dist/examples/observer/Button.java b/docs/dist/examples/observer/Button.java new file mode 100644 index 000000000..086a89e24 --- /dev/null +++ b/docs/dist/examples/observer/Button.java @@ -0,0 +1,45 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +Button.java + +*/ + + +package observer; + +import java.awt.Color; +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +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() {} + +} diff --git a/docs/dist/examples/observer/ColorLabel.java b/docs/dist/examples/observer/ColorLabel.java new file mode 100644 index 000000000..7b0c05fc9 --- /dev/null +++ b/docs/dist/examples/observer/ColorLabel.java @@ -0,0 +1,40 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +ColorLabel.java + +*/ + +package observer; +import java.awt.Color; +import java.awt.Label; + +class ColorLabel extends Label { + + ColorLabel(Display display) { + super(); + display.addToFrame(this); + } + + final static Color[] colors = {Color.red, Color.blue, + Color.green, Color.magenta}; + private int colorIndex = 0; + private int cycleCount = 0; + void colorCycle() { + cycleCount++; + colorIndex = (colorIndex + 1) % colors.length; + setBackground(colors[colorIndex]); + setText("" + cycleCount); + } +} + + diff --git a/docs/dist/examples/observer/Demo.java b/docs/dist/examples/observer/Demo.java new file mode 100644 index 000000000..b25552478 --- /dev/null +++ b/docs/dist/examples/observer/Demo.java @@ -0,0 +1,34 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +Demo.java + +*/ + +package observer; + +public class Demo { + public static void main(String[] args) { + + Display display = new Display(); + Button b1 = new Button(display); + Button b2 = new Button(display); + ColorLabel c1 = new ColorLabel(display); + ColorLabel c2 = new ColorLabel(display); + ColorLabel c3 = new ColorLabel(display); + + b1.addObserver(c1); + b1.addObserver(c2); + b2.addObserver(c3); + } +} + diff --git a/docs/dist/examples/observer/Display.java b/docs/dist/examples/observer/Display.java new file mode 100644 index 000000000..d7f4d479c --- /dev/null +++ b/docs/dist/examples/observer/Display.java @@ -0,0 +1,52 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +Display.java + +*/ + +package observer; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Container; +import java.awt.Component; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.BorderLayout; + +/* + * Display is the container class that holds all the views of the + * colored number. + * In this demo, it holds buttons. + */ + +class Display extends Panel { + + protected Frame frame = new Frame("Subject/Observer Demo"); + + Display() { + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) {System.exit(0);} + }); + + frame.add(this, BorderLayout.CENTER); + frame.pack(); + frame.setVisible(true); + } + + void addToFrame(Component c) { + add(c); + frame.pack(); + } +} + + diff --git a/docs/dist/examples/observer/Observer.java b/docs/dist/examples/observer/Observer.java new file mode 100644 index 000000000..58ae44916 --- /dev/null +++ b/docs/dist/examples/observer/Observer.java @@ -0,0 +1,22 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +Observer.java + +*/ +package observer; + +interface Observer { + void setSubject(Subject s); + Subject getSubject(); + void update(); +} diff --git a/docs/dist/examples/observer/Subject.java b/docs/dist/examples/observer/Subject.java new file mode 100644 index 000000000..5d80b1e09 --- /dev/null +++ b/docs/dist/examples/observer/Subject.java @@ -0,0 +1,24 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +Subject.java + +*/ +package observer; +import java.util.Vector; + +interface Subject { + void addObserver(Observer obs); + void removeObserver(Observer obs); + Vector getObservers(); + Object getData(); +} diff --git a/docs/dist/examples/observer/SubjectObserverProtocol.java b/docs/dist/examples/observer/SubjectObserverProtocol.java new file mode 100644 index 000000000..73f730e09 --- /dev/null +++ b/docs/dist/examples/observer/SubjectObserverProtocol.java @@ -0,0 +1,47 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +SubjectObserverProtocol.java + +*/ + +package observer; + +import java.util.Vector; + +abstract aspect SubjectObserverProtocol { + + abstract pointcut stateChanges(Subject s); + + after(Subject s): stateChanges(s) { + for (int i = 0; i < s.getObservers().size(); i++) { + ((Observer)s.getObservers().elementAt(i)).update(); + } + } + + private Vector Subject.observers = new Vector(); + public void Subject.addObserver(Observer obs) { + observers.addElement(obs); + obs.setSubject(this); + } + public void Subject.removeObserver(Observer obs) { + observers.removeElement(obs); + obs.setSubject(null); + } + public Vector Subject.getObservers() { return observers; } + + private Subject Observer.subject = null; + public void Observer.setSubject(Subject s) { subject = s; } + public Subject Observer.getSubject() { return subject; } + +} + diff --git a/docs/dist/examples/observer/SubjectObserverProtocolImpl.java b/docs/dist/examples/observer/SubjectObserverProtocolImpl.java new file mode 100644 index 000000000..01f0c38fc --- /dev/null +++ b/docs/dist/examples/observer/SubjectObserverProtocolImpl.java @@ -0,0 +1,36 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +SubjectObserverProtocolImpl.java + +*/ + +package observer; + +import java.util.Vector; + +aspect SubjectObserverProtocolImpl extends SubjectObserverProtocol { + + declare parents: Button implements Subject; + public Object Button.getData() { return this; } + + declare parents: ColorLabel implements Observer; + public void ColorLabel.update() { + colorCycle(); + } + + pointcut stateChanges(Subject s): + target(s) && + call(void Button.click()); + +} + diff --git a/docs/dist/examples/spacewar/Bullet.java b/docs/dist/examples/spacewar/Bullet.java new file mode 100644 index 000000000..6581dbbf7 --- /dev/null +++ b/docs/dist/examples/spacewar/Bullet.java @@ -0,0 +1,48 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +Bullet.java +Part of the Spacewar game. + +*/ + +package spacewar; + +class Bullet extends SpaceObject { + + static private final int SIZE = 3; //Can't be changed for now!!! + static private int LIFETIME = 50; + + private int lifeLeft; + + Bullet (Game theGame, double xP, double yP, double xV, double yV) { + super(theGame, xP, yP, xV, yV); + lifeLeft = LIFETIME; + } + + int getSize() { return SIZE; } + + void handleCollision(SpaceObject obj) { + die(); + } + + void clockTick() { + if (--lifeLeft == 0) + die(); + super.clockTick(); + } +} diff --git a/docs/dist/examples/spacewar/Debug.java b/docs/dist/examples/spacewar/Debug.java new file mode 100644 index 000000000..b9a476e0e --- /dev/null +++ b/docs/dist/examples/spacewar/Debug.java @@ -0,0 +1,219 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +Debug.java +Part of the Spacewar system. + +*/ + +package spacewar; + +import java.awt.Menu; +import java.awt.CheckboxMenuItem; +import java.awt.Frame; +import java.awt.TextArea; +import java.awt.Dimension; + +/** + * This aspect specifies debugging information to be output to the + * information window. + * + * When the debug aspect is compiled in the Frame menu has several checkbox + * items that can be used to control the amount of tracing information + * displayed. (By default the first three are off, because they generate + * so much information.) + * + * There are two reasons to gather all this debugging code into an aspect + * like this: + * + * (1) It makes it easier to understand when it is all in one place. + * + * (2) It means that we can "plug and debug". We can enable/disable + * the debugging code simply by weaving or not weaving this + * aspect in. + * + * All in all, this is a lot better than the usual practice of writing + * complex debugging code and then deleting it when the bug is found, + * only to regret it a month later when a related bug surfaces. (Or even + * the same bug!) + * + * This file also defines a class InfoWin, which it uses to display all the + * debugging information. + */ +aspect Debug { + + private static InfoWin infoWin = new InfoWin(); + + private static Menu menu = new Menu("Debug"); + + private static CheckboxMenuItem traceConstructors = + new CheckboxMenuItem("trace constructors", false); + private static CheckboxMenuItem traceInitializations = + new CheckboxMenuItem("trace initializations", false); + private static CheckboxMenuItem traceMethods = + new CheckboxMenuItem("trace methods", false); + private static CheckboxMenuItem traceClockTick = + new CheckboxMenuItem("trace clock tick", false); + private static CheckboxMenuItem traceRegistry = + new CheckboxMenuItem("trace registry", true); + private static CheckboxMenuItem traceFireCollideDamage = + new CheckboxMenuItem("trace fire, collide, damage", true); + + after() returning (SWFrame frame): call(SWFrame+.new(..)) { + menu.add(traceConstructors); + menu.add(traceInitializations); + menu.add(traceMethods); + menu.add(traceClockTick); + menu.add(traceRegistry); + menu.add(traceFireCollideDamage); + frame.getMenuBar().add(menu); + } + + /* + * all constructors + */ + pointcut allConstructorsCut(): + call((spacewar.* && !(Debug+ || InfoWin+)).new(..)); + + before(): allConstructorsCut() { + if (traceConstructors.getState()) { + infoWin.println("begin constructing " + thisJoinPoint.getSignature()); + } + } + + after(): allConstructorsCut() { + if (traceConstructors.getState()) { + infoWin.println("done constructing " + thisJoinPoint.getSignature()); + } + } + + /* + * All dynamic initializations + */ + pointcut allInitializationsCut(): + initialization((spacewar.* && !(Debug+ || InfoWin+)).new(..)); + + before(): allInitializationsCut() { + if (traceConstructors.getState()) { + infoWin.println("begin initializing " + thisJoinPoint.getSignature()); + } + } + after(): allInitializationsCut() { + if (traceConstructors.getState()) { + infoWin.println("done initializing " + thisJoinPoint.getSignature()); + } + } + + /* + * all methods + */ + pointcut allMethodsCut(): + execution(* (spacewar.* && !(Debug+ || InfoWin+)).*(..)); + + before(): allMethodsCut() { + if (traceMethods.getState()) { + infoWin.println("entering " + thisJoinPoint.getSignature()); + } + } + after(): allMethodsCut() { + if (traceMethods.getState()) { + infoWin.println("exiting " + thisJoinPoint.getSignature()); + } + } + + /* + * clock ticks + */ + after(Object obj): + (target(obj) && (target(Game) || + target(Registry) || + target(SpaceObject))) + && call(void clockTick()) { + if (traceClockTick.getState()) + infoWin.println("ticking " + obj); + } + + /* + * registry contents + */ + after(Registry registry): + target(registry) && (call(void register(..)) || + call(void unregister(..))) { + if (traceRegistry.getState()) + infoWin.println(registry.getTable().size() + + " space objects in the registry."); + } + + /* + * fire, collide, damage + */ + after(): call(void Ship.fire()) { + if (traceFireCollideDamage.getState()) + infoWin.println("firing"); + } + + after(Ship ship, SpaceObject obj): + call(void Ship.handleCollision(SpaceObject)) && target(ship) && args(obj) { + if (traceFireCollideDamage.getState()) + infoWin.println(ship + " collides with " + obj); + } + + after(Ship shipA, Ship shipB): + execution(void Ship.bounce(Ship, Ship)) && args(shipA, shipB) { + if (traceFireCollideDamage.getState()) + infoWin.println(shipA + " bounces with " + shipB); + } + + before(Ship ship, double amount): + call(void Ship.inflictDamage(double)) && target(ship) && args(amount) { + if (traceFireCollideDamage.getState()) + if (amount > 0) + infoWin.println(ship + "gets " + + amount + " damage (" + + ship.getDamage() + ")"); + } + +} + +class InfoWin { + private Frame frame; + private TextArea info; + + InfoWin() { + frame = new Frame("debugging info for spacewar game"); + info = new TextArea(); + info.setEditable(false); + + Dimension screenSize = frame.getToolkit().getScreenSize(); + frame.setSize(250, 600); + frame.setLocation(screenSize.width - 250, 0); + frame.add(info); + frame.show(); + frame.toFront(); + } + + void clear() { + info.setText(""); + } + + void println(String line) { + info.append(line + "\n"); + } + + void print(String line) { + info.append(line); + } +} diff --git a/docs/dist/examples/spacewar/Display.java b/docs/dist/examples/spacewar/Display.java new file mode 100644 index 000000000..a0f77b347 --- /dev/null +++ b/docs/dist/examples/spacewar/Display.java @@ -0,0 +1,166 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +Display.java +Part of the Spacewar system. +*/ + +package spacewar; + +import java.util.Vector; +import java.util.Enumeration; +import java.awt.Graphics; +import java.awt.Canvas; +import java.awt.Image; +import java.awt.event.KeyListener; + +/** + * The display aspects capture the look and feel of the Game in modular + * pluggable units. + * + * The model is that constructing a concrete subclass of Display attaches that + * kind of display to the game. It will Display the game as it goes along. + * A game can have any number of displays. Any of the displays will accept + * keyboard input. + * + */ + +class Display extends Canvas { + + private static Vector DISPLAYS = new Vector(2); + private static Vector PLAYERS = new Vector(2); + private static Pilot pilot1, pilot2; + + Game game; + SWFrame frame; + Image offImage; + Graphics offGraphics; + + Game getGame() { return game; } + static Pilot getPilot1() { return pilot1; } + static Pilot getPilot2() { return pilot2; } + + Display(Game g) { + super(); + game = g; + + frame = new SWFrame(game, this); + DISPLAYS.addElement(this); + } + + + void noticeSizeChange() { + initializeOffImage(); + } + + private void initializeOffImage () { + int w = getSize().width; + int h = getSize().height; + if ( w > 0 & h > 0) { + offImage = createImage(w, h); + offGraphics = offImage.getGraphics(); + } + } + + /* + * In our double buffering scheme, painting just means copying the buffer + * to the screen. The Display aspect draws into the buffer. + */ + public void paint(Graphics g) { + if (offImage != null) + g.drawImage(offImage, 0, 0, null); + } + + public void update(Graphics g) { + /* + * There are 4 steps to this: + * - clear the double buffer + * - paint the objects into the double buffer + * - paint the status into the double buffer + * - paint the doublebuffer into the buffer + */ + offGraphics.setColor(getBackground()); + offGraphics.fillRect(0, 0, getBounds().width, getBounds().height); + paintObjects(offGraphics); + paintStatus(offGraphics); + g.drawImage(offImage, 0, 0, null); + } + + void paintObjects(Graphics g) { } + void paintStatus(Graphics g) {} + + static aspect DisplayAspect { + + after (String mode) returning (Game game): call(Game+.new(String)) && args(mode) { + new Display1(game); + new Display2(game); + + if ( mode.equals("1") ) { + pilot1 = game.newPlayer(1); + } + else if ( mode.equals("2") ) { + pilot1 = game.newPlayer(1); + pilot2 = game.newPlayer(2); + } + else if (mode. equals("demo")) { + pilot1 = game.newRobot(1); + pilot2 = game.newRobot(2); + } else { + game.error("Invalid mode: " + mode); + game.quit(); + } + } + + + /* + * I'm not really sure this belongs here. + * + * Being here what it does is makes the Display aspect + * responsible for having the Players couple up to it. That's + * kind of nice, but its a bit incomplete, since Player is + * really part of the GUI, not part of the core Game. + * + * In a future re-factoring this will get worked out better. + * What will happen is that GUI will be an aspect that has the + * core GUI. Each of the different kinds of displays will be + * aspects that tie themselves in. + */ + after () returning (Player player): call(Player+.new(..)) { + Enumeration elements = DISPLAYS.elements(); + while ( elements.hasMoreElements() ) { + Display display = (Display)elements.nextElement(); + display.addKeyListener(player); + } + } + + after() returning (Display display): call(Display+.new(..)) { + display.noticeSizeChange(); + } + + after(Display display) returning (): call(void setSize(..)) && target(display) { + display.noticeSizeChange(); + } + + after(): call(void Game.clockTick()) { + Enumeration elements = DISPLAYS.elements(); + while ( elements.hasMoreElements() ) { + Display display = (Display)elements.nextElement(); + display.repaint(); + } + } + } +} diff --git a/docs/dist/examples/spacewar/Display1.java b/docs/dist/examples/spacewar/Display1.java new file mode 100644 index 000000000..484a2342a --- /dev/null +++ b/docs/dist/examples/spacewar/Display1.java @@ -0,0 +1,203 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +Display1.java +Part of the Spacewar system. +*/ + +package spacewar; + + +import java.util.Vector; +import java.util.Enumeration; +import java.awt.Graphics; +import java.awt.Color; +import java.util.Random; + +/** + * This is the standard display aspect. + */ +class Display1 extends Display { + /* + * Here's the color scheme for the game. No other places in this file + * should say Color.xxx. Instead, that color should be given a symbolic + * name here. + */ + private static Color backgroundColor = Color.black; + private static Color player1ShipColor = Color.white; + private static Color player2ShipColor = Color.gray; + private static Color robotShipColor = new Color(0xa00000); + private static Color flameColor = Color.red; + private static Color shipExplosionColor = Color.red; + private static Color bulletColor = Color.green; + private static Color energyPacketOuterColor = Color.blue; + private static Color energyPacketInnerColor = new Color(0x7070FF); + private static Color statusLabelsColor = Color.white; + private static Color statusMeterBorderColor = Color.white; + private static Color energyStatusMeterColor = Color.blue; + private static Color damageStatusMeterColor = Color.red; + + + Display1(Game game) { + super(game); + frame.setLocation(20, 20); + } + + void noticeSizeChange() { + super.noticeSizeChange(); + setBackground(backgroundColor); + } + + void paintObjects(Graphics g) { + SpaceObject[] objects = game.getRegistry().getObjects(); + final int len = objects.length; + for (int i = 0; i < len; i++) { + objects[i].paint(g); + } + } + + static aspect SpaceObjectPainting { + + abstract private void SpaceObject.paint(Graphics g); + + /* + * Ships are by far and away the most complex of the space Objects + * to paint. First off, we need to set the color when the ship + * is made. + */ + private Color Ship.color; + + after(Pilot pilot) returning (Ship ship): call(Ship Game.newShip(Pilot)) && args(pilot) { + if (pilot.getNumber() == 1) + ship.color = player1ShipColor; + else if (pilot.getNumber() == 2) + ship.color = player2ShipColor; + else + ship.color = robotShipColor; + } + + private void Ship.paint(Graphics g) { + final double PI = Math.PI; + int[] radius = {15, 12, -4, 12, -9, -15, -9}; + double[] angle = {0, PI * 3/4, 0, -PI * 3/4, PI/8, 0, -PI/8}; + int[] x; + int[] y; + + Random random = new Random(); + + if (this.getDamage() >= this.MAX_DAMAGE) { + int lines = 20; + x = new int[lines]; + y = new int[lines]; + g.setColor(shipExplosionColor); + for (int i = 0; i < lines; i++) { + x[i] = (int)(this.getXPos()) + random.nextInt() % 20; + y[i] = (int)(this.getYPos()) + random.nextInt() % 20; + } + for (int i = 0; i < lines; i++) + g.drawLine(x[i], y[i], x[(i + 1) % lines], y[(i + 1) % lines]); + } else { + x = new int[7]; + y = new int[7]; + + g.setColor(this.color); + + radius[5] += random.nextInt() % 3; + // convert coordinates from polar to cartesian + for (int i = 0; i < 7; i++) { + x[i] = (int) + (this.getXPos() + + Math.cos(this.getOrientation() + angle[i]) * radius[i]); + y[i] = (int) + (this.getYPos() + + Math.sin(this.getOrientation() + angle[i]) * radius[i]); + } + + // draw the body as a polygon + g.drawPolygon(x, y, 4); + + // if the ship is accelerating, draw in a flame + if (this.getRAcc() != 0) { + g.setColor(flameColor); + g.drawLine(x[4], y[4], x[5], y[5]); + g.drawLine(x[5], y[5], x[6], y[6]); + } + } + } + + /* + * Bullets + */ + private void Bullet.paint(Graphics g) { + g.setColor(bulletColor); + g.fillOval((int)this.getXPos() - 1, + (int)this.getYPos() - 1, + 3, + 3); + } + + /* + * energy packets + */ + private void EnergyPacket.paint(Graphics g) { + g.setColor(energyPacketOuterColor); + g.fillOval((int)this.getXPos() - 5, + (int)this.getYPos() - 5, + 10, 10); + g.setColor(energyPacketInnerColor); + g.fillOval((int)this.getXPos() - 2, + (int)this.getYPos() - 2, + 3, 3); + } + } + + + void paintStatus(Graphics g) { + int left1 = 60; + int top1 = 0; + + int left2 = 200; + int top2 = 0; + + g.setColor(statusLabelsColor); + g.drawString("energy:", 5, top1 + 15); + g.drawString("damage:", 5, top1 + 30); + + if (getPilot1() != null) + paintLevels(g, getPilot1().getShip(), top1, left1); + if (getPilot2() != null) + paintLevels(g, getPilot2().getShip(), top2, left2); + } + + static void paintLevels(Graphics g, Ship ship, int top, int left) { + if (ship == null) + return; + else if (ship.isAlive()) { + g.setColor(statusMeterBorderColor); + g.drawRect(left, top + 6, 101, 10); + g.drawRect(left, top + 21, 101, 10); + g.setColor(energyStatusMeterColor); + g.fillRect(left + 1, top + 7, (int)(ship.getEnergyLevel()*100), 9); + g.setColor(damageStatusMeterColor); + g.fillRect(left + 1, top + 22, (int)(ship.getDamageLevel()*100), 9); + } + else { + g.setColor(damageStatusMeterColor); + g.drawString("Ship is destroyed", left+1, top+15); + } + } +} diff --git a/docs/dist/examples/spacewar/Display2.java b/docs/dist/examples/spacewar/Display2.java new file mode 100644 index 000000000..d2dbeb40e --- /dev/null +++ b/docs/dist/examples/spacewar/Display2.java @@ -0,0 +1,138 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +Display2.java +Part of the Spacewar system. +*/ + +package spacewar; + + +import java.util.Vector; +import java.util.Enumeration; +import java.awt.Graphics; +import java.awt.Color; + + +/** + * This is the cheap Display aspect. + */ +class Display2 extends Display { + + Display2(Game game) { + super(game); + frame.setLocation(540, 20); + } + + void noticeSizeChange() { + super.noticeSizeChange(); + setBackground(Color.darkGray); + } + + void paintObjects(Graphics g) { + SpaceObject[] objects = game.getRegistry().getObjects(); + final int len = objects.length; + for (int i = 0; i < len; i++) { + objects[i].paint(g); + } + } + + static aspect SpaceObjectPainting { + + abstract private void SpaceObject.paint(Graphics g); + + /* + * Ships are by far and away the most complex of the space Objects + * to paint. + */ + private Color Ship.color; + + after(Pilot pilot) returning (Ship ship): call(Ship Game.newShip(Pilot)) && args(pilot) { + if (pilot.getNumber() == 1) + ship.color = Color.white; + else if (pilot.getNumber() == 2) + ship.color = Color.gray; + else + ship.color = new Color(0xa00000); + } + + private void Ship.paint(Graphics g) { + if (this.getDamage() < this.MAX_DAMAGE) { + double x = this.getXPos(); + double y = this.getYPos(); + double sinTheta = Math.sin(this.getOrientation()); + double cosTheta = Math.cos(this.getOrientation()); + + g.setColor(color); + g.drawLine((int)(x + 8*cosTheta), (int)(y + 8*sinTheta), + (int)(x - 8*cosTheta), (int)(y - 8*sinTheta)); + + // if the ship is accelerating, draw thruster + if (this.getRAcc() != 0) { + g.setColor(Color.red); + g.fillOval((int)(x - 8*cosTheta), (int)(y - 8*sinTheta), 6, 6); + } + } + } + + private void Bullet.paint(Graphics g) { + g.setColor(Color.green); + g.fillOval((int)this.getXPos() - 1, + (int)this.getYPos() - 1, + 3, + 3); + } + + private void EnergyPacket.paint(Graphics g) { + g.setColor(Color.white); + g.fillOval((int)this.getXPos() - 5, + (int)this.getYPos() - 5, + 10, + 10); + } + } + + void paintStatus(Graphics g) { + int left1 = 60; + int top1 = 0; + + int left2 = 200; + int top2 = 0; + + g.setColor(Color.white); + g.drawString("energy:", 5, top1 + 15); + g.drawString("damage:", 5, top1 + 30); + + if (getPilot1() != null) + paintLevels(g, getPilot1().getShip(), top1, left1); + if (getPilot2() != null) + paintLevels(g, getPilot2().getShip(), top2, left2); + } + + void paintLevels(Graphics g, Ship ship, int top, int left) { + if (ship == null) + return; + else if (ship.isAlive()) { + g.drawString(Float.toString(ship.getEnergyLevel()*100), left+1, top+15); + g.drawString(Float.toString(ship.getDamageLevel()*100), left+1, top+30); + } + else { + g.setColor(Color.red); + g.drawString("Ship is destroyed", left+1, top+15); + } + } +} diff --git a/docs/dist/examples/spacewar/EnergyPacket.java b/docs/dist/examples/spacewar/EnergyPacket.java new file mode 100644 index 000000000..d7bc4f9ec --- /dev/null +++ b/docs/dist/examples/spacewar/EnergyPacket.java @@ -0,0 +1,44 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +EnergyPacket.java +Part of the Spacewar system. + +*/ + +package spacewar; + + +class EnergyPacket extends SpaceObject { + + static private final int SIZE = 5; //Can't be changed for now!!! + int getSize() { return SIZE; } + + private double energy; + + double getEnergy() { return energy; } + + EnergyPacket(Game theGame, + double xP, double yP, double xV, double yV, double e) { + super(theGame, xP, yP, xV, yV); + energy = e; + } + + void handleCollision(SpaceObject obj) { + die(); + } +} diff --git a/docs/dist/examples/spacewar/EnergyPacketProducer.java b/docs/dist/examples/spacewar/EnergyPacketProducer.java new file mode 100644 index 000000000..efd276042 --- /dev/null +++ b/docs/dist/examples/spacewar/EnergyPacketProducer.java @@ -0,0 +1,63 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +EnergyPacketProducer.java +Part of the Spacewar system. + + This implementation creates booby-trapped packets 20% of the time. + +*/ + +package spacewar; + + +class EnergyPacketProducer extends Thread { + private final static int MIN = -20; + private final static int MAX = 80; + private final static int EXPECTEDINTERVAL = 15; + + private Game game; + + Game getGame() { return game; } + + EnergyPacketProducer(Game theGame) { + super("EnergyPacketProducer"); + game = theGame; + } + + public void run() { + while(true) { + produceAPacket(); + waitForABit(); + } + } + + void waitForABit() { + try { Thread.sleep((int)(Math.random() * EXPECTEDINTERVAL * 2000)); } + catch (InterruptedException e) {} + } + + void produceAPacket() { + EnergyPacket pkt = + new EnergyPacket(game, + Math.random() * getGame().getWidth(), + Math.random() * getGame().getHeight(), + Math.random() * 2 - 1, + Math.random() * 2 - 1, + Math.random() * (MAX - MIN) + MIN); + } +} diff --git a/docs/dist/examples/spacewar/EnsureShipIsAlive.java b/docs/dist/examples/spacewar/EnsureShipIsAlive.java new file mode 100644 index 000000000..f7b949a92 --- /dev/null +++ b/docs/dist/examples/spacewar/EnsureShipIsAlive.java @@ -0,0 +1,35 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +Ship.java +Part of the Spacewar system. + +*/ + +package spacewar; + +/** + * This aspect makes sure that the ship is alive before performing any console + * commands. + * + */ +aspect EnsureShipIsAlive { + void around (Ship ship): Ship.helmCommandsCut(ship) { + if ( ship.isAlive() ) { + proceed(ship); + } + } +} diff --git a/docs/dist/examples/spacewar/Game.java b/docs/dist/examples/spacewar/Game.java new file mode 100644 index 000000000..da67d7bc3 --- /dev/null +++ b/docs/dist/examples/spacewar/Game.java @@ -0,0 +1,215 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +Game.java +Part of the Spacewar system. + +*/ + +package spacewar; + +import java.awt.Dimension; + +/** + * The Game class is the root of the spacewar game. To start a spacewar + * game, you can either call the main method, or instantiate this class + * directly. + * + * Synchronization is done by the GameSynchronization aspect. + */ +public class Game extends Thread { + + /** + * To run the game from top level, simply say Java Game, as usual. Passing + * an argument makes the game run in demo mode. Without an argument it runs + * in the normal player mode. + */ + public static void main(String[] args) { + if ( args.length == 0 ) + new Game("1").run(); + new Game(args[0]).run(); + } + + + private Timer timer; + private EnergyPacketProducer ePP; + + private Registry registry; + private Pilot pilot1, pilot2; + + private Dimension screenSize = new Dimension(500, 500); + + Registry getRegistry() { return registry; } + Pilot getPilot1() { return pilot1; } + Pilot getPilot2() { return pilot2; } + + /** returns the width of the screen, delegating to screenSize */ + int getWidth() { return screenSize.width; } + + /** returns the height of the screen, delegating to screenSize */ + int getHeight() { return screenSize.height; } + + /** + * To run the game, simply instantiate this class. It runs in its own + * thread. You can instantiate multiple games at once. For the time being + * the only way to end the game is to exit from the Java VM. + * + * @param isDemo Controls whether the game runs in demo mode or not. True + * means it is a demo, false means it runs in normal 2 player mode. + */ + public Game(String mode) { + timer = new Timer(this); + ePP = new EnergyPacketProducer(this); + registry = new Registry(this); + } + + public void run() { + timer.start(); + ePP.start(); + + while(true) { + try { + newRobot(3); + Thread.sleep(15000); + } + catch (InterruptedException e) {} + } + } + + + /** + * add a robot to the game. This is a menu command. + */ + void addRobot() { + newRobot(3); + } + + /** + * resurrect the ships in the game. This is a menu command. + */ + void resetShips() { + Ship[] ships = registry.getShips(); + + for (int i = 0; i < ships.length; i++) { + Ship ship = ships[i]; + Pilot pilot = ship.getPilot(); + newShip(pilot); + } + } + + /** + * leave the game. This is a menu command. + */ + void quit() { + System.exit(0); + } + + void error(Object o) { + System.err.println(o); + } + + + /** + * returns a new player. With {@link #newRobot} and {@link + * #newShip}, the only ways to make a Player, a Robot, or a Ship. + * The structural invariant is that there should be no calls to + * new of one of these three classes outside these three methods. + */ + Player newPlayer(int number) { + Player player = new Player(this, number); + newShip(player); + return player; + } + + /** + * returns a new robot. With {@link #newPlayer} and {@link + * #newShip}, the only ways to make a Player, a Robot, or a Ship. + * The structural invariant is that there should be no calls to + * new of one of these three classes outside these three methods. + */ + Robot newRobot(int number) { + Robot robot = new Robot(this, number); + newShip(robot); + robot.start(); + return robot; + } + + /** + * returns a new ship. With {@link #newRobot} and {@link + * #newPlayer}, the only ways to make a Player, a Robot, or a + * Ship. The structural invariant is that there should be no + * calls to new of one of these three classes outside these three + * methods. + */ + Ship newShip(Pilot pilot) { + // + // If there is an old ship (we're doing a reset), then remove it from + // the registry. + // + Ship oldShip = pilot.getShip(); + if (! (oldShip == null)) + oldShip.die(); + + Ship newShip = new Ship(this, + Math.random() * getWidth(), + Math.random() * getHeight(), + Math.random() * Math.PI * 2); + pilot.setShip(newShip); + newShip.setPilot(pilot); + + return newShip; + } + + void clockTick() { + registry.clockTick(); + handleCollisions(); + } + + // collision detection + + void handleCollisions() { + SpaceObject[] objects = registry.getObjects(); + + SpaceObject objI, objJ; + for (int i = 0; i < objects.length; i++) { + objI = objects[i]; + for (int j = i + 1; j < objects.length; j++) { + objJ = objects[j]; + if (objI instanceof Bullet && objJ instanceof Bullet) + continue; + if (isCollision(objI, objJ)) { + if (objI instanceof Ship && objJ instanceof Ship) + Ship.bounce((Ship)(objI), (Ship)(objJ)); + else { + objI.handleCollision(objJ); + objJ.handleCollision(objI); + } + } + } + } + } + + /* + * Is the distance between the two centers less than the sum of the two + * radii. This is a cheap and dirty (i.e. wrong) implementation of this. + */ + static boolean isCollision(SpaceObject a, SpaceObject b) { + return (Math.abs(a.getXPos() - b.getXPos()) + + Math.abs(a.getYPos() - b.getYPos())) < + (a.getSize()/2 + b.getSize()/2); + } +} diff --git a/docs/dist/examples/spacewar/GameSynchronization.java b/docs/dist/examples/spacewar/GameSynchronization.java new file mode 100644 index 000000000..dcf42e904 --- /dev/null +++ b/docs/dist/examples/spacewar/GameSynchronization.java @@ -0,0 +1,54 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +RegistrySynchronization.java +Part of the Spacewar system. + +*/ + +package spacewar; + +import coordination.Coordinator; + +/** + * This aspect ensures synchronized access to methods of the Game in the + * presence of several threads. + * + * It uses the Coordinator class, from the AspectJ coordination library. + * (This case is right on the borderline of being too simple to use the + * coordination library, but we use it anyways to keep the similarity + * with the RegistrySynchronizer.) + * + * It uses a per-Game coordination scheme, so there is one instance of + * this class for each instance of the Game class. When this class is + * constructed, it registers appropriate mutexes and selfexes using + * the behavior inherited from Coordinator. + * + * The coordination constraints for the Game are simple. We just need to + * make sure that newShip and handleCollisions are mutually exclusive. That + * ensures that they we can't destroy a ship that has just been replaced. + */ +aspect GameSynchronization extends Coordinator perthis(this(Game)) { + + protected pointcut synchronizationPoint(): + call(void Game.handleCollisions(..)) || call(Ship Game.newShip(..)); + + public GameSynchronization() { + addMutex(new String[] {"handleCollisions", "newShip"}); + } + +} diff --git a/docs/dist/examples/spacewar/Makefile b/docs/dist/examples/spacewar/Makefile new file mode 100644 index 000000000..108d3c8c4 --- /dev/null +++ b/docs/dist/examples/spacewar/Makefile @@ -0,0 +1,12 @@ +SHELL=bash +ACJOPTS=-verbose -nosymbols +AJC=ajc + +.PHONY: demo debug + +demo: + $(AJC) $(ACJOPTS) @demo.lst + +debug: + $(AJC) $(ACJOPTS) @debug.lst + diff --git a/docs/dist/examples/spacewar/Pilot.java b/docs/dist/examples/spacewar/Pilot.java new file mode 100644 index 000000000..330d860bf --- /dev/null +++ b/docs/dist/examples/spacewar/Pilot.java @@ -0,0 +1,44 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +*/ + +package spacewar; + + +/** + * Pilot is the abstract superclass of Player and Robot. + * + */ + +abstract class Pilot { + private Game game; + private int number; + protected Ship ship = null; + + Game getGame() { return game; } + int getNumber() { return number; } + Ship getShip() { return ship; } + + void setShip(Ship s) { ship = s; } + + Pilot (Game g, int n) { + super(); + game = g; + number = n; + } +} diff --git a/docs/dist/examples/spacewar/Player.java b/docs/dist/examples/spacewar/Player.java new file mode 100644 index 000000000..ebde6d5c4 --- /dev/null +++ b/docs/dist/examples/spacewar/Player.java @@ -0,0 +1,122 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +*/ + +package spacewar; + +import java.util.Enumeration; +import java.awt.event.KeyListener; +import java.awt.event.KeyEvent; + +class Player extends Pilot implements KeyListener { + + private KeyMapping keyMapping; + + /** current rotation key */ + private int rotation_direction = Ship.STOP; // current rotation key + + /** current thrust */ + private boolean thrust_on = false; + + Player(Game theGame, int number) { + super(theGame,number); + + if (getNumber() == 1) + keyMapping = KeyMapping.keyMapping1; + else if (getNumber() == 2) + keyMapping = KeyMapping.keyMapping2; + + } + + public void keyPressed(KeyEvent e) { + int keyCode = e.getKeyCode(); + boolean consumed = true; + + if (keyCode == keyMapping.fire) { + ship.fire(); + } + else if (keyCode == keyMapping.thrust && !thrust_on) { + ship.thrust(true); + thrust_on = true; + } + else if (keyCode == keyMapping.right && + rotation_direction != Ship.COUNTERCLOCKWISE) { + //start rotating clockwise unless already rotating in the + //opposite direction + rotation_direction = Ship.CLOCKWISE; + ship.rotate(Ship.CLOCKWISE); + } + else if (keyCode == keyMapping.left && + rotation_direction != Ship.CLOCKWISE) { + //start rotating counterclockwise unless already rotating in the + //opposite direction + rotation_direction = Ship.COUNTERCLOCKWISE; + ship.rotate(Ship.COUNTERCLOCKWISE); + } + else { + consumed = false; + } + + if (consumed) e.consume(); + } + + public void keyReleased(KeyEvent e) { + int keyCode = e.getKeyCode(); + + if (keyCode == keyMapping.thrust) { + ship.thrust(false); //engine off + thrust_on = false; + } + else if (keyCode == keyMapping.right && + rotation_direction == Ship.CLOCKWISE + || + keyCode == keyMapping.left && + rotation_direction == Ship.COUNTERCLOCKWISE) { + ship.rotate(Ship.STOP); //stop rotation + rotation_direction = Ship.STOP; + } + } + + public void keyTyped(KeyEvent e) { + // have to implement this because it's in KeyListener + } +} + +class KeyMapping { + + static final KeyMapping keyMapping1 = + new KeyMapping(KeyEvent.VK_LEFT, + KeyEvent.VK_RIGHT, + KeyEvent.VK_UP, + KeyEvent.VK_SPACE); + + static final KeyMapping keyMapping2 = + new KeyMapping(KeyEvent.VK_X, + KeyEvent.VK_V, + KeyEvent.VK_D, + KeyEvent.VK_ALT); + + int left, right, thrust, fire; + + KeyMapping(int k_left, int k_right, int k_thrust, int k_fire) { + left = k_left; + right = k_right; + thrust = k_thrust; + fire = k_fire; + } +} diff --git a/docs/dist/examples/spacewar/README.html b/docs/dist/examples/spacewar/README.html new file mode 100644 index 000000000..8b6a56910 --- /dev/null +++ b/docs/dist/examples/spacewar/README.html @@ -0,0 +1,79 @@ + + + + + + +Space War + + + + +

    © Copyright 1997-2001 Xerox Corporation. All rights +reserved.

    + +

    Last updated: January 10, 2001

    + +

     

    + + + +

    Exploring the Spacewar Example

    + +

    The code in this directory is an implementation of the +classic video game Spacewar.

    + +

    The Spacewar game is intended to provide a modest-sized example of +a program that uses aspects. The code for this example is evolving, +as we add new features to AspectJ and come up with a better +understanding of how to use the features.

    + +

    In order to compile and run this example, make sure to have the latest +version of AspectJ correctly installed. If you're not sure you do, try the +helloworld example first by following the instructions in Primer +section Getting Started.

    + +

    Compiling Spacewar

    + + + +

    Running Spacewar

    + + + +

    When the game starts up you will see two different displays. These +are the two built-in display aspects of the game. In each you will +see a single white ship and two red ships. The white ship is yours +to control; the red ships are an enemy robots. Your ship is controlled +with the four arrow keys to turn, thrust and stop; the spacebar +fires. As you play, the game will be displayed in both windows.

    + +

    You can quit the game with ctl-Q.

    + +

    Exploring the Code

    + +

    There is one other built-in configurations for the Spacewar game. +Try it by typing ajc @spacewar\debug.lst. This +compiles in an elaborate debugging aspect for the game. + +

    + +

    We recommend you explore the Spacewar source code and look at the +aspects that it uses. You will find several of them, of different +scales and different degrees of cross-cutting. Remember that these +represent our evolving understanding of how to use AspectJ to +implement Spacewar. If you believe we should be doing something +differently, then please let us know. +

    + + + + + diff --git a/docs/dist/examples/spacewar/Registry.java b/docs/dist/examples/spacewar/Registry.java new file mode 100644 index 000000000..a9cec0418 --- /dev/null +++ b/docs/dist/examples/spacewar/Registry.java @@ -0,0 +1,126 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +Registry.java +Part of the Spacewar system. + +*/ + +package spacewar; + +import java.util.Vector; +import java.util.Hashtable; +import java.util.Enumeration; + +/** + * The Registry keeps track of all the space objects that are floating around. + * It basically supports register, unregister and contents type operations. + * + * The synchronization is done by the RegistrySynchronization aspect. + */ + +class Registry { + + private Hashtable table; + private Game game; + + Game getGame() { return game; } + + Registry (Game theGame) { + game = theGame; + table = new Hashtable(); + } + + + void register(SpaceObject object) { + table.put(object, object); + } + + void unregister(SpaceObject object) { + table.remove(object); + } + + /* + * It is an invariant of the design that only two points in SpaceObject + * should call register and unregister. This aspect enforces that. + * + * Unfortunately, in the current compiler, we get a static warning when + * there are no illegal calls that this advice has no targets. That will + * be fixed in a future release. For the time being the dummy method + * just below this fixes that. + */ + static aspect RegistrationProtection { + after() returning(): + (call(void Registry.register(SpaceObject)) || + call(void Registry.unregister(SpaceObject))) && + !(within(SpaceObject) && (withincode(new(..)) || + withincode(void die()))) { + throw new IllegalAccessError( + "This is an illegal call to " + thisJoinPoint + "\n" + + "Only the constructor and the die() on SpaceObject\n" + + "should call the primitive registry operations."); + } + } + + void dummy() { // see comment above + register(getObjects()[0]); + unregister(getObjects()[0]); + } + + + SpaceObject[] getObjects() { + SpaceObject[] allObjects = new SpaceObject[table.size()]; + Enumeration elements = table.elements(); + for(int i = 0; elements.hasMoreElements(); i++) { + allObjects[i] = (SpaceObject)(elements.nextElement()); + } + return allObjects; + } + + Ship[] getShips() { + // + // First we have to put just the Ships into a vector, then we can put + // them into an array of exactly the right length. + // + Ship[] arrayOfShips; + Vector vectorOfShips = new Vector(); + Enumeration elements = table.elements(); + while (elements.hasMoreElements()) { + Object object = elements.nextElement(); + if (object instanceof Ship) { + vectorOfShips.addElement(object); + } + } + + arrayOfShips = new Ship[(vectorOfShips.size())]; + vectorOfShips.copyInto(arrayOfShips); + return arrayOfShips; + } + + Hashtable getTable() { return table; } + + // + // The protocol for clockTick is that it automatically cascades. + // + void clockTick() { + Enumeration elements = table.elements(); + while (elements.hasMoreElements()) { + ((SpaceObject)elements.nextElement()).clockTick(); + } + } +} + diff --git a/docs/dist/examples/spacewar/RegistrySynchronization.java b/docs/dist/examples/spacewar/RegistrySynchronization.java new file mode 100644 index 000000000..986e4bd30 --- /dev/null +++ b/docs/dist/examples/spacewar/RegistrySynchronization.java @@ -0,0 +1,58 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +RegistrySynchronization.java +Part of the Spacewar system. + +*/ + +package spacewar; + +import coordination.Coordinator; + + +/** + * This aspect ensures synchronized access to methods of the Registry in + * the presence of several threads. + * + * It uses the Coordinator class, from the AspectJ coordination library. + * + * It uses a per-Registry coordination scheme, so there is one instance of + * this class for each instance of the Registry class. When this class is + * constructed, it registers appropriate mutexes and selfexes using the + * behavior inherited from Coordinator. + * + * The mutating methods (register and unregister) should be self-exclusive. + * Each reader method should be mutually exclusive with the mutating + * methods. But the readers can run concurrently. */ +aspect RegistrySynchronization extends Coordinator perthis(this(Registry)) { + + protected pointcut synchronizationPoint(): + call(void Registry.register(..)) || + call(void Registry.unregister(..)) || + call(SpaceObject[] Registry.getObjects(..)) || + call(Ship[] Registry.getShips(..)); + + public RegistrySynchronization() { + addSelfex("register"); + addSelfex("unregister"); + + addMutex(new String[] {"register", "unregister", "getObjects"}); + addMutex(new String[] {"register", "unregister", "getShips"}); + } + +} diff --git a/docs/dist/examples/spacewar/Robot.java b/docs/dist/examples/spacewar/Robot.java new file mode 100644 index 000000000..05f276108 --- /dev/null +++ b/docs/dist/examples/spacewar/Robot.java @@ -0,0 +1,201 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +Robot.java +Part of the Spacewar system. + +*/ + +package spacewar; + +import java.util.Random; + +/** + * Robot is an automatic pilot that now has quite a bit of intelligence. + * So, beware ! + */ +class Robot extends Pilot implements Runnable { + + private static final int FIRE_INTERVAL = 60; + private static final int REBIRTH_DELAY = 900; + + private final Random random = new Random(); + + private Thread runner; + private boolean runnable = true; + + Robot(Game theGame, int number) { + super(theGame, number); + } + + void start() { + if (runner == null) { + runner = new Thread(this); + runner.start(); + } + } + + void destroy() { + if (runner != null) { + runnable = false; + runner = null; + } + } + + + // A Robot tracks User-controlled ships and fires at them + public void run() { + Ship target = null; + + while(runnable) { + // find target ship + do { + Ship[] potentials = getGame().getRegistry().getShips(); + if(potentials.length != 0) + target = potentials[Math.abs(random.nextInt() % potentials.length)]; + sleepForABit(25); + } while (target == ship); + // main loop + int currentRotation = Ship.STOP; + int time; + boolean currentlyAccelerating = false; + double dx, dy, angleA, angleB, theta, dtheta, d, + targetVel, a, b, c, targetXVel, targetYVel; + + while(true) { + sleepForABit(FIRE_INTERVAL); + + // if my ship is destroyed, give me a new one + if (!ship.isAlive()) { + sleepForABit(REBIRTH_DELAY); + getGame().newShip(this); + } + + // find direction and distance from target to me + dx = ship.getXPos() - target.getXPos(); + if (dx < - getGame().getWidth() / 2) + dx += getGame().getWidth(); + if (dx > getGame().getWidth() / 2) + dx -= getGame().getWidth(); + dy = ship.getYPos() - target.getYPos(); + if (dy < - getGame().getHeight() / 2) + dy += getGame().getHeight(); + if (dy > getGame().getHeight() / 2) + dy -= getGame().getHeight(); + d = Math.sqrt(dx * dx + dy * dy); + angleA = Math.atan(dy / dx); + if (dx < 0) + angleA += Math.PI; + + // find relative velocity and trajectory of target + targetXVel = target.getXVel() - ship.getXVel(); + targetYVel = target.getYVel() - ship.getYVel(); + targetVel = Math.sqrt(targetXVel * targetXVel + + targetYVel * targetYVel); + angleB = Math.atan(targetYVel / targetXVel); + if (targetXVel < 0) + angleB+=Math.PI; + + // find angle between line to target and taget's direction of travel + theta = (angleA - angleB) % (2 * Math.PI); + if (theta < -Math.PI) + theta += 2 * Math.PI; + if (theta > Math.PI) + theta -= 2 * Math.PI; + + // calculate time to bullet impact using law of cosines + a = targetVel * targetVel + Ship.BULLET_SPEED * Ship.BULLET_SPEED; + b = d * targetVel * Math.cos(theta); + c = - d * d; + time = (int)((-b + Math.sqrt(b * b - 4 * a * c)) / 2 / a); + + // calculate angle and distance to bullet impact location + dx = targetXVel * time - dx; + dy = targetYVel * time - dy; + theta = Math.atan(dy / dx); + if(dx < 0) + theta += Math.PI; + + // find desired change in rotation + dtheta = (theta - ship.getOrientation()) % (2 * Math.PI); + // find the shortest path to the desired orientation; + if(dtheta < - Math.PI) + dtheta += 2 * Math.PI; + if(dtheta > Math.PI) + dtheta -= 2 * Math.PI; + + // turn if nessecary + if (dtheta > Ship.DEFAULT_ANGULAR_VELOCITY / 2) { + if (currentRotation != Ship.CLOCKWISE) + ship.rotate(currentRotation = Ship.CLOCKWISE); + } + else if (dtheta < -Ship.DEFAULT_ANGULAR_VELOCITY / 2) { + if (currentRotation != Ship.COUNTERCLOCKWISE) + ship.rotate(currentRotation = Ship.COUNTERCLOCKWISE); + } // otherwise, fire, maybe even a burst + else { + if(currentRotation != Ship.STOP) + ship.rotate(currentRotation = Ship.STOP); + if (random.nextInt() % 40 == 0) { + ship.fire(); + } + } + + // randomly accelerate + if (currentlyAccelerating && random.nextInt() % 2 == 0) + ship.thrust(currentlyAccelerating = false); + else { + if (ship.getXVel() == 0) + angleA = 0; + else + angleA = Math.atan(ship.getYVel() / ship.getXVel()); + + if (ship.getXVel() < 0) + angleA+=Math.PI; + angleB = (angleA - ship.getOrientation()) % (2 * Math.PI); + if (angleB < -Math.PI) + angleB += 2 * Math.PI; + if (angleB > Math.PI) + angleB -= 2 * Math.PI; + angleB = Math.abs(angleB); + + // angleB now represents the angle between the ship's + // orientation and velocity vector. This will be used to + // determine the probably that the ship will thrust to + // prevent ships from accelerating too much in one direction + if (random.nextInt() % (int)(12 * (Math.PI - angleB) + 1) == 0) + ship.thrust(currentlyAccelerating = true); + } + + // switch targets if current one has been destroyed + if (target.getDamage() == 100) + break; + + // randomly switch targets + if (random.nextInt() % 4000 == 0) + break; + } + } + } + + void sleepForABit (int time) { + try { + runner.sleep(time); + } + catch (InterruptedException e) {} + } +} diff --git a/docs/dist/examples/spacewar/SWFrame.java b/docs/dist/examples/spacewar/SWFrame.java new file mode 100644 index 000000000..6dfb9f6f6 --- /dev/null +++ b/docs/dist/examples/spacewar/SWFrame.java @@ -0,0 +1,92 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +SWFrame.java +Part of the Spacewar system. + +*/ + +package spacewar; + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Dimension; +import java.awt.Insets; + +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +class SWFrame extends Frame implements ActionListener { + private Game game; + private Display display; + private Menu menu; + + Game getGame() { return game; } + Display getDisplay() { return display; } + Menu getMenu() { return menu; } + + SWFrame(Game theGame, Display d) { + super("Space War!"); + + game = theGame; + + display = d; + add(display); + + // create menu + menu = new Menu("Game"); + MenuItem item1 = new MenuItem("Add Robot", new MenuShortcut('a')); + MenuItem item2 = new MenuItem("Reset Ships", new MenuShortcut('r')); + MenuItem item3 = new MenuItem("Quit", new MenuShortcut('q')); + item1.setActionCommand("Add Robot"); + item2.setActionCommand("Reset Ships"); + item3.setActionCommand("Quit"); + menu.add(item1); + menu.add(item2); + menu.add(item3); + menu.addActionListener(this); + + setMenuBar(new MenuBar()); + getMenuBar().add(menu); + + Dimension screenSize = new Dimension(500, 500); + setSize(screenSize); + setVisible(true); + toFront(); + + Insets inset = getInsets(); + int displayWidth = screenSize.width - inset.left - inset.right; + int displayHeight = screenSize.height - inset.top - inset.bottom; + display.setSize(displayWidth, displayHeight); + } + + public void actionPerformed(ActionEvent e) { + String s = e.getActionCommand(); + if (s.equals("Add Robot")) { + getGame().addRobot(); + } + else if (s.equals("Reset Ships")) { + getGame().resetShips(); + } + else if (s.equals("Quit")) { + getGame().quit(); + } + } +} diff --git a/docs/dist/examples/spacewar/Ship.java b/docs/dist/examples/spacewar/Ship.java new file mode 100644 index 000000000..9978fe694 --- /dev/null +++ b/docs/dist/examples/spacewar/Ship.java @@ -0,0 +1,296 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +Ship.java +Part of the Spacewar system. + +*/ + +package spacewar; + +class Ship extends SpaceObject { + + pointcut helmCommandsCut(Ship ship): + target(ship) && ( call(void rotate(int)) || + call(void thrust(boolean)) || + call(void fire()) ); + + + /** + * Energy and Damage are key values in the state of a ship. Energy is + * basically about fuel, and damage is about how bad a shape we are in. + * + * The energy related values are: + * + * The damage related values are: + * + * Finally, REPAIR_RATE is the rate at which energy is consumed to fix + * damage. + * + */ + private static final int MAX_ENERGY = 100; + private static final int BULLET_ENERGY= 2; + private static final double ACCELERATION_COST_FACTOR = 0.05; + + //XXX was private + static final int MAX_DAMAGE = 100; + private static final int BULLET_DAMAGE = 15; + private static final double COLLISION_DAMAGE_FACTOR = 0.1; + + private static final double REPAIR_RATE = 0.08; + + + private static final int EXPLOSION_LENGTH = 10; + + static final int BULLET_SPEED = 10; + + static final int CLOCKWISE = 1; + static final int STOP = 0; + static final int COUNTERCLOCKWISE = (-1); + + static final double DEFAULT_ANGULAR_VELOCITY = 0.2; + static final double DEFAULT_ACCELERATION = .4; + + static private final int SIZE = 30; //Can't be changed for now!!! + + private double energy; // range: 0 to MAX_ENERGY + private double damage; // range: 0 to MAX_DAMAGE + private double orientation; // in degrees + private double angularVel; // in ??? + private double xAcc, yAcc, rAcc; // + private int countdown; // remaining explosion time + + private Pilot pilot; + + Ship(Game theGame, double xPos, double yPos, double orientation) { + super(theGame, xPos, yPos, 0, 0); + xAcc = 0; + yAcc = 0; + this.orientation = orientation; + angularVel = 0; + + energy = MAX_ENERGY; + damage = 0; + countdown = EXPLOSION_LENGTH; + } + + + int getSize() { return SIZE; } + + double getEnergy() { return energy; } + double getDamage() { return damage; } + double getOrientation() { return orientation; } + double getRAcc() { return rAcc; } + + Pilot getPilot() { return pilot; } + void setPilot (Pilot p) { pilot = p; } + + float getEnergyLevel() { + return (float)energy / (float)MAX_ENERGY; + } + float getDamageLevel() { + return (float)damage / (float)MAX_DAMAGE; + } + + /** returns false if energy is out, otherwise decrements energy by amount + * and returns true + */ + boolean expendEnergy(double amount) { + if (amount <= energy) { + energy -= amount; + return true; + } + else + return false; + } + + /** increments damage by amount and handles the destruction of a ship if + * damage reaches MAX_DAMAGE. + */ + void inflictDamage(double amount) { + if (amount < 0) // shouldn't happen + return; + damage = Math.min(MAX_DAMAGE, damage + amount); + if (damage == MAX_DAMAGE) + setIsAlive(false); + } + + /** repairs some damage + */ + void repairDamage(double amount) { + if (amount < 0) // shouldn't happen + return; + if (damage == 0) + return; + damage = Math.max(0, damage - amount); + } + + public void clockTick() { + if (! isAlive()) { + // + // If we aren't alive, but we are still in the registry, it means + // we are exploding. countdown counts the length of the explosion. + // + if (--countdown == 0) + die(); + } + else { + if (angularVel != 0) { + orientation += angularVel; + xAcc = rAcc * Math.cos(orientation); + yAcc = rAcc * Math.sin(orientation); + } + setXVel(getXVel() + xAcc); + setYVel(getYVel() + yAcc); + + //expend energy + if (!expendEnergy(rAcc * ACCELERATION_COST_FACTOR)) + rAcc = xAcc = yAcc = 0; + + // fix damage + if (energy > 10 && damage > REPAIR_RATE) { + expendEnergy(REPAIR_RATE); + repairDamage(REPAIR_RATE); + } + } + super.clockTick(); + } + + /** + * First check to make sure we have enough energy to accelerate. If + * we do, then go ahead and do so. Acceleration is in the direction + * we are already facing (i.e. orientation). + */ + void setAcceleration(double acc) { + if (acc * ACCELERATION_COST_FACTOR <= energy) { + rAcc = acc; + xAcc = rAcc * Math.cos(orientation); + yAcc = rAcc * Math.sin(orientation); + } + } + + /** + * First check to make sure we have enough energy to rotate. If + * we do, then go ahead and do so. + */ + void setAngularVelocity(double omega) { + // changing direction of rotation takes energy + if (!expendEnergy(Math.abs(omega - angularVel) / 2)) + return; + //sets amount of degree rotation per clock tick, in radians; + //clockwise is positive + angularVel = omega; + } + + /** affect rotation thrusters. Direction can be one of {@link + * #CLOCKWISE}, {@link #COUNTERCLOCKWISE}, or zero for turning off + * the thrusters. + */ + void rotate(int direction) { + setAngularVelocity( + direction == CLOCKWISE ? DEFAULT_ANGULAR_VELOCITY : + direction == COUNTERCLOCKWISE ? -DEFAULT_ANGULAR_VELOCITY : + 0); + } + + /** turn on acceleration */ + void thrust(boolean onOff) { + setAcceleration(onOff ? DEFAULT_ACCELERATION : 0); + } + + /** create a bullet and fire it */ + void fire() { + // firing a shot takes energy + if (!expendEnergy(BULLET_ENERGY)) + return; + + //create a bullet object so it doesn't hit the ship that's firing it + double xV = getXVel() + BULLET_SPEED * (Math.cos(orientation)); + double yV = getYVel() + BULLET_SPEED * (Math.sin(orientation)); + + // create the actual bullet + new Bullet( + getGame(), + (getXPos() + ((getSize()/2 + 2) * (Math.cos(orientation))) + xV), + (getYPos() + ((getSize()/2 + 2) * (Math.sin(orientation))) + yV), + xV, + yV); + } + + + void handleCollision(SpaceObject obj) { + if (obj instanceof Ship) { + // should never be called. ship - ship collisions are handled in + // Ship.bounce(Ship shipA, Ship shipB) + } + else if (obj instanceof Bullet) { + inflictDamage(BULLET_DAMAGE); + } + else if (obj instanceof EnergyPacket) { + double packetEnergy = ((EnergyPacket)obj).getEnergy(); + energy = Math.max(0, Math.min(energy + packetEnergy, MAX_ENERGY)); + } + else { + System.err.println("collision with UFO!"); + } + } + + static void bounce(Ship shipA, Ship shipB) { + double dx, dy, denominator, + xAccA, yAccA, xAccB, yAccB, damage, + xComp, yComp, dvx, dvy; + + dx = Math.abs(shipA.getXPos() - shipB.getXPos()); + dy = Math.abs(shipA.getYPos() - shipB.getYPos()); + denominator = Math.sqrt(dx * dx + dy * dy); + xComp = dx / denominator; + yComp = dy / denominator; + xAccA = shipB.getXVel() * xComp + shipA.getXVel() * (1 - xComp) - + shipA.getXVel(); + yAccA = shipB.getYVel() * yComp + shipA.getYVel() * (1 - yComp) - + shipA.getYVel(); + xAccB = shipA.getXVel() * xComp + shipB.getXVel() * (1 - xComp) - + shipB.getXVel(); + yAccB = shipA.getYVel() * yComp + shipB.getYVel() * (1 - yComp) - + shipB.getYVel(); + shipA.accelerate(xAccA, yAccA); + shipB.accelerate(xAccB, yAccB); + dvx = shipA.getXVel() - shipB.getXVel(); + dvy = shipA.getYVel() - shipA.getYVel(); + damage = COLLISION_DAMAGE_FACTOR * (dvx * dvx + dvy * dvy); + shipA.inflictDamage(damage); + shipB.inflictDamage(damage); + + // !!! + // !!! poopers! this does a local time warp. this has to be a + // !!! violation of the clockTick protocol + // !!! + while (Game.isCollision(shipA, shipB)) { + shipA.clockTick(); + shipB.clockTick(); + } + } +} diff --git a/docs/dist/examples/spacewar/SpaceObject.java b/docs/dist/examples/spacewar/SpaceObject.java new file mode 100644 index 000000000..ee3afabcc --- /dev/null +++ b/docs/dist/examples/spacewar/SpaceObject.java @@ -0,0 +1,106 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +SpaceObject.java +Part of the Spacewar system. + +*/ + +package spacewar; + + +/** + * SpaceObjects are objects that float around in space. They support the + * minimal SpaceObject protocol, having to do with position, velocity, + * size and liveness. They are constructed with game, position, velocity + * and size. When constructed, a spaceobject adds itself to the registry. + * + * When it dies, a spaceobject removes itself from the registry. But note + * that it doesn't decide when to die, subclasses do that. + * + * The display aspects actually draw the space object on the screen and say + * how much space it takes up there. + */ +abstract class SpaceObject { + + private Game game; + private double xPos, yPos, oldXPos, oldYPos, xVel, yVel; + private boolean alive; + + SpaceObject (Game theGame, double xP, double yP, double xV, double yV) { + game = theGame; + xPos = xP; + yPos = yP; + oldXPos = xP; + oldYPos = yP; + xVel = xV; + yVel = yV; + + alive = true; + getGame().getRegistry().register(this); + } + + Game getGame() { return game; } + + double getXPos() { return xPos; } + double getYPos() { return yPos; } + + double getOldXPos() { return oldXPos; } + double getOldYPos() { return oldYPos; } + + double getXVel() { return xVel; } + double getYVel() { return yVel; } + + void setXVel (double n) { xVel = n; } + void setYVel (double n) { yVel = n; } + + boolean isAlive() { return alive; } + void setIsAlive(boolean n) { alive = n; } + + + /** + * Move 1 unit of time's worth of distance. I.e. increment xPos by xVel + * and yPos by yVel. If we move off an edge of the screen move us back + * in the opposite edge. + */ + void clockTick() { + oldXPos = xPos; + oldYPos = yPos; + xPos = (xPos + xVel) % getGame().getWidth(); + if(xPos < 0) + xPos += getGame().getWidth(); + yPos = (yPos + yVel) % getGame().getHeight(); + if(yPos < 0) + yPos += getGame().getHeight(); + } + + void accelerate(double dXVel, double dYVel) { + xVel += dXVel; + yVel += dYVel; + } + + void die() { + getGame().getRegistry().unregister(this); + } + + abstract int getSize(); + + /** resolve the effects of colliding with a space object. + * @param obj the space object that this object is colliding with. + */ + abstract void handleCollision(SpaceObject obj); +} diff --git a/docs/dist/examples/spacewar/Timer.java b/docs/dist/examples/spacewar/Timer.java new file mode 100644 index 000000000..1f4a992a7 --- /dev/null +++ b/docs/dist/examples/spacewar/Timer.java @@ -0,0 +1,53 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + + +Timer.java +Part of the Spacewar system. + +*/ + +package spacewar; + + +class Timer extends Thread { + + private final static int TICK_PERIOD = 40; // time between ticks in millis + + private Game game; + + Game getGame() { return game; } + + Timer (Game theGame) { + super("Timer"); + game = theGame; + } + + public void run() { + long t1, tdiff; + while (true) { + t1 = System.currentTimeMillis(); + getGame().clockTick(); + tdiff = System.currentTimeMillis() - t1; + if (tdiff < TICK_PERIOD) { + try { + sleep (Math.max(0 , TICK_PERIOD - tdiff)); + } + catch (InterruptedException e) { } + } + } + } +} diff --git a/docs/dist/examples/telecom/AbstractSimulation.java b/docs/dist/examples/telecom/AbstractSimulation.java new file mode 100644 index 000000000..1c44af7a7 --- /dev/null +++ b/docs/dist/examples/telecom/AbstractSimulation.java @@ -0,0 +1,80 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; + +public abstract class AbstractSimulation { + + public static AbstractSimulation simulation; + + /** + * Creates objects and puts them to work. + */ + public void run() { + Customer jim = new Customer("Jim", 650); + Customer mik = new Customer("Mik", 650); + Customer crista = new Customer("Crista", 415); + + say("jim calls mik..."); + Call c1 = jim.call(mik); + wait(1.0); + say("mik accepts..."); + mik.pickup(c1); + wait(2.0); + say("jim hangs up..."); + jim.hangup(c1); + report(jim); + report(mik); + report(crista); + + say("mik calls crista..."); + Call c2 = mik.call(crista); + say("crista accepts..."); + crista.pickup(c2); + wait(1.5); + say("crista hangs up..."); + crista.hangup(c2); + report(jim); + report(mik); + report(crista); + } + + /** + * Print a report of the connection time for customer + */ + abstract protected void report(Customer c); + + /** + * Wait 0.1 seconds per "second" for simulation + */ + protected static void wait(double seconds) { + Object dummy = new Object(); + synchronized (dummy) { + //XXX cheat and only wait 0.1 seconds per second + try {dummy.wait((long)(seconds*100)); } + catch (Exception e) {} + } + } + + /** + * Put a message on standard output + */ + protected static void say(String s){ + System.out.println(s); + } + +} diff --git a/docs/dist/examples/telecom/BasicSimulation.java b/docs/dist/examples/telecom/BasicSimulation.java new file mode 100644 index 000000000..ab7426376 --- /dev/null +++ b/docs/dist/examples/telecom/BasicSimulation.java @@ -0,0 +1,34 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; + +/** + * This simulation subclass implements AbstractSimulation.run(..) + * with a test script for the telecom system with only the + * basic objects. + */ +public class BasicSimulation extends AbstractSimulation { + + public static void main(String[] args){ + simulation = new BasicSimulation(); + simulation.run(); + } + + protected void report(Customer c) { } + +} diff --git a/docs/dist/examples/telecom/Billing.java b/docs/dist/examples/telecom/Billing.java new file mode 100644 index 000000000..c69ca758c --- /dev/null +++ b/docs/dist/examples/telecom/Billing.java @@ -0,0 +1,80 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package telecom; +/** + * The Billing aspect deals with... billing. + * How much money did each connection cost? + * How much money did each call cost? + * How much money is being debited to a customer? + * This aspect can be used by other parts of the system. (not in this example) + * + * Billing can depend many things, such as timing, the type of the connection, + * some special discounts the customer has, special features, etc. In here, + * it depends only on timing and on the type of the connection. + */ +public aspect Billing { + // domination required to get advice on endtiming in the right order + declare dominates: Billing, Timing; + + public static final long LOCAL_RATE = 3; + public static final long LONG_DISTANCE_RATE = 10; + + + public Customer Connection.payer; + public Customer getPayer(Connection conn) { return conn.payer; } + /** + * Caller pays for the call + */ + after(Customer cust) returning (Connection conn): + args(cust, ..) && call(Connection+.new(..)) { + conn.payer = cust; + } + + /** + * Connections give the appropriate call rate + */ + public abstract long Connection.callRate(); + + + public long LongDistance.callRate() { return LONG_DISTANCE_RATE; } + public long Local.callRate() { return LOCAL_RATE; } + + + /** + * When timing stops, calculate and add the charge from the + * connection time + */ + 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); + } + + + /** + * Customers have a bill paying aspect with state + */ + public long Customer.totalCharge = 0; + public long getTotalCharge(Customer cust) { return cust.totalCharge; } + + public void Customer.addCharge(long charge){ + totalCharge += charge; + } +} diff --git a/docs/dist/examples/telecom/BillingSimulation.java b/docs/dist/examples/telecom/BillingSimulation.java new file mode 100644 index 000000000..09f273ff6 --- /dev/null +++ b/docs/dist/examples/telecom/BillingSimulation.java @@ -0,0 +1,44 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; + +/** + * This simulation subclass implements AbstractSimulation.report(..) + * + */ +public class BillingSimulation extends AbstractSimulation { + + public static void main(String[] args){ + System.out.println("\n... Billing simulation 2 ...\n"); + simulation = new BillingSimulation(); + simulation.run(); + } + + /** + * Print a report of the connection time and the bill for customer + */ + protected void report(Customer c){ + Timing t = Timing.aspectOf(); + Billing b = Billing.aspectOf(); + System.out.println(c + " has been connected for " + + t.getTotalConnectTime(c) + + " seconds and has a bill of " + + b.getTotalCharge(c)); + } +} + diff --git a/docs/dist/examples/telecom/Call.java b/docs/dist/examples/telecom/Call.java new file mode 100644 index 000000000..738d2d348 --- /dev/null +++ b/docs/dist/examples/telecom/Call.java @@ -0,0 +1,97 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; +import java.util.Vector; +import java.util.Enumeration; + +/** + * A call supports the process of a customer trying to + * connect to others. + */ +public class Call { + + private Customer caller, receiver; + private Vector connections = new Vector(); + + /** + * Create a new call connecting caller to receiver + * with a new connection. This should really only be + * called by Customer.call(..) + */ + public Call(Customer caller, Customer receiver) { + this.caller = caller; + this.receiver = receiver; + Connection c; + if (receiver.localTo(caller)) { + c = new Local(caller, receiver); + } else { + c = new LongDistance(caller, receiver); + } + connections.add(c); + } + + /** + * picking up a call completes the current connection + * (this means that you shouldnt merge calls until + * they are completed) + */ + public void pickup() { + Connection connection = (Connection)connections.lastElement(); + connection.complete(); + } + + + /** + * Is the call in a connected state? + */ + public boolean isConnected(){ + return ((Connection)connections.lastElement()).getState() + == Connection.COMPLETE; + } + + /** + * hanging up a call drops the connection + */ + public void hangup(Customer c) { + for(Enumeration e = connections.elements(); e.hasMoreElements();) { + ((Connection)e.nextElement()).drop(); + } + } + + /** + * is Customer c one of the customers in this call? + */ + public boolean includes(Customer c){ + boolean result = false; + for(Enumeration e = connections.elements(); e.hasMoreElements();) { + result = result || ((Connection)e.nextElement()).connects(c); + } + return result; + } + + /** + * Merge all connections from call 'other' into 'this' + */ + public void merge(Call other){ + for(Enumeration e = other.connections.elements(); e.hasMoreElements();){ + Connection conn = (Connection)e.nextElement(); + other.connections.remove(conn); + connections.addElement(conn); + } + } +} diff --git a/docs/dist/examples/telecom/Connection.java b/docs/dist/examples/telecom/Connection.java new file mode 100644 index 000000000..7d54ec843 --- /dev/null +++ b/docs/dist/examples/telecom/Connection.java @@ -0,0 +1,87 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; + +/** + * Connections are circuits between customers + * There are two kinds: local and long distance + * see subclasses at the end of this file. + */ +public abstract class Connection { + + public static final int PENDING = 0; + public static final int COMPLETE = 1; + public static final int DROPPED = 2; + + Customer caller, receiver; + private int state = PENDING; + + /** + * Creatte a new Connection between a and b + */ + Connection(Customer a, Customer b) { + this.caller = a; + this.receiver = b; + } + + /** + * what is the state of the connection? + */ + public int getState(){ + return state; + } + + /** + * get the customer who initiated this connection + */ + public Customer getCaller() { return caller; } + + /** + * get the customer who received this connection + */ + public Customer getReceiver() { return receiver; } + + /** + * Called when a call is picked up. This means the b side has picked up + * and the connection should now complete itself and start passing data. + */ + void complete() { + state = COMPLETE; + System.out.println("connection completed"); + } + + /** + * Called when the connection is dropped from a call. Is intended to + * free up any resources the connection was consuming. + */ + void drop() { + state = DROPPED; + System.out.println("connection dropped"); + } + + /** + * Is customer c connected by this connection? + */ + public boolean connects(Customer c){ + return (caller == c || receiver == c); + } + +} + + + diff --git a/docs/dist/examples/telecom/Customer.java b/docs/dist/examples/telecom/Customer.java new file mode 100644 index 000000000..1e099984c --- /dev/null +++ b/docs/dist/examples/telecom/Customer.java @@ -0,0 +1,112 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; +import java.util.Vector; + +/** + * Customers have a unique id (name in this case for didactic purposes + * but it could be telephone number) and area code. + * They also have protocol for managing calls: call, pickup, etc. + */ +public class Customer { + + private String name; + private int areacode; + private Vector calls = new Vector(); + + /** + * unregister a call + */ + protected void removeCall(Call c){ + calls.removeElement(c); + } + + /** + * register a call + */ + protected void addCall(Call c){ + calls.addElement(c); + } + + /** + * Make a new customer with given name + */ + public Customer(String name, int areacode) { + this.name = name; + this.areacode = areacode; + } + + /** + * String rendition of customer + */ + public String toString() { + return name + "(" + areacode + ")"; + } + + /** + * what area is the customer in? + */ + public int getAreacode(){ + return areacode; + } + + /** + * Is the other customer in the same area? + */ + public boolean localTo(Customer other){ + return areacode == other.areacode; + } + + /** + * Make a new call to receiver + */ + public Call call(Customer receiver) { + Call call = new Call(this, receiver); + addCall(call); + return call; + } + + /** + * pick up a call + */ + public void pickup(Call call) { + call.pickup(); + addCall(call); + } + + /** + * hang up a call + */ + public void hangup(Call call) { + call.hangup(this); + removeCall(call); + } + + /** + * Merge a pair of calls -- conference them + * PRE: call1.includes(this) + * call2.includes(this) + * call1.connected() + * call2.connected() + * POST: call1 includes all customers connected by call1@pre and call2@pre + */ + public void merge(Call call1, Call call2){ + call1.merge(call2); + removeCall(call2); + } +} diff --git a/docs/dist/examples/telecom/Local.java b/docs/dist/examples/telecom/Local.java new file mode 100644 index 000000000..e0bc02679 --- /dev/null +++ b/docs/dist/examples/telecom/Local.java @@ -0,0 +1,26 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; + +public class Local extends Connection { + Local(Customer a, Customer b) { + super(a, b); + System.out.println("[new local connection from " + + a + " to " + b + "]"); + } +} diff --git a/docs/dist/examples/telecom/LongDistance.java b/docs/dist/examples/telecom/LongDistance.java new file mode 100644 index 000000000..b2ed6eb7d --- /dev/null +++ b/docs/dist/examples/telecom/LongDistance.java @@ -0,0 +1,26 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; + +public class LongDistance extends Connection { + LongDistance(Customer a, Customer b) { + super(a, b); + System.out.println("[new long distance connection from " + + a + " to " + b + "]"); + } +} diff --git a/docs/dist/examples/telecom/Timer.java b/docs/dist/examples/telecom/Timer.java new file mode 100644 index 000000000..813ae3a0d --- /dev/null +++ b/docs/dist/examples/telecom/Timer.java @@ -0,0 +1,50 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; + + +/** + * Simple timer machine used to record elapsed time + */ +public class Timer { + public long startTime, stopTime; + + /** + * set the start time + */ + public void start() { + startTime = System.currentTimeMillis(); + stopTime = startTime; + } + + /** + * set the end time + */ + public void stop() { + stopTime = System.currentTimeMillis(); + } + + /** + * set how much time passed between last start and stop? + */ + public long getTime() { + return stopTime - startTime; + } +} + + diff --git a/docs/dist/examples/telecom/TimerLog.java b/docs/dist/examples/telecom/TimerLog.java new file mode 100644 index 000000000..4591894dc --- /dev/null +++ b/docs/dist/examples/telecom/TimerLog.java @@ -0,0 +1,29 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; + +public aspect TimerLog { + + after(Timer t): target(t) && call(* Timer.start()) { + System.err.println("Timer started: " + t.startTime); + } + + after(Timer t): target(t) && call(* Timer.stop()) { + System.err.println("Timer stopped: " + t.stopTime); + } +} diff --git a/docs/dist/examples/telecom/Timing.java b/docs/dist/examples/telecom/Timing.java new file mode 100644 index 000000000..f40bd0fca --- /dev/null +++ b/docs/dist/examples/telecom/Timing.java @@ -0,0 +1,62 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; + +/** + * The Timing aspect is concerned with the duration + * of connections and with customer's cumulative + * connection time. + */ +public aspect Timing { + + /** + * Every Customer has a total connection time + */ + public long Customer.totalConnectTime = 0; + + public long getTotalConnectTime(Customer cust) { + return cust.totalConnectTime; + } + /** + * Every connection has a timer + */ + private Timer Connection.timer = new Timer(); + public Timer getTimer(Connection conn) { return conn.timer; } + + /** + * Start the timer when call completed + */ + after (Connection c): target(c) && call(void Connection.complete()) { + getTimer(c).start(); + } + + /** + * When to stop the timer + */ + pointcut endTiming(Connection c): target(c) && + call(void Connection.drop()); + + /** + * Stop the timer when call dropped and update the involved parties + */ + after(Connection c): endTiming(c) { + getTimer(c).stop(); + c.getCaller().totalConnectTime += getTimer(c).getTime(); + c.getReceiver().totalConnectTime += getTimer(c).getTime(); + } +} diff --git a/docs/dist/examples/telecom/TimingSimulation.java b/docs/dist/examples/telecom/TimingSimulation.java new file mode 100644 index 000000000..309563769 --- /dev/null +++ b/docs/dist/examples/telecom/TimingSimulation.java @@ -0,0 +1,40 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ +package telecom; + +/** + * This simulation subclass implements AbstractSimulation.report(..) + * + */ +public class TimingSimulation extends AbstractSimulation { + + public static void main(String[] args){ + System.out.println("\n... Timing simulation 2 ...\n"); + simulation = new TimingSimulation(); + simulation.run(); + } + + /** + * Print a report of the connection time for customer + */ + protected void report(Customer c){ + Timing t = Timing.aspectOf(); + System.out.println(c + " spent " + t.getTotalConnectTime(c)); + } + +} diff --git a/docs/dist/examples/tjp/Demo.java b/docs/dist/examples/tjp/Demo.java new file mode 100644 index 000000000..8b90a7a49 --- /dev/null +++ b/docs/dist/examples/tjp/Demo.java @@ -0,0 +1,40 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +*/ +package tjp; + +public class Demo { + + static Demo d; + + public static void main(String[] args){ + new Demo().go(); + } + + void go(){ + d = new Demo(); + d.foo(1,d); + System.out.println(d.bar(new Integer(3))); + } + + void foo(int i, Object o){ + System.out.println("Demo.foo(" + i + ", " + o + ")\n"); + } + + + String bar (Integer j){ + System.out.println("Demo.bar(" + j + ")\n"); + return "Demo.bar(" + j + ")"; + } + +} diff --git a/docs/dist/examples/tjp/GetInfo.java b/docs/dist/examples/tjp/GetInfo.java new file mode 100644 index 000000000..63f13c74e --- /dev/null +++ b/docs/dist/examples/tjp/GetInfo.java @@ -0,0 +1,49 @@ +/* +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. +*/ + +package tjp; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.reflect.CodeSignature; + +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]); + } + } +} diff --git a/docs/dist/examples/tracing/Circle.java b/docs/dist/examples/tracing/Circle.java new file mode 100644 index 000000000..76b73e20a --- /dev/null +++ b/docs/dist/examples/tracing/Circle.java @@ -0,0 +1,71 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing; + +/** + * + * Circle is a 2D shape. It extends the TwoDShape class with the radius + * variable, and it implements TwoDShape's abstract methods for + * correctly computing a circle's area and distance. + * + */ +public class Circle extends TwoDShape { + protected double r; // radius + + /* + * All sorts of constructors + */ + 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); + } + + /** + * Returns the perimeter of this circle + */ + public double perimeter() { + return 2 * Math.PI * r; + } + + /** + * Returns the area of this circle + */ + public double area() { + return Math.PI * r*r; + } + + /** + * This method overrides the one in the superclass. It adds some + * circle-specific information. + */ + public String toString() { + return ("Circle radius = " + String.valueOf(r) + super.toString()); + } +} diff --git a/docs/dist/examples/tracing/ExampleMain.java b/docs/dist/examples/tracing/ExampleMain.java new file mode 100644 index 000000000..93cc465b7 --- /dev/null +++ b/docs/dist/examples/tracing/ExampleMain.java @@ -0,0 +1,44 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing; + +/** + * + * A main function for testing 2D shapes. + * + */ +public class ExampleMain { + public static void main(String[] args) { + Circle c1 = new Circle(3.0, 3.0, 2.0); + Circle c2 = new Circle(4.0); + + Square s1 = new Square(1.0, 2.0); + + System.out.println("c1.perimeter() = " + c1.perimeter()); + System.out.println("c1.area() = " + c1.area()); + + System.out.println("s1.perimeter() = " + s1.perimeter()); + System.out.println("s1.area() = " + s1.area()); + + System.out.println("c2.distance(c1) = " + c2.distance(c1)); + System.out.println("s1.distance(c1) = " + s1.distance(c1)); + + System.out.println("s1.toString(): " + s1.toString()); + } +} diff --git a/docs/dist/examples/tracing/README b/docs/dist/examples/tracing/README new file mode 100644 index 000000000..6bf89328b --- /dev/null +++ b/docs/dist/examples/tracing/README @@ -0,0 +1,32 @@ + +This directory contains several examples of tracing aspects, +including a reusable tracing library and examples of +using that library. + +A lesson in the AspectJ Primer explains all of this code. + +To work with these (or any other examples), first be sure .../examples +is on your classpath, where ... is where you have installed AspectJ. + + +--To compile and run the example without tracing-- + + ajc @.../examples/tracing/notrace.lst + + java tracing.ExampleMain + + +--To compile and run the example with tracing version-- + + ajc @.../examples/tracing/tracev.lst + + java tracing.version.TraceMyClasses + +where is 1, 2, 3 or 4 + +--To use the tracing.lib.AbstractTrace aspect-- + + Make sure .../examples is in your classpath. + + In order to use this aspect, please read the documentation under + tracing/doc diff --git a/docs/dist/examples/tracing/Square.java b/docs/dist/examples/tracing/Square.java new file mode 100644 index 000000000..78b36882d --- /dev/null +++ b/docs/dist/examples/tracing/Square.java @@ -0,0 +1,71 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing; + +/** + * + * Square is a 2D shape. It extends the TwoDShape class with the side + * variable, and it implements TwoDShape's abstract methods for + * correctly computing a square's area and distance. + * + */ +public class Square extends TwoDShape { + protected double s; // side + + /* + * All sorts of constructors + */ + 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); + } + + /** + * Returns the perimeter of this square + */ + public double perimeter() { + return 4 * s; + } + + /** + * Returns the area of this square + */ + public double area() { + return s*s; + } + + /** + * This method overrides the one in the superclass. It adds some + * circle-specific information. + */ + public String toString() { + return ("Square side = " + String.valueOf(s) + super.toString()); + } +} diff --git a/docs/dist/examples/tracing/TwoDShape.java b/docs/dist/examples/tracing/TwoDShape.java new file mode 100644 index 000000000..960a01b89 --- /dev/null +++ b/docs/dist/examples/tracing/TwoDShape.java @@ -0,0 +1,78 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + + +package tracing; + +/** + * + * TwoDShape is an abstract class that defines generic functionality + * for 2D shapes. + * + */ +public abstract class TwoDShape { + /** + * Coordinates of the center of the shape. + */ + protected double x, y; + + protected TwoDShape(double x, double y) { + this.x = x; this.y = y; + } + + /** + * Returns the x coordinate of the shape. + */ + public double getX() { return x; } + + /** + * Returns the y coordinate of the shape. + */ + public double getY() { return y; } + + /** + * Returns the distance between this shape and the shape given as + * parameter. + */ + 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); + } + + /** + * Returns the perimeter of this shape. Must be defined in + * subclasses. + */ + public abstract double perimeter(); + + /** + * Returns the area of this shape. Must be defined in + * subclasses. + */ + public abstract double area(); + + /** + * Returns a string representation of 2D shapes -- simply its + * coordinates. + */ + public String toString() { + return (" @ (" + String.valueOf(x) + ", " + String.valueOf(y) + ") "); + } +} + diff --git a/docs/dist/examples/tracing/lib/AbstractTrace.java b/docs/dist/examples/tracing/lib/AbstractTrace.java new file mode 100644 index 000000000..8c67b12c3 --- /dev/null +++ b/docs/dist/examples/tracing/lib/AbstractTrace.java @@ -0,0 +1,185 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing.lib; + +import java.io.PrintStream; +import org.aspectj.lang.JoinPoint; + + +/** + * This class provides support for printing trace messages into a stream. + * The trace messages consist of the class name, method name (if method) + * and the list of parameter types.

    + * The class is thread-safe. Different threads may use different output streams + * by simply calling the method initStream(myStream).

    + * This class should be extended. + * It defines 3 abstract crosscuts for injecting the tracing functionality + * into any constructors and methods of any application classes.

    + * + * One example of using this class might be + *

    + * import tracing.lib.AbstractTrace;
    + * aspect TraceMyClasses extends AbstractTrace of eachJVM() {
    + *   pointcut classes(): within(TwoDShape) | within(Circle) | within(Square);
    + *   pointcut constructors(): executions(new(..));
    + *   pointcut methods(): executions(!abstract * *(..))
    + * }
    + * 
    + * (Make sure .../aspectj/examples is in your classpath) + */ +public abstract aspect AbstractTrace { + + /** + * Application classes - left unspecified. + * Subclasses should concretize this crosscut with class names. + */ + abstract pointcut classes(); + /** + * Constructors - left unspecified. + * Subclasses should concretize this crosscut with constructors. + */ + abstract pointcut constructors(); + /** + * Methods - left unspecified. + * Subclasses should concretize this crosscut with method names. + */ + abstract pointcut methods(); + + before(): classes() && constructors() { + doTraceEntry(thisJoinPoint, true); + } + after(): classes() && constructors() { + doTraceExit(thisJoinPoint, true); + } + + before(): classes() && methods() { + doTraceEntry(thisJoinPoint, false); + } + after(): classes() && methods() { + doTraceExit(thisJoinPoint, false); + } + + /* + * From here on, it's an ordinary class implementation. + * The static state is thread-safe by using ThreadLocal variables. + */ + + /** + * This method initializes this thread's trace output stream. + * By default, the output stream is System.err, and it is the same for + * all threads. In multithreaded applications, you may want to define + * different output streams for the different threads. For doing it, + * simply call this method in the beginning of each thread's main loop, + * giving it different output streams. + */ + public void initStream(PrintStream _stream) { + setStream(_stream); + } + + + private ThreadLocal stream = new ThreadLocal() { + protected Object initialValue() { + return System.err; + } + }; + private ThreadLocal callDepth = new ThreadLocal() { + protected Object initialValue() { + return new Integer(0); + } + }; + + private PrintStream getStream() { + return (PrintStream)stream.get(); + } + private void setStream(PrintStream s) { + stream.set(s); + } + private int getCallDepth() { + return ((Integer)(callDepth.get())).intValue(); + } + private void setCallDepth(int n) { + callDepth.set(new Integer(n)); + } + + private void doTraceEntry (JoinPoint jp, boolean isConstructor) { + setCallDepth(getCallDepth() + 1); + printEntering(jp, isConstructor); + } + + private void doTraceExit (JoinPoint jp, boolean isConstructor) { + printExiting(jp, isConstructor); + setCallDepth(getCallDepth() - 1); + } + + private void printEntering (JoinPoint jp, boolean isConstructor) { + printIndent(); + getStream().print("--> "); + getStream().print(jp); + // printParameterTypes(jp); + getStream().println(); + } + + private void printExiting (JoinPoint jp, boolean isConstructor) { + printIndent(); + getStream().print("<-- "); + getStream().print(jp); + // printParameterTypes(jp); + getStream().println(); + } + +// private void printParameterTypes(JoinPoint jp) { +// Class[] ptypes = jp.parameterTypes; + +// getStream().print("("); +// for (int i = 0; i < ptypes.length; i++) { +// getStream().print(ptypes[i].getName()); +// if (i < ptypes.length - 1) getStream().print(", "); +// } +// getStream().print(")"); +// } + + private void printIndent() { + for (int i = 0; i < getCallDepth(); i++) + getStream().print(" "); + } + + /** + * This method is not being used. + * It's being included solely for illustrating how to access and use + * the information in JoinPoint. + * If you want, you can replace the calls to printParameterTypes (above) + * by calls to this method. + */ +// private void printParameters(JoinPoint jp) { +// Class[] ptypes = jp.parameterTypes; +// String[] pnames = jp.parameterNames; +// Object[] params = jp.parameters; + +// getStream().print("("); +// for (int i = 0; i < ptypes.length; i++) { +// getStream().print(ptypes[i].getName() + " " + +// pnames[i] + "=" + +// params[i]); +// if (i < ptypes.length - 1) getStream().print(", "); +// } +// getStream().print(")"); +// } + +} + diff --git a/docs/dist/examples/tracing/lib/TraceMyClasses.java b/docs/dist/examples/tracing/lib/TraceMyClasses.java new file mode 100644 index 000000000..95c3a859c --- /dev/null +++ b/docs/dist/examples/tracing/lib/TraceMyClasses.java @@ -0,0 +1,67 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing.lib; + +import tracing.TwoDShape; +import tracing.Circle; +import tracing.Square; +import tracing.ExampleMain; + +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.io.FileNotFoundException; + +aspect TraceMyClasses extends AbstractTrace { + /** + * The application classes + */ + pointcut classes(): within(TwoDShape) || within(Circle) || within(Square); + /** + * The constructors in those classes - but only the ones with 3 + * arguments. + */ + pointcut constructors(): execution(new(double, double, double)); + /** + * This specifies all the message executions. + */ + pointcut methods(): execution(* *(..)); + + /** + * A main function for testing the trace aspect. + */ + public static void main(String[] _args) { + final String[] args = _args; + new Thread() { + public void run() { + TraceMyClasses.aspectOf().initStream(System.err); + ExampleMain.main(args); + } + }.start(); + + new Thread() { + public void run() { + try { + TraceMyClasses.aspectOf().initStream(new PrintStream(new FileOutputStream("AJTRACETEST"))); + } + catch (FileNotFoundException e) {} + ExampleMain.main(args); + } + }.start(); + } +} diff --git a/docs/dist/examples/tracing/version1/Trace.java b/docs/dist/examples/tracing/version1/Trace.java new file mode 100644 index 000000000..eef96df51 --- /dev/null +++ b/docs/dist/examples/tracing/version1/Trace.java @@ -0,0 +1,83 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing.version1; + +import java.io.PrintStream; + +/** + * + * This class provides some basic functionality for printing trace messages + * into a stream. + * + */ +public class Trace { + /** + * There are 3 trace levels (values of TRACELEVEL): + * 0 - No messages are printed + * 1 - Trace messages are printed, but there is no indentation + * according to the call stack + * 2 - Trace messages are printed, and they are indented + * according to the call stack + */ + public static int TRACELEVEL = 0; + protected static PrintStream stream = null; + protected static int callDepth = 0; + + /** + * Initialization. + */ + public static void initStream(PrintStream s) { + stream = s; + } + + /** + * Prints an "entering" message. It is intended to be called in the + * beginning of the blocks to be traced. + */ + public static void traceEntry(String str) { + if (TRACELEVEL == 0) return; + if (TRACELEVEL == 2) callDepth++; + printEntering(str); + } + + /** + * Prints an "exiting" message. It is intended to be called in the + * end of the blocks to be traced. + */ + public 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(" "); + } +} diff --git a/docs/dist/examples/tracing/version1/TraceMyClasses.java b/docs/dist/examples/tracing/version1/TraceMyClasses.java new file mode 100644 index 000000000..b4a97ee31 --- /dev/null +++ b/docs/dist/examples/tracing/version1/TraceMyClasses.java @@ -0,0 +1,75 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing.version1; + +/** + * + * This class connects the tracing functions in the Trace class with + * the constructors and methods in the application classes. + * + */ +import tracing.TwoDShape; +import tracing.Circle; +import tracing.Square; +import tracing.ExampleMain; + +aspect TraceMyClasses { + /** + * Application classes. + */ + pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); + /** + * The constructors in those classes. + */ + pointcut myConstructor(): myClass() && execution(new(..)); + /** + * The methods of those classes. + */ + pointcut myMethod(): myClass() && execution(* *(..)); + + /** + * Prints trace messages before and after executing constructors. + */ + before (): myConstructor() { + Trace.traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myConstructor() { + Trace.traceExit("" + thisJoinPointStaticPart.getSignature()); + } + + /** + * Prints trace messages before and after executing methods. + */ + before (): myMethod() { + Trace.traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myMethod() { + Trace.traceExit("" + thisJoinPointStaticPart.getSignature()); + } + + /** + * A main function for testing the trace aspect. + */ + public static void main(String[] args) { + Trace.TRACELEVEL = 2; + Trace.initStream(System.err); + ExampleMain.main(args); + } +} + diff --git a/docs/dist/examples/tracing/version2/Trace.java b/docs/dist/examples/tracing/version2/Trace.java new file mode 100644 index 000000000..cd631e278 --- /dev/null +++ b/docs/dist/examples/tracing/version2/Trace.java @@ -0,0 +1,123 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing.version2; + +import java.io.PrintStream; + +/** + * + * This class provides support for printing trace messages into a stream. + * Trace messages are printed before and after constructors and methods + * are executed. + * It defines one abstract crosscut for injecting that tracing functionality + * into any application classes. + * To use it, provide a subclass that concretizes the abstract crosscut. + */ +abstract aspect Trace { + + /* + * Functional part + */ + + /** + * There are 3 trace levels (values of TRACELEVEL): + * 0 - No messages are printed + * 1 - Trace messages are printed, but there is no indentation + * according to the call stack + * 2 - Trace messages are printed, and they are indented + * according to the call stack + */ + public static int TRACELEVEL = 2; + protected static PrintStream stream = System.err; + protected static int callDepth = 0; + + /** + * Initialization. + */ + 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(" "); + } + + + /* + * Crosscut part + */ + + /** + * Application classes - left unspecified. + * Subclasses should concretize this pointcut with class names. + */ + abstract pointcut myClass(); + /** + * The constructors in those classes. + */ + pointcut myConstructor(): myClass() && execution(new(..)); + /** + * The methods of those classes. + */ + pointcut myMethod(): myClass() && execution(* *(..)); + + /** + * Prints trace messages before and after executing constructors. + */ + before(): myConstructor() { + traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myConstructor() { + traceExit("" + thisJoinPointStaticPart.getSignature()); + } + + /** + * Prints trace messages before and after executing methods. + */ + before(): myMethod() { + traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myMethod() { + traceExit("" + thisJoinPointStaticPart.getSignature()); + } +} diff --git a/docs/dist/examples/tracing/version2/TraceMyClasses.java b/docs/dist/examples/tracing/version2/TraceMyClasses.java new file mode 100644 index 000000000..a3ae99e95 --- /dev/null +++ b/docs/dist/examples/tracing/version2/TraceMyClasses.java @@ -0,0 +1,43 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing.version2; + +import tracing.TwoDShape; +import tracing.Circle; +import tracing.Square; +import tracing.ExampleMain; + +/** + * + * This class concretizes the abstract crosscut in Trace, + * applying the trace facility to these application classes. + * + */ +public aspect TraceMyClasses extends Trace { + pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); + + /** + * A main function for testing the trace aspect. + */ + public static void main(String[] args) { + Trace.TRACELEVEL = 2; + Trace.initStream(System.err); + ExampleMain.main(args); + } +} diff --git a/docs/dist/examples/tracing/version3/Trace.java b/docs/dist/examples/tracing/version3/Trace.java new file mode 100644 index 000000000..8fc9d8613 --- /dev/null +++ b/docs/dist/examples/tracing/version3/Trace.java @@ -0,0 +1,123 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing.version3; + +import java.io.PrintStream; + +/** + * + * This class provides support for printing trace messages into a stream. + * Trace messages are printed before and after constructors and methods + * are executed. + * The messages are appended with the string representation of the objects + * whose constructors and methods are being traced. + * It defines one abstract pointcut for injecting that tracing functionality + * into any application classes. + * + */ +abstract aspect Trace { + + /* + * Functional part + */ + + /** + * There are 3 trace levels (values of TRACELEVEL): + * 0 - No messages are printed + * 1 - Trace messages are printed, but there is no indentation + * according to the call stack + * 2 - Trace messages are printed, and they are indented + * according to the call stack + */ + public static int TRACELEVEL = 0; + protected static PrintStream stream = null; + protected static int callDepth = 0; + + /** + * Initialization. + */ + public static void initStream(PrintStream s) { + stream = s; + } + + protected static void traceEntry(String str, Object o) { + if (TRACELEVEL == 0) return; + if (TRACELEVEL == 2) callDepth++; + printEntering(str + ": " + o.toString()); + } + + protected static void traceExit(String str, Object o) { + if (TRACELEVEL == 0) return; + printExiting(str + ": " + o.toString()); + if (TRACELEVEL == 2) callDepth--; + } + + private static void printEntering(String str) { + printIndent(); + stream.println("--> " + str); + } + + private static void printExiting(String str) { + printIndent(); + stream.println("<-- " + str); + } + + + private static void printIndent() { + for (int i = 0; i < callDepth; i++) + stream.print(" "); + } + + + /* + * Crosscut part + */ + + /** + * Application classes - left unspecified. + */ + abstract pointcut myClass(Object obj); + /** + * The constructors in those classes. + */ + pointcut myConstructor(Object obj): myClass(obj) && execution(new(..)); + /** + * The methods of those classes. + */ + // toString is called from within our advice, so we shouldn't + // advise its executions. But if toString is overridden, even + // this might not be enough, so we might want + // && !cflow(execution(String toString())) + pointcut myMethod(Object obj): myClass(obj) && + execution(* *(..)) && !execution(String toString()); + + before(Object obj): myConstructor(obj) { + traceEntry("" + thisJoinPointStaticPart.getSignature(), obj); + } + after(Object obj): myConstructor(obj) { + traceExit("" + thisJoinPointStaticPart.getSignature(), obj); + } + + before(Object obj): myMethod(obj) { + traceEntry("" + thisJoinPointStaticPart.getSignature(), obj); + } + after(Object obj): myMethod(obj) { + traceExit("" + thisJoinPointStaticPart.getSignature(), obj); + } +} diff --git a/docs/dist/examples/tracing/version3/TraceMyClasses.java b/docs/dist/examples/tracing/version3/TraceMyClasses.java new file mode 100644 index 000000000..c986d2615 --- /dev/null +++ b/docs/dist/examples/tracing/version3/TraceMyClasses.java @@ -0,0 +1,46 @@ +/* + +Copyright (c) Xerox Corporation 1998-2002. All rights reserved. + +Use and copying of this software and preparation of derivative works based +upon this software are permitted. Any distribution of this software or +derivative works must comply with all applicable United States export control +laws. + +This software is made available AS IS, and Xerox Corporation makes no warranty +about the software, its performance or its conformity to any specification. + +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| +|<--- this code is formatted to fit into 80 columns --->| + +*/ + +package tracing.version3; + +import tracing.TwoDShape; +import tracing.Circle; +import tracing.Square; +import tracing.ExampleMain; + +/** + * + * This class concretizes the abstract crosscut in Trace, + * applying the trace facility to these application classes. + * + */ +public aspect TraceMyClasses extends Trace { + pointcut myClass(Object obj): + this(obj) && + (within(TwoDShape) || within(Circle) || within(Square)); + + /** + * A main function for testing the trace aspect. + */ + public static void main(String[] args) { + Trace.TRACELEVEL = 2; + Trace.initStream(System.err); + ExampleMain.main(args); + } +} + diff --git a/docs/faq/faq.xml b/docs/faq/faq.xml new file mode 100644 index 000000000..63dc386e2 --- /dev/null +++ b/docs/faq/faq.xml @@ -0,0 +1,3397 @@ + + + + + + +
    + Frequently Asked Questions about AspectJ + Copyright (c) 1997-2001 Xerox Corporation, + 2002 Palo Alto Research Center, Incorporated. All rights reserved. + + + Last updated on the web November 26, 2002. + + + + For a list of recently-updated FAQ entries, see + AspectJ 1.1 is currently in development, and + some answers may change after it is released; + for more information, see the + AspectJ 1.1 README. + This is a web-only distribution of the FAQ; the 1.0 documentation bundle + contains an earlier version. + + + + Overview + + + What is AspectJ? + + + + AspectJ(tm) is a simple and practical extension to the + Java(tm) programming + language that adds to Java aspect-oriented programming (AOP) + capabilities. AOP allows developers to reap the benefits of + modularity for concerns that cut across the natural units of + modularity. In object-oriented programs like Java, the natural unit + of modularity is the class. In AspectJ, aspects modularize concerns that + affect more than one class. + + AspectJ includes a compiler (ajc), a + debugger (ajdb), a documentation generator + (ajdoc), a program structure browser + (ajbrowser), and integration + with Eclipse, Sun-ONE/Netbeans, GNU Emacs/XEmacs, JBuilder, and Ant. + + You compile your program using the AspectJ compiler (perhaps using + the supported development environments) and then run it, supplying + a small (< 100K) runtime library. + + + + + + What are the benefits of using AspectJ? + + + AspectJ can be used to improve the modularity of software + systems. + + Using ordinary Java, it can be difficult to modularize design + concerns such as + + + system-wide error-handling + contract enforcement + distribution concerns + feature variations + context-sensitive behavior + persistence + testing + + The code for these concerns tends to be spread out across the + system. Because these concerns won't stay inside of any one module + boundary, we say that they crosscut the + system's modularity. + + AspectJ adds constructs to Java that enable the modular + implementation of crosscutting concerns. This ability is + particularly valuable because crosscutting concerns tend to be both + complex and poorly localized, making them hard to deal with. + + + + + + + Can AspectJ work with any Java program? + + + AspectJ has been designed as a compatible + extension to Java. By compatible, we mean + + + + + + + upward compatible + + All legal Java programs are legal AspectJ + programs. + + + + + platform + compatible + + + All legal AspectJ programs run on standard Java + virtual machines. + + + + + tool + compatible + + + Existing tools can be extended to work with + AspectJ. + + + + + programmer compatible + + Programming in AspectJ feels natural to Java + programmers. + + + + + + The AspectJ tools run on any Java 2 Platform compatible + platform. The AspectJ compiler produces classes that run + on any Java 1.1 (or later) compatible platform. + + + + + + How is AspectJ licensed? + + + The AspectJ tools are open-source software available under the + Mozilla Public License 1.1. + The documentation is available under a separate + + license + that precludes for-profit or commercial + redistribution. Generally, we permit some usage for + internal presentations; please contact us at + support@aspectj.org + for permission. + + Most users only want to use AspectJ to build programs they distribute. + There are no restrictions here. When you distribute your program, be sure to + include all the runtime classes from the aspectjrt.jar for that version of AspectJ. + When distributing only the runtime classes, you need not provide any notice that + the program was compiled with AspectJ or includes binaries from the AspectJ project, + except as necessary to preserve the warranty disclaimers in our license. + Although the license does not require it, please email + support@aspectj.org + if you are shipping applications built with AspectJ; knowing that is + critical for ongoing support from our sponsors. + + + + + + + + What is the AspectJ Project? + + + AspectJ is based on over ten years of research at + + Xerox Palo Alto Research Center + + as funded by Xerox, a U.S. Government grant (NISTATP), and a + DARPA contract. + + It has evolved through open-source releases to a strong + user community. + The AspectJ team works closely with the community + to ensure AspectJ continues to evolve as an effective + aspect-oriented programming language and tool set. + + The latest release is 1.0.6 + which can be downloaded from the AspectJ + download page. + Further development is focused on supporting applications, + improving performance of the 1.0 compiler, + enhancing integration with IDEs, + and building the next generations of the language. + + + + + + Quick Start + + + + What Java versions does AspectJ require and support? + + + + + The AspectJ compiler produces programs for any released version of the + Java platform (jdk1.1 and later). When running, your program classes must + be able to reach classes in the + small (< 100K) runtime library (aspectjrt.jar) from the distribution. + The tools themselves require Java 2 (jdk 1.2) or later to run, + but the compiler can be set up to target any 1.1-compliant + version of the Java platform. + + + + + + How do I download and install AspectJ? + + + Go to AspectJ's + download web + page + and choose which components you want download. + The jar files are installed by executing + + + java -jar jar file name + + Do not try to extract the + jar file contents and then attempt to execute + java org.aspectj.Main. (A + NoClassDefFoundError exception will be + thrown.) The AspectJ distribution is not designed to be installed + this way. Use the java -jar form shown above. + + The compressed tar files (suffix: + .tgz) are extracted by decompressing them with + tar or with WinZip. + + To uninstall, remove the files the installer wrote in your + file system. In most cases, you can delete the top-level install + directory (and all contained files), after you remove any + new or updated files you want to keep. On Windows, no + registry settings were added or changed, so nothing needs to be + undone. You may install over prior versions, but if the files are + locked the installer will warn you but still complete; in this case, + remove the locked files and reinstall. + + + + + + How should I start using AspectJ? + + + Many users adopt AspectJ incrementally, first using it + to understand and validate their systems (relying on it only in + development) and then using it to implement crosscutting concerns + in production systems. AspectJ has been designed to make each + step discrete and beneficial. + + + In order of increasing reliance, you may use AspectJ: + + + + + In the development + process + Use AspectJ to trace or log + interesting information. You can do this by adding + simple AspectJ code that performs logging or tracing. + This kind of addition may be removed ("unplugged") for + the final build since it does not implement a design + requirement; the functionality of the system is unaffected by + the aspect. + + + + + As an ancillary part of your + system + Use AspectJ to more completely and + accurately test the system. + Add sophisticated code that can check contracts, + provide debugging support, or implement test strategies. + Like pure development aspects, this code may also be + unplugged from production builds. However, the same code + can often be helpful in diagnosing failures in deployed + production systems, so you may design the functionality + to be deployed but disabled, and enable it when debugging. + + + + + As an essential part of your + system + Use AspectJ to modularize + crosscutting concerns in your system by design. + This uses AspectJ to implement logic integral to a system + and is delivered in production builds. + + + + This adoption sequence works well in practice and has been + followed by many projects. + + + + + + How does AspectJ integrate with existing Java development + tools? + + + + AspectJ products are designed to make it easy to integrate + AspectJ into an existing development process. + Each release includes + Ant taskdefs for building programs, + the AspectJ Development Environment (AJDE) for writing + aspects inside popular IDE's, and + command-line tools for compiling, documenting, and debugging. + + + AspectJ provides replacements for standard Java tools: + + + ajc, the AspectJ compiler, + runs on any Java 2 compatible platform, and produces classes + that run on any Java 1.1 (or later) compatible platform. + + + + ajdoc works like + Sun's javadoc API documentation generator + to produce HTML describing the semantics of Java and + AspectJ source files, including entries and cross-references + for the crosscutting structure. + + + + ajdb is an aspect-aware debugger + akin to Java's jdb. + + + + + The AspectJ Development Environment (AJDE) + enables programmers to view and navigate the crosscutting structures + in their programs, integrated with existing support in + popular Java IDE's for viewing and navigating object-oriented + structures. For many programmers this provides a deeper understanding + of how aspects work to modularize their concerns and permits them + to incrementally extend their development practices without + having to abandon their existing tools. + + + AJDE integrates with the following tools: + + + + Borland's JBuilder (versions 4 and 5) + + + Sun Microsystems' Forte for Java (versions 2 and 3), + and Netbeans 3.2 + + + + Eclipse (version 2.0) + + + GNU Emacs (version 20.3) and XEmacs (version 21.1 on Unix + and 21.4 on Windows) + + + + + The common functionality of AJDE is also available in + the stand-alone source code browser ajbrowser, + included in the tools distribution. + + AspectJ also supports building with Ant by providing + taskdef interfaces to the ajc and ajdoc tools. + + + + + + Typical AspectJ programs + + + Are aspects always optional or non-functional parts of + a program? + + + + No. Although AspectJ can be used in a way that allows AspectJ + code to be removed for the final build, aspect-oriented code is not + always optional or non-functional. Consider + what AOP really does: it makes the modules in a program correspond + to modules in the design. In any given design, some modules are + optional, and some are not. + + The examples directory included in the AspectJ distribution + contains some examples of the use aspects that are not optional. + Without aspects, + + + + + + + bean + + Point objects would not be JavaBeans. + + + + introduction + + Point objects would not be cloneable, comparable or + serializable. + + + + + spacewar + + Nothing would be displayed. + + + + telecom + + No calls would be billed. + + + + + + + + + + What is the difference between development and production aspects? + + + + + Production aspects are delivered with the finished product, + while development aspects are used during the development process. + Often production aspects are also used during development. + + + + + + + What are some common development aspects? + + + + Aspects for logging, tracing, debugging, profiling + or performance monitoring, or testing. + + + + + + + What are some common production aspects? + + + + + Aspects for performance monitoring and diagnostic systems, + display updating or notifications generally, security, + context passing, and error handling. + + + + + + Basic AOP and AspectJ Concepts + + + What are scattering, tangling, and crosscutting? + + + + "Scattering" is when similar code is distributed throughout many + program modules. This differs from a component being used by + many other components since + it involves the risk of misuse at each point and of inconsistencies + across all points. Changes to the implementation may require + finding and editing all affected code. + + "Tangling" is when two or more concerns are implemented in + the same body of code or component, making it more difficult to understand. + Changes to one implementation may cause unintended changes + to other tangled concerns. + + "Crosscutting" is how to characterize a concern than spans + multiple units of OO modularity - classes and objects. Crosscutting + concerns resist modularization using normal OO constructs, but + aspect-oriented programs can modularize crosscutting concerns. + + + + + + What are join points? + + + Join points are well-defined points in the execution of a + program. Not every execution point is a join point: only those + points that can be used in a disciplined and principled manner are. + So, in AspectJ, the execution of a method call is a join point, but + "the execution of the expression at line 37 in file Foo.java" is + not. + + The rationale for restricting join points is similar to the + rationale for restricting access to memory (pointers) or + restricting control flow expressions (goto) in + Java: programs are easier to understand, maintain and extend + without the full power of the feature. + + AspectJ join points include reading or writing a field; calling + or executing an exception handler, method or constructor. + + + + + + + What is a pointcut? + + + + A pointcut picks out + + join points + . These join points are described by the pointcut + declaration. Pointcuts can be defined in classes or in aspects, + and can be named or be anonymous. + + + + + + What is advice? + + + Advice is code that executes at each + join point picked out by a + pointcut. There are three + kinds of advice: before advice, around advice and after advice. As + their names suggest, before advice runs before the join point + executes; around advice executes before and after the join point; + and after advice executes after the join point. The power of + advice comes from the advice being able to access values in the + execution context of a pointcut. + + + + + + What are inter-type declarations? + + + AspectJ enables you to declare members and supertypes of another class + in an aspect, subject to Java's type-safety and access rules. These are + visible to other classes only if you declare them as accessible. + You can also declare compile-time errors and warnings based on pointcuts. + + + + + + What is an aspect? + + + Aspects are a new class-like language element that has been + added to Java by AspectJ. Aspects are how developers encapsulate + concerns that cut across classes, the natural unit of modularity in + Java. + + Aspects are similar to classes because... + + aspects have type + + + aspects can extend classes and other aspects + + + + + aspects can be abstract or concrete + + + + + non-abstract aspects can be instantiated + + + + aspects can have static and non-static state and + behavior + + + + aspects can have fields, methods, and types + as members + + + + the members of non-privileged aspects follow the + same accessibility rules as those of classes + + + + + Aspects are different than classes because... + + + aspects can additionally include as members pointcuts, + advice, and inter-type declarations; + + + + aspects can be qualified by specifying the + context in which the non-static state is available + + + + aspects can't be used interchangeably with + classes + + + + aspects don't have constructors or finalizers, + and they cannot be created with the new operator; + they are automatically available as needed. + + + + privileged aspects can access private members of + other types + + + + + + + + + Why AOP? + + + Are crosscutting concerns induced by flaws in parts of the + system design, programming language, operating system, etc. Or is + there something more fundamental going on? + + + + AOP's fundamental assumption is that in any sufficiently + complex system, there will inherently be some crosscutting + concerns. + + So, while there are some cases where you could re-factor a + system to make a concern no longer be crosscutting, the AOP idea + is that there are many cases where that is not possible, or where + doing so would damage the code in other ways. + + + + + + Does it really make sense to define aspects in terms of + crosscutting? + + + + Yes. + The short summary is that it is right to define AOP in terms of + crosscutting, because well-written AOP programs have clear + crosscutting structure. It would be a mistake to define AOP in + terms of "cleaning up tangling and scattering", because that isn't + particular to AOP, and past programming language innovations also + do that, as will future developments. + + Slides for a long talk on this topic are at + + http://www.cs.ubc.ca/~gregor/vinst-2-17-01.zip + . + + + + + + Is AOP restricted to domain-specific + applications? + + + + No. Some implementations of AOP are domain-specific, but + AspectJ was specifically designed to be general-purpose. + + + + + + Why do I need AOP if I can use interceptors + (or JVMPI or ref + lection)? + + + + There are many mechanisms people use now to implement + some crosscutting concerns. But they don't have a way to express + the actual structure of the program so you (and your tools) + can reason about it. Using a language enables you to express the + crosscutting in first-class constructs. You can not only avoid the + maintenance problems and structural requirements of some other + mechanisms, but also combine forms of crosscutting so that all + the mechanisms for a particular concern are one piece of code. + + + + + + Related Technology + + + + How does AspectJ compare to other new forms of programming? + + + + There are many recent proposals for programming languages that + provide control over crosscutting concerns. Aspect-oriented + programming is an overall framework into which many of these + approaches fit. AspectJ is one particular instance of AOP, + distinguished by the fact that it was designed from the ground up + to be compatible with Java. + + See the + Related + Sites + page of the AspectJ web site for more + information. + + + + + + How do you compare the features of AspectJ with + reflective systems? + + + + Reflective and aspect-oriented languages have an important + similarity: both provide programming support for dealing with + crosscutting concerns. In this sense reflective systems proved + that independent programming of crosscutting concerns is + possible. + + But the control that reflection provides tends to be low-level + and extremely powerful. In contrast, AspectJ provides more + carefully controlled power, drawing on the rules learned from + object-oriented development to encourage a clean and understandable + program structure. + + + + + + How do AspectJ features compare with those of mixin-based + inheritance? + + + + Some features of AspectJ, such as introduction, are related to + mixin-based inheritance. But, in order to + support crosscutting, a core goal for AspectJ, AspectJ goes beyond + mixin-based inheritance. + + Firstly, an aspect imposes behavior on a class, rather than a + class requesting behavior from an aspect. An aspect can modify a + class without needing to edit that class. This property is + sometimes called reverse inheritance. + + Secondly, a single aspect can affect multiple classes in + different ways. A single paint aspect can add different paint + methods to all the classes that know how to paint, unlike mixin + classes. + + +So mixin-based inheritance doesn't have the reverse inheritance +property, and mixins affect every class that mixes them in the same. +If I want to do something like SubjectObserverProtocol, I need two +mixins, SubjectPartofSubjectObserverProtocol and ObserverPartof... +In AspectJ, both halves of the protocol can be captured in a single +aspect. + + + + + + What is the relationship between AOP and + XP (extreme programming AKA agile methods)? + + + + From a question on the user list: + +> Anyone know the connections between AOP and Extreme Programming? +> I am really confused. It seems AOP is a programming paradigm, which +> is the next level of abstraction of OOP. Extreme Programming, however, +> this is a lightweight software development process. One of the common +> motivations of AOP and XP is designed to adopt to the requirement +> changes, so that it can save the cost of software development. + + + + This is Raymond Lee's answer: + + + You're not really that confused. AOP and XP are orthogonal concepts, + although AOP can be used to help accomplish XP goals. + One of the goals of XP is to respond to changing requirements. + Another is to reduce the overall cost of development. These are + not necessarily the same thing. + + + One of the principles of XP that contribute to meeting those goals + is to maintain clean, simple designs. One of the criteria for clean, + simple designs is to factor out duplication from the code. Benefits + of removing duplication include the code being easier to understand, + better modularity of the design, lower costs of code changes, less + chance of conflicting changes when practicing collective code + ownership, etc. + + + Different types of duplication lend themselves to being addressed by + different design paradigms and language features. Duplicate snippets + of code can be factored out into methods. Duplicate methods can be + factored out to common classes, or pushed up to base classes. + Duplicate patterns of methods and their use can be factored out to + mechanisms of classes and methods (i.e. instantiations of design + patterns). + + + AOP addresses a type of duplication that is very difficult to handle + in the other common paradigms, namely cross-cutting concerns. By + factoring out duplicate cross-cutting code into aspects, the target + code becomes simpler and cleaner, and the cross-cutting code becomes + more centralized and modular. + + + So, AOP as a paradigm, and the associated tools, gives an XPer, or + anyone wanting to remove duplication from the code base, a powerful + way to remove a form of duplication not easily addressed until now. + + + + + + Will you support C#? + + + Not at this time. Although the resemblances between C# and Java + means it would probably be a fairly straightforward matter to take + the AspectJ language design and produce AspectC#, our current focus + is only on supporting effective uses of AspectJ. + + + + + + Deciding to adopt AspectJ + + + + Is it safe to use AspectJ in my product plans? + + + + You may use AspectJ in your product or project with little + risk. Several factors play a role in reducing the risk of adopting + this new technology: + + + AspectJ is an addition to + Java, and can be incrementally introduced into a project + in a way that limits risk. + See for + some suggestions on how to do this. + + + + The AspectJ compiler accepts standard Java as + input and produces standard Java bytecode as output. An + optional mode produces standard Java source code which may + then be compiled with any compliant Java compiler, e.g. Sun's + javac compiler + or IBM's jikes compiler. + + + + AspectJ is available under the + Mozilla Public License, + a non-proprietary, open source license. This ensures that + AspectJ will continue to evolve and be available, regardless + of the fate of any particular organization involved with + AspectJ. + + + + Removing AspectJ from your program is not + difficult, although you will lose the flexibility and + economy that AspectJ provided. + + + + + + + + + What is the effect of using AspectJ on the source code + size of programs? + + + + Using aspects reduces, as a side effect, the number of source + lines in a program. However, the major benefit of using aspects + comes from improving the modularity of a + program, not because the program is smaller. Aspects gather into a + module concerns that would otherwise be scattered across or + duplicated in multiple classes. + + + + + + + Does AspectJ add any performance overhead? + + + + The issue of performance overhead is an important one. It is + also quite subtle, since knowing what to measure is at least as + important as knowing how to measure it, and neither is always + apparent. + + There is currently no benchmark suite for AOP languages in + general nor for AspectJ in particular. It is probably too early to + develop such a suite because AspectJ needs more maturation of the + language and the coding styles first. Coding styles really drive + the development of the benchmark suites since they suggest what is + important to measure. + + In the absence of a benchmark suite, AspectJ probably has an + acceptable performance for everything except non-static advice. + Introductions and static advice should have extremely small + performance overheads compared to the same functionality + implemented by hand. + + The ajc compiler will use static typing information + to only insert those checks that are absolutely necessary. Unless you use + 'thisJoinPoint' or 'if', then the only dynamic checks that will be + inserted by ajc will be 'instanceof' checks which are generally quite fast. + These checks will only be inserted when they can not be inferred from + the static type information. + + If you'd like to measure the performance be sure to write code + fragments in AspectJ and compare them to the performance of the + corresponding code written without AspectJ. For example, don't + compare a method with before/after advice that grabs a lock to just + the method. That would be comparing apples and oranges. Also be + sure to watch out for JIT effects that come from empty method + bodies and the like. Our experience is that they can be quite + misleading in understanding what you've measured. + + + + + + + I've heard that AspectJ leads to modularity violations. Does it? + + + + + Well I haven't yet seen a language in which you can't write bad code! + + + But seriously, most AspectJ users find that just like when they learned + OO, it takes a while to really get the hang of it. They tend to start + in the usual way, by copying canonical examples and experimenting with + variations on them. + + + But users also find that rather than being dangerous, AspectJ helps them + write code that is more clear and has better encapsulation -- once they + understand the kind of modularity AspectJ supports. There are several + good papers that talk about this (see below), but here's a basic point + to keep in mind: when properly used, AspectJ makes it possible program + in a modular way, something that would otherwise be spread throughout + the code. Consider the following code, adapted from the AspectJ tutorial: + + +aspect PublicErrorLogging { + Log log = new Log(); + + pointcut publicInterface(Object o): + call(public * com.xerox.*.*(..)) && target(o); + + after(Object o) throwing (Error e): publicInterface(o) { + log.write(o, e); + } +} + + + The effect of this code is to ensure that whenever any public method of + an interface or class in the com.xerox package + throws an error, that error is logged before being thrown to its caller. + + + Of course in the alternative implementation a large number of methods + have a try/catch around their body. + + + The AspectJ implementation of this crosscutting concern is clearly + modular, whereas the other implementation is not. As a result, if you + want to change it, its easier in the AspectJ implementation. For + example, if you also want to pass the name of the method, or its + arguments to log.write, you only have to edit + one place in the AspectJ code. + + + This is just a short example, but I hope it shows how what happens + with AOP and AspectJ is that the usual benefits of modularity are + achieved for crosscutting concerns, and that leads to better code, + not more dangerous code. + + + One paper someone else just reminded me of that talks some more + about this is: + + http://www.cs.ubc.ca/~kdvolder/Workshops/OOPSLA2001/submissions/12-nordberg.pdf + + + + + + + + Why does AspectJ permit aspects to access and add members of another type? + Isn't that violating OO encapsulation? + + + + In the spirit of Smalltalk, we have decided to give more power + to the language in order to let the user community experiment and + discover what is right. To date this has proven to be a successful + strategy because it has permitted the construction of many useful + aspects that crosscut the internal state of an object, and as such + need access the its private members. However, we are not + discounting that some sort of restrictions are useful, rather, we + are seeking input from the community in order to decide on what + these restrictions should be. + + + In that light, our position on encapsulation is : + + + we respect Java's visibility rules + we also provide open-classes, a mature OO technology + we provide "privileged" access if you really need it. + + + Introducing parents or members to classes is a well-studied OO technique + known as open classes. + + + Open classes have been used in many languages prior to AspectJ, + including CLOS, Python, Smalltalk, Objective-C, and others. + Building from Java, introduction in AspectJ provides better + name hygiene and access control than prior languages. + Introduced code obeys all of Java's normal accessibility rules + for its lexical location in the aspect that it is introduced from. + Such code can not even see, much less access, private members of + the class it is introduced into. Further, introductions can be + declared private to the aspect, so they are not visible to + other clients of the class. + + + Privileged aspects do permit access to private members of another + class. They are a response to the very few cases where developers + genuinely need such access (typically for testing purposes where it + access is necessary), but it would be more risky to open access by + putting the aspect in the same package, adding test code, or changing + access in the target class. We recommend using privileged aspects + only as necessary, and believe that marking them "privileged" makes + any potential misuse apparent. + + + + + + Can I use AspectJ with J2EE? + + + + Consider the component types in J2EE: + + + + + Servlet: AspectJ works well within servlets + + + + + JSP: It is possible to use AspectJ to affect code in JSPs by precompiling + them into Java sources and compiling these with ajc. This can be used, e.g., to + customize displays by turning on and off custom JSP taglibs. The mapping from a + given jsp source to java package and class name is not standardized, which means + doing this imposes dependencies on specific container versions. + + + + + EJB: AspectJ supports a wide variety of aspects for EJBs. It can be used for + logging, tracing, debugging, error handling by layers, correlated method-level + interception (e.g., chargebacks), metering, fine-grained transactions, etc. + Indeed, it can be used to enforce adherence to coding restrictions within an + EJB (e.g., not using java.io, creating a class loader, or listening on + sockets) using declare error. + + + + + The basic limitations are that there is no built-in support for writing J2EE + analogs for AspectJ extensions to Java, like distributed aspects, distributed + cflow, or managing state between invocations. These don't prevent one from using + AspectJ to do useful intra-container implementation, nor need they prevent one + from building distributed support, state management, and inter-component + implementations that leverage AspectJ. It just takes some work. In more detail: + + + All AspectJ implementations may define "code the implementation controls". + The AspectJ 1.0 implementation defines this as the files passed to the compiler + (AspectJ 1.1 will also support bytecode weaving). + + + Some advice on EJB operations will generate methods that confuse ejb compilers. + To avoid this problem, you can use the -XaddSafePrefix flag when compiling with ajc. + + + EJB components may be invoked remotely, and containers may passivate and + pool EJB's. Servlets have similar limitations, and in both cases the + lifespan of the defining class loader is implementation-dependent + (though it must span the operation of a particular request). + + + Being limited by lifecycle and namespace, the AspectJ 1.0 implementation + supports aspects that operate through non-remote invocations during the lifetime + of the namespace for a particular + deployment unit compiled in its entirety by the ajc compiler. + This means AspectJ supports common aspects only within a single local runtime + namespace (usually implemented as a class loader hierarchy). + + + Further, AspectJ recognizes language-level join points (object initialization, + method calls, etc.), not their EJB analogs (ejb find or create methods...). + These lead to the following consequences: + + + + + Issingleton aspects (the default) are limited to the lifetime of + the defining class loader, which in some implementations may not span + multiple invocations of the same application or EJB component. + + + + + EJB lifecycles are different from object lifecycles, so perthis + and pertarget aspects will make little sense. They do not work + in the current implementation, which uses synchronized methods + to ensure a correct association in threaded environments + (EJB's may not have synchronized methods). + + + + + Percflow or percflowbelow aspects are restricted to a chain of + non-remote invocations. While EJB 2.0 permits declaring an interface + local, this information is not available to the AspectJ compiler today. + For same reasons as stated above fore perthis, these will not work even + in the EJB container. + + + + + Evaluation of cflow or cflowbelow pointcuts will be valid only + with respect to a chain of non-remote invocations. + + + + + In addition, any AspectJ code should respect EJB operations: + + + + + The EJB container accesses EJB component fields directly, i.e., + in code outside the control of the compiler. There is no join point for + these accesses, and hence no way to write a pointcut to advise that access. + + + + + The EJB container may pool EJB components, so any initialization + join points may run once per component constructed, not once per + component initialized for purposes of a client call. + + + + + The EJB container is permitted to change class loaders, even + between invocations of a particular EJB component (by passivating and + activating with a new class loader). In this case, instances of singleton + aspects will not operate over multiple invocations of the component, or that + static initialization join point recur for a given class as it is re-loaded. + This behavior depends on the container implementation. + + + + + + + + Can I use AspectJ with Generic Java? + + + At this time, unfortunately not. The two compilers are just not + at all compatible. In an ideal world, there would be a wonderful + Open Source extensible compiler framework for Java that both GJ and + AspectJ would be built on top of, and they would seamlessly + interoperate along with all other extensions to Java that you might + be interested in, but that's not the case (yet?). + + However, on 09 October 2000, the Java Community Process + approved a proposal to add generic types to Java that is largely + based on GJ (JSR 14). A draft specification was submitted for + public review, which closed on 01 August 2001, and a + + prototype implementation + has been released. + + We are committed to moving very rapidly to add support for + generic types in AspectJ when generic types become part of the Java + language specification. Everyone on the AspectJ team is looking + forward to this, because we too would really like to be able to + write code that includes both aspects and generic types. + + + + + + Are you working to put AOP into Java? + It seems that every AOP toolset currently uses proprietary mechanisms + to describe point-cuts, etc. + + + + + We are working on standardization, but it's + a question of timing/ripeness (imagine going from thousands of users + to millions). (See .) We believe + AspectJ addresses this question in the best way possible now: + + + + It's open-source. Rather than being proprietary or controlled by a + vendor, it's available for anybody to use and build upon, forever. + + + + + AspectJ is not a set of mechanisms, it's a language. It is currently + implemented using certain techniques, but there's nothing that prevents + it from being implemented with other techniques. That means users can + adopt the language with confidence that implementations will get better. + + + + + There is no engineering need to change Java. The AspectJ language uses + the join point model already in Java, so there is no need to extend the + programming model. Our implementation produces valid Java bytecode, which + runs in any compliant J2SE VM and supports standard debuggers for those VM's + that support JSR-45 (debugging support for multi-language/multi-file sources). + This is a huge benefit to Sun since Sun must be extremely cautious + about extensions to the language or VM; before adopting AOP, Sun should + demand the kind of actual-proof that AspectJ implementations offer. + + + + + On the issue of "proprietary mechanisms to describe pointcuts, etc.": Any AOP + has to have some language to describe pointcuts and the like ("pointcuts" + of course being the AspectJ term). Users would like to have one language + (to avoid having to learn or transform between many languages) and the + choice of multiple implementations (tailored for a configuration, subject + to competitive pressure, etc.). That's what AspectJ offers. + + + + + That said, we believe the AspectJ extensions to Java could form the basis + for bringing AOP to Java; when that happens, there will be engineering + opportunities to make the implementation and tool support better. + + + + + + + + + What kind of support is available? + + + + The AspectJ users mailing list provides an + informal network of AspectJ experts. To subscribe, + visit the Mailing Lists + page of the AspectJ web site. + + If you have a problem that is not a bug, you may email + the AspectJ team at + support@aspectj.org. + You may view and submit bug reports and feature requests at + http://aspectj.org/bugs. + + Members of the AspectJ team are available to work with users in + more depth on both program design and implementation issues. + The team also presents educational courses and speakers for + interested groups and offers commercial support + and consulting for businesses. + Please contact the + AspectJ team. + with your request. + + + + + + Using the AspectJ compiler + + + + What files do I need to include when compiling AspectJ programs? + + + + You need to specify to the compiler the source files that + contain your aspects and the source files that contain the + types affected by your aspects. + See . + The AspectJ compiler will not search the source path for types + that may be affected (unlike Javac and Jikes), and it only uses + aspects in source form. + + In some cases you should compile your entire system all at once. + If this is too slow, then you can try to make reasonable divisions + between sets of source files whose aspects do not interact to + achieve a shorter compile cycle (particularly for development + aspects). However, if you get any problems + or if you wish to run tests or do a release, you should recompile + the entire system. + + + + + + I have to list many files in the command line to + compile with ajc. Is there any other way to + provide the file names to ajc? + + + + + Yes, use the argfile option to ajc. List source + files in a line-delimited text file and direct ajc to that + file using -argfile or @: + + ajc @sources.lst +ajc -argfile sources.lst + + + For more information, see the ajc tool + section of the + + Development Environment Guide + . + + + + + + What Java virtual machine (JVM) do I use to run the + AspectJ compiler? + + + + Use the latest, greatest, fastest JVM you can get your hands on + for your platform. The compiler's performance is dependent on the + performance of the JVM it is running on, so the faster a JVM you + can find to run it on, the shorter your compile times will be. At a + minimum you need to use a Java 2 or later JVM to run the compiler. + We realize that this constraint can be a problem for users who + don't currently have a Java 2 JVM available. We're sorry for the + inconvenience, but we had to make the hard decision that the + advantages of being able to rely on Java 2 were worth the cost of + losing a number of developers who are working on platforms without + Java 2 support. Here is a list of starting places where you might + find support for your system. + + + + Java 2 + Platform, Standard Edition + + + + + + + developerWorks : J + ava technology : Tools and products - Developer kits + + + + + + + developerWorks : Open Source - Jikes Project + + + + + + Java + Platform Ports + + + + + + The requirement of Java 2 support is only for + running the AspectJ compiler. The AspectJ + compiler can be used to build programs that will run on Java 1.1 + (or probably even on Java 1.0) systems. This means that it can + build programs that will run on Macintosh, FreeBSD, and applets + that will run in Internet Explorer and Netscape Navigator that are + still not yet Java 2 compliant. + + + + + + How can I use ajc to compile + programs for a JVM that is different from the one used to run it? + + + + + ajc can be used to develop programs that are + targeted at the Java 1.1 platform, even though the + ajc compiler won't run on that platform. Here's + an example of using ajc in this sort of + cross-compilation mode (assuming a Windows platform with all the + default installation directories): + + +ajc -target 1.1 -bootclasspath c:\jdk1.1.7\lib\classes.zip \ + -classpath c:\aspectj1.0\lib\aspectjrt.jar -extdirs "" \ + -argfile jdk11system.lst + + This same technique can be used if you want to run + ajc on a JDK 1.3 JVM (highly recommended) but + need to generate code for JDK 1.2. That would look something + like: + + +ajc -bootclasspath c:\jdk1.2\jre\lib\rt.jar \ + -classpath c:\aspectj1.0\lib\aspectjrt.jar \ + -extdirs c:\jdk1.2\jre\lib\ext + -argfile jdk12system.lst + + + + + + Does the ajc compiler support + the assert keyword in Java 1.4? + + + + Yes. As with Javac, + use the -source 1.4 option as described + in the ajc tool section + of the + + Development Environment Guide + . + + + + + + Are there any issues using AspectJ with the Microsoft + JVM? + + + + Since AspectJ requires Java 2 or later, it will not run on the + Microsoft JVM, which does not support Java 2. + + + + + + Does ajc rely + on javac for generating Java bytecode + (.class) files? + + + + No. Some previous versions of AspectJ had this requirement, + and javac can still be used as + ajc back end by using the + -usejavac flag. You can also run ajc + in preprocessor mode to generate Java source + (.java) files to be compiled using + javac or another java compiler. + + + + + + + I noticed the AspectJ compiler doesn't use a parser generator. Why is that? + + + + + The PARSER for ajc is written by hand. This choice was made with full + awareness of the generator tools out there. (Jim had for example used + the excellent javacc tool for building the parser for JPython (now Jython)). + One of the reasons that AspectJ uses a hand-written parser is that using + javacc taught Jim about the LL-k design for parsers (pioneered by antlr). + As opposed to the state-machine parsers produced by yacc, these parsers are + very readable and writable by humans. + + + Antlr and javacc did not really suit the project: + + + + + Antlr's support for unicode in the lexer is still immature and this makes + using it with Java challenging. This was an even bigger issue 3 years ago + when we started on the Java implementation of ajc. + + + + + While javacc is freely available, it is not Open Source. Depending on a + closed-source tool to build an Open Source compiler would reduce some + of the transparency and control of open-source. + + + + + There were also several things that were easier to implement with + a hand-written parser than with any of the exiting tools. + + + + + Semi-keywords -- it's important to us that + "every legal Java program is also a legal AspectJ program." + This wouldn't be true if we made 'before' and 'call' full keywords in + AspectJ. It is easier to support these sorts of semi-keywords with a + hand-written parser. (Note: ajc-1.0.x handles 'aspect' and 'pointcut' + slightly specially which can break a few unusual pure Java programs. + This is a compiler limitation that will be fixed in a future release.) + + + + + Deprecated syntax warnings -- the syntax of AspectJ + changed many times from version 0.2 to the 1.0 release. It was easier + to provide helpful warning messages for these changes with our + hand-written parser. + + + + + Grammar modularity -- We like being able to have + AspectJParser extend JavaParser. + + + + + Part of the grammar for AspectJ is extremely hard for existing tools to + capture. This is the type pattern syntax, i.e. "com.xerox..*.*(..)". + The sort of case that gives standard parser generators fits is something + like "*1.f(..)" which no one would ever write, but which must be + supported for a consistent language. + + + + + + + + Integrating AspectJ into your development environment + + + How do I know which aspects affect a class when looking + at that class's source code? + + + + When you are working with the IDE support, you can get an + understanding of which aspects affect any class. + This enables AspectJ programmers to get the benefits of + modularizing crosscutting concerns while still having immediate + access to what aspects affect a class. + + For example, the + + Development Environment Guide + section + on ajbrowser shows that you can list or navigate + between method and advice affecting that method and between a type + and declarations in an aspect on that type. (The IDE support may + have more features than ajbrowser, depending + on the IDE.) + + + When you are looking at documentation, + ajdoc will provide links from aspects and + advice to the affected code, but it provides less information + than the IDE support because it only parses declarations. + + + When you are running your program, + you can trace advice as it executes. This + enables you to identify advice on join points picked out + dynamically, which cannot be reflected precisely by IDE support. + + See for more + information on which Java development environments are + supported. + + + + + + What kind of IDE support is available for developing + AspectJ programs? + + + + See + + + + + I want the aspects for development builds but + remove them for production builds. How can I set up the build + system so they are unpluggable? And so I use javac + in my production build? + + + + + If you are using development-time-only aspects - aspects that only + exist when you are developing the code, not when you ship it - + you can use implement a hybrid build process by listing + the production source files into a javac-compliant argfile, + and the development source files in another ajc argfiles: + + + -- file "production.lst": + One.java + two/Three.java + ... + + -- file "tracing.lst": + trace/Library.java + Trace.java + + -- file "development.lst": + @production.lst + @tracing.lst + + + Then your development build can use ajc: + + + ajc @development.lst + + + And your development build can use + ajc or javac + or jikes: + + + jikes @production.lst + + + + + + What plans are there to support my IDE? + + + + The AspectJ team directly provides components for JBuilder, Forte, + and Emacs. We also support the open-source AspectJ plugin project + at http://eclipse.org/ajdt + which uses the AJDE API support for IDE's. We + are interested in supporting other developers as they use AJDE + to provide components for the following IDE's (roughly in + order of interest and viability). + + + + IDEA/IntelliJ has an enthusiastic community and + the developers are working on an extensibility API + - http://intellij.com + + + + jEdit comes from a very active open-source community. + + + + Oracle JDeveloper has an Extension SDK unfamiliar to us. + + + + Together extensibility API is too limited + + + + VisualCafe may have a difficult extensibility API + + + + + IBM's VisualAge for Java is to be replaced with Eclipse + + + + Some have suggested Codeguide from Omnicore + http://www.omnicore.com/ + + + Visual SlickEdit ?? + Kawa has been discontinued + VIM has been suggested. + + + + If you would like to build support for an IDE, contact us so we can help. + To contribute or propose new IDE's, please + mail us. + + + + + + Can I port AJDE support to my development environment? + + + Yes. The core AJDE API is extensible and the source code is + available for download. Start by studying the sources + for the existing IDE support. + + + + + + Programming notes and tips + + + Is it possible to change methods by introducing keywords (like + synchronized), adding parameters, + or changing the "throws" clause? + + + + AspectJ does not enable you to change the signature of a method, + but you can (by express declaration) work around some + limits imposed by the signature. You can convert a checked exception to + unchecked using declare soft, privileged aspects + have access to private methods, and you can use a percflow aspect to + ferry additional state to a callee without changing intervening + signatures. For more details, see + The AspectJ Programming Guide. + In the case of synchronized, + we have what we consider a better solution that uses + around advice instead of introduction. This solution is described + in + + this thread + on the AspectJ users list, with some + + additional comments + . + + + + + + + I don't understand what join points exist. How can I see them? + + + + + Try using an aspect posted to the user's list called + + TraceJoinPoints.java + . + For example, you can start logging at a particular method call and + see what join points occur after the call and before it returns. + + + + + + + What is the difference between call and execution join points? + + + + Consider method execution in Java as (1) the initial call from + this object to some method on the target object with a + particular signature; and (2) the execution of the actual code + in the particular method dispatched in the target object. + The call join point starts with the initial call and ends + when control returns to the call (by return or perhaps + thrown exception). The execution join point starts with + the method body and ends when the body completes (again + by return or throwing an exception), so the execution join + point always happens within the bounds of the corresponding + call join point. You can see this if you use the + join-point tracing aspect in + + TraceJoinPoints.java + . + as described above. + + As you would expect, the context differs + in advice on pointcuts picking out execution and call join + points; for call, this refers to the caller, whereas + for execution this refers to the called + (executing) object. + + + There are some subtle interactions with other AspectJ semantics. + First, the meaning of the signature in the + execution() and call() + pointcut designators (PCD's) differ: the call type depends upon + the type of the reference making the call, while the execution + type depends on the enclosing class. + Second, you may choose one over another if you cannot bring all + your sources within the code the compiler controls + (described in the appendix + to the Programming Guide). + For example, to trace calls into a + method from classes which are outside the code the compiler controls + at compile time, then using execution() will work + while using call()may not. Finally, since + super invocations are not considered method calls, + to trace super.foo() would require using + execution. + + + In most cases you should use the call() + pointcut designator unless you have a good reason to use + execution() + + + + + + + What is the difference between cflow and cflowbelow? + + + + + Both pick out all the join points in the control flow of + the specified join points. + They differ only in that the cflowbelow() + pointcut designator does not pick out the join points + specified, while cflow() does. + + + + + + + What is the difference between call and execution? + + + + + There are two interesting times when a constructor or method is + run. Those times are when it is called, and when it actually + executes. + + + The main difference is that a call join point happens outside of + the object (for non-static methods) or class (for static methods + and constructors), and that an execution join point happens inside + the object or class. This means that the within + and withincode pointcuts pick them out + differently: A call join point is picked out within the caller, + while an execution join point is picked + out where it is actually defined. + + + A call join point is the ``outermost'' join point for a particular + call. Once a call join point proceeds, then a number of different + things happen. For non-static methods, for example, method + dispatch happens, which will cause one method execution join point + -- perhaps more, if there are super calls. For constructors, the + super constructor is called, and fields are initialized, and then + various constructor execution join points will occur. + + + A call join point matches only the ``external'' calls of a method + or constructor, based on a signature, and it does not pick out + calls made with super, or + this constructor calls. + + + + + + How do I say that I want the topmost entrypoint in a + recursive call? How about the most-recent prior entrypoint? + + + + This is best seen by way of example. + Given a recursive call to int factorial(int) + you can print the arguments for + (a) the current and most-recent recursive call + or (b) the current and original recursive call: + + +aspect LogFactorial { + pointcut f(int i) : call(int factorial(int)) && args(i); + + // most-recent + before(int i, final int j) : f(i) && cflowbelow(f(j)) { + System.err.println(i + "-" + j); + } + + // original + before(int i, final int j) : f(i) + && cflowbelow(cflow(f(j)) && !cflowbelow(f(int))) { + System.err.println(i + "@" + j); + } +} + + + + + + What is the difference between constructor call, + constructor execution, initialization, and static + initialization join points? + + + + Static initialization pertains to initialization of + a class or interface type. Constructor call and execution + are akin to method call, and initialization generalizes this and + picks out the first constructor called. + + Their relations are best + demonstrated by tracing the join points. Below is the class + Test which implements an interface and extends a class + along with a trace of the join points below and including + the constructor call obtained using + TraceJointPoints.java (linked above). + + + + + + + + + + + + + + + + + + +]]> + + + Ordinarily, using a call pointcut designator + is best because the call join point surrounds the others, but in + the case of constructors there is no target object for + the call (because it has not been constructed yet), so you + might prefer to use the initialization + pointcut designator. + + + + + + + I want advice to run at two pointcuts, but it doesn't run at all. What gives? + + + + + This reflects both a conceptual error and a programming mistake. + Most likely you want to do something like "run the advice for all + public and private calls," and the code looks something like this: + + + within(com.xerox.printing..*) && call(public * *(..)) && call(private * *(..)) + + + A pointcut picks out join points; it is evaluated at each join point. + The expression above would never pick out any call join point, + because no method signature has both public and private access. + In a pointcut, pc1() && pc2() means both + must be true at a given join point for advice to run at that join point. + The correct pointcut would use || as follows: + + + within(com.xerox.printing..*) && (call(public * *(..)) || call(private * *(..))) + + + Then the advice will run at the join point. + + + + + + + How do I refer to a static field when my advice crosscuts multiple classes? + + + + There is no way in advice to refer to the type of the + code executing in a static context except by specification. + This makes it impossible to refer to static members using + runtime information. + + + + + + I would like to reuse a type pattern, e.g., to + write advice that is limited to a certain set of classes. + Do I have to retype it each time? + + + + No. You can declare that all the types implement + an interface you define, and then use the interface type in + your program. For example: + + +/** + * Example of using an interface to represent a type pattern. + * sub-aspects use declare parents to add to traced types, e.g., + * declare parents: com.mycompany.whatever..* implements Marked; + */ +abstract aspect MarkerExample { + /** marker interface for types that we want to trace */ + interface Marked {} + + /** calls to an instance of Marked not from an instance of Marked */ + pointcut dynamicCallsIn(): call(* *(..)) && target(Marked) && !this(Marked); + + /** calls to methods defined by a subtype of Marked + * that don't come from the body of a subtype of Marked + */ + pointcut staticCallsIn(): call(* Marked+.*(..)) && !within(Marked+); + + /** print dynamic calls */ + before(): dynamicCallsIn() { System.out.println("before " + thisJoinPoint); } +} + +aspect MyMarker extends MarkerExample { + declare parents: com.mycompany.whatever..* implements Marked; +} + + + + + + Where do I find example programs? + + + Some examples are distributed in the documentation release, + and you can find other code in the discussions on the users list. + + + + + + Are aspect libraries available? + + + Some libraries are distributed in the release under the + examples folder in the distribution. If you develop a library and + want to make it available to other users, make sure to + + contact us + . + + + + + + How does ajc interact with the + serialVersionUID? + + + + The current version of ajc can change the + serialVersionUID of generated + .class files as a result of weaving in advice. + This is an important fact that developers using both aspects and + serialization should be aware of. It is likely that a future + version of the compiler will be better behaved regarding the + serialVersionUID. + + However, changes to the serialVersionUID + attribute are typically only important when using serialization for + the long-term persistence of objects. Using standard Java + serialization for long-term persistence has a number of drawbacks + and many developers already use alternative solutions. For one + possibly standard solution, see + + Lon + g-Term Persistence for JavaBeans Specification + . + + + + + + How can I use AspectJ with applets? + + + + Just include the aspectjrt.jar as a required archive. + For example, here is the HTML code for an HTML editor + applet that contains some debugging aspects: + + + + + + + + +]]> + + + The above markup has worked reliably with the Java Plugin + (included in the JRE 1.4.x) in IE 6, Mozilla 1.1 (Win32), + and Mozilla 1.0.1 (Red Hat Linux 8.0). + The following link describes how to configure Mozilla/Netscape + 6.x/7.x to use the Java Plugin from a JRE/SDK installation: + + http://java.sun.com/j2se/1.4.1/manual_install_linux.html. + (Thanks to Chris Bartling for this answer.) + + + + + + How can I specify types for advice that captures primitives, void, etc.? + + + + In some cases, AspectJ allows conversion from values of primitive types to Object, + so that highly polymorphic advice may be written. This works if an advice parameter + or the return type for around is typed to Object. So: + + +class Test { + static int i; + public static void main(String[] args) { + i = 37; + } +} + +aspect TraceSet { + before(Object val): set(* Test.*) && args(val) { + System.err.println(val); + System.err.println(val.class); + } +} + + + will print out + + +37 +java.lang.Integer + + + For more information, see the Programming Guide + + semantics section "Context Exposure" + . + + + + + + Common Problems + + + When I run, I get a StackOverflowError + (or a long stack trace or no output whatsoever) + + + + Most likely this is a case of infinite recursion, + where advice is advising itself. It presents as a + StackOverflowError + or silence as the VM exhausts itself in the recursion. + + Of course, infinite recursion is possible in Java: + +public class Main { + public static void main(String[] args) { + try { + main(args); + } finally { + main(args); + } + } +} + + If you compile and run this program, and it will fail silently, trying + to process the finally clause even after throwing the StackOverflowError. + + Here's a similar AspectJ program where the recursion is + not so obvious: + + +aspect A { + after(): call(* *(..)) { System.out.println("after " + thisJoinPoint); } +} + + This re-invokes itself because it advises any call. + It invokes itself even after an exception is thrown, since + after advice, like a finally clause, runs even + after exceptions are thrown. You can fix this by following two practices: + + + (1) Use after returning to advise normal completions + or after throwing to advise abrupt completions. + If you use after or after throwing, + write the advice with the same care you would a finally clause, + understanding that it may run after some failure. + + (2) Avoid writing advice that advises itself. One simple way to + do so is to exclude the code within the current aspect: + + +aspect A { + after() returning: !within(A) && call(* *(..)) { + System.out.println("after " + thisJoinPoint); + } +} + + A better way is often to re-write the pointcut. + If the advice is advising itself accidentally, that's a sign that + the pointcut is not saying what you mean. + + +aspect A { + pointcut withinTargetClasses() : within(A+) || within(B+); + after() returning: withinTargetClasses() && call(* *(..)) { + System.out.println("after " + thisJoinPoint); + } +} + + + + + + I've declared a field on every class in + my package; how do I use it in advice? + + +aspect A { + boolean com.xerox..*.dirtyFlag; + after (Object target) returning + : target(target) && call(* com.xerox..*.set*(..)) { + target.dirtyFlag = true; // compile fails here + } +} + + + + You need a type to refer to any member, field or method. + It's generally better to introduce onto an interface and + declare classes to implement the interface, which permits you + to use the interface type in advice formals. + + +aspect A { + interface TrackingSets {} + boolean TrackingSets.dirtyFlag; + declare parents : com.xerox..* implements TrackingSets; + + after (TrackingSets target) returning + : target(target) && call(* com.xerox..*.set*(..)) { + target.dirtyFlag = true; + } +} + + + + + + The AspectJ compiler aborts with an OutOfMemoryError when + compiling many classes. How can I fix this? + + + + The command ajc is actually a script that + launches a Java virtual machine with the correct classpath. You + should make a copy of this script, rename it, and then edit it. + Change the -Xmx option, size of memory allocation pool (heap). You + might try -Xmx128M or even + -Xmx256M. + + + + + + + ajc recompiles all files every time. + How can I make it recompile only the files that have changed? + + + + + ajc 1.0 does not currently support incremental + compilation, but we are working on this for the 1.1 release. + + As a limited workaround, many build systems enable you to avoid + doing a compile if no sources have changed. (See, e.g., Ant's + "uptodate" task.) + + + + + + + ajc is using the wrong JVM. How do I + fix it? + + + + The easiest way to fix this is to re-install + ajc (using the same .class or + .exe file that you originally downloaded) and + this time make sure to tell it to use the desired JDK (typically + the JDK versions 1.2 or 1.3 from Sun). + + If you are familiar with DOS batch files or shell programming, + you could also fix this by simply editing the + bin\ajc.bat or bin/ajc + script. + + + + + + My IDE is trying to parse AspectJ files which makes my project unusable. + What can I do? + + + + + When working with an unsupported IDE that objects to the syntax of + AspectJ source files (and, e.g., automatically gathers them + in a source tree as Java files based on the .java extension), + you can use the .aj extension for your AspectJ files. + The ajc compiler accepts both .java and .aj files, and you can + set up your build scripts to include the correct list of + source files. (You will have to find another editor for + editing AspectJ files; you can use the ajbrowser to view + edit your AspectJ files and navigate the crosscutting structure.) + + + + + + I used to be able to compile my program in my IDE, but when I + use AJDE, I run out of memory (or it goes really slow). + + + + + The ajc compiler does more analysis than (e.g.,) javac, + and AJDE may in some IDE's hold a copy of the structure tree until the + next tree is available from the compile process. Both mean that you may + need extra memory to compile the same program. However, increasing + available memory to the point that you are swapping to disk can + slow the process considerably. + + + If you are having problems and would like to find the optimal memory + allocation, iteratively decrease the amount of memory available until + AJDE or ajc signals out-of-memory errors, and then increase that + amount by 5-10%. + + + To increase memory for the ajc compiler, see . + For your IDE, do something similar or follow the provider's instructions. + For example, to increase memory in JBuilder, edit the + jbuilderX/bin/jbuilder.config + file to have an entry like: + +vmparam -Xmx384m + + + + If it turns out that your project is too big to use with AJDE, your IDE + may nonetheless support external commands or Ant build processes, which + run outside the IDE memory space. For an Ant taskdef, see + . For a JBuilder Ant plugin, some + people have directed us to . + + + + + + + My stack traces don't make sense. What gives? + + + + Unless you are using the ajdb debugger, + stack traces may + have synthetic methods in the stack, and the line numbers may + not track your source code. The + Development Environment Guide. + discusses how to interpret stack at the end of the section + on the ajc compiler. + + + + + + + My advice is not running (or running twice), and I don't know why. + + + + When advice is not running, it is probably a problem in the + pointcut. Sometimes users specify pointcuts that do not mean what they intend - + most often when they misspell a type name. Run the compiler in + -Xlint mode, which will flag some likely mistakes, + like the type name. If that does not work, use + + TraceJoinPoints.java + to see if your join points are executing at all. + + When advice is running more than it should, it may be that your + pointcut picks out more join points than you intend. + If you are using IDE support, you should be able to trace back from + the pointcut or advice to the join points which can be statically + determined to be affected. To identify advised dynamic join points, + you can try using + + TraceJoinPoints.java + , but often it is easier to update the advice to + print the source location of the join point. + This will show if the advice applies to code that you did + not consider. + + If you've done this and convinced yourself it's not working, + it may be a bug. See . + + + + + + + I declared a member on a class with package access, but other classes in the package cannot see it. + + + + When declaring parents on other types from an aspect, package access only + applies to code the implementation controls. For AspectJ 1.0, that is the set of files + passed to the compiler. That means other classes not compiled with the aspect will not + be able to access the aspect-declared members even if they are in the same package. + The only way for classes outside the control of the implementation to access aspect-declared + members is to declare them public. + + + + + + + ajc complains that it can't find + javac. What's wrong? + + + + + ajc does not try to locate + javac in your path: it uses the + javac classes directly. In JDK 1.2 and 1.3 these + classes are found in tools.jar (in the + lib directory of the JDK distribution), which + must be on your classpath to make + ajc work with javac. + Inspect the java command that launches ajc to make sure that + tools.jar is on the classpath for ajc; + the -classpath option only applies to the sources compiled. + + + + + + + I'm running under 1.4, but ajdoc asks for 1.3 + (or throws IllegalAccessError for HtmlWriter.configuration) + + + + + The current implementation of ajdoc uses + specific javadoc classes in the J2SE 1.3 tools.jar. + We are working on addressing this limitation, but in the interim + it is best to run ajdoc under 1.3. + + + When running from the command-line scripts, edit the scripts directly + to put the 1.3 tools.jar first on the classpath. (The installer does + not know about this limitation of ajdoc.) + + + When running from Ant, users often have tools.jar in ${ant.classpath} + (to make javac, et al work). That makes it impossible to run the ajdoc + taskdef (which does not currently support forking), so you'll need to + run a separate ant process, either from the command-line or via Ant's + exec task (the Ant task will propagate the classpath). + If the wrong tools.jar is not on the ant classpath, then it should work + to put the 1.3 tools.jar in the taskdef classpath. + + + + + + I set up different files to my compiles to change what + the aspects see, but now I don't + understand how the aspects are working. + + + + It is a bad practice to use the compilation unit + to control crosscutting. Aspects and pointcuts especially + should be written to specify crosscutting precisely. + Aspects will behave the same when you add files if + you initially included all files affected by your aspects. + If you use the compilation unit, then your code will behave + differently in AspectJ implementations that do not limit + themselves to specified files. + + + + + + I'm reading the code generated by ajc + in -preprocess mode, and it seems like it would not + work (or "like it works this way"). + + + + The generated code can be difficult for a human to read and + understand. The compiler uses implementation techniques which might + not be apparent. To determine if the code is behaving correctly, you + should write and run a program that attempts to provoke the error you + suspect. Similarly, you should not rely on invariants you infer from + the generated code (especially naming conventions for generated members). + Please rely only on the semantics stated in the appendix of the + AspectJ Programming Guide. + + + + + + I've heard AspectJ can generate or inject code into my code. + Is this true? + + + + + This is a misconception spawned from the early implementation. + + + AspectJ does not "inject" or "generate" code. In AspectJ the + pointcut constructs allow the programmer to identify join points, + and the advice constructs define additional code to run at those + join points. + + + So the semantic model of advice is like the semantic model of a + method -- it says "when any of these things happen, do this". + + + People who worked with earlier versions of AspectJ, in which ajc + was very explicitly a pre-processor, sometimes thought of AspectJ + as injecting code. But that was an artifact of the implementation, + not the underlying language semantics. + + + This distinction is important for two reasons. One is that thinking + about it this way will make more sense at the implementation continues + to evolve towards load-time or runtime weaving. The other is that + it makes it much easier to understand the semantics of advice on + cflow pointcuts. + + + + + + What are the bugs now most affecting users? + + + + + + 813 + - Ajdoc requires J2SE 1.3 tools.jar, not that of 1.2 or 1.4. + + + + + + + + Getting Help + + + + How do I find out more about AspectJ? + + + + Visit the AspectJ project web site: + http://aspectj.org. + + + + + + How do I submit a bug report? + + + You can submit a bug using the web interface + http://aspectj.org/bugs + (preferred), or you may send email to + jitterbug@aspectj.org directly. + See also + +If it seems to be a bug in the compiler, + please include in the body of the email source code to reproduce the problem. + + + + + + + How do I submit comments and feature requests? + + + + You can email comments to all users at + users@aspectj.org, + email the AspectJ team at + support@aspectj.org. + You can view and submit bug reports and feature requests at + http://aspectj.org/bugs. + If you think you might simply be making a mistake, you might + email some source code to + users@aspectj.org. + + + + + + + How do I communicate with other AspectJ users? + + + + You can reach other AspectJ users by using the + aspectj-users mailing list. To subscribe to the list or view the + list archives go to the user community page: + + http://aspectj.org/lists + . + + + + + + + How can I search the email archives or the web site? + + + + + There is a search entry box on the left navigation bar of the web site, + but it is generally more effective to do a google search of the form, + + http://www.google.com/search?q=site%3Aaspectj.org+%22abstract pointcuts%22 + + + + + + + + How should I write email queries? + + + + + + + Here's the big picture of what I'm trying to do... + + + + + Here's what I think it takes, in AspectJ terms + (concepts, syntax, and semantics) from the + Programming Guide... + + + + + Here's the AspectJ code I'm using, the output it + produces when run, and what I expect... + + + + + The big picture helps others redirect you to other approaches. + Using AspectJ terms helps others correct mistakes in thinking + about the problem (the most common being to confuse join points + and pointcuts). + The code is key to clarifying your question and getting a good + response. On the mail list, someone can reply by fixing your + code. In bugs, the developers can reproduce the problem immediately + and start analyzing the fix. + + + For the mail lists, we try to follow the conventions for open-source + discussions that help avoid "the tragedy of the commons." + For example conventions, see + + http://jakarta.apache.org/site/mail.html + and + + http://www.tuxedo.org/%7Eesr/faqs/smart-questions.html + . + + + + + + + How do I write bugs for IDE support? + + + + + Bugs appearing in the IDE's may apply to the affected IDE + or to the compiler. Compiler stack traces in IDE message windows + are prefixed "Internal Compiler Error" and should be written up + as compiler bugs. If you are unsure, try redoing the compile + from the command line. + + + Bug reports for the Eclipse support go to the Eclipse + + bugzilla + database. + Bug reports on other IDE support should have version + information for both Java and the IDE, and + (most importantly) clear steps for reproducing the bug. + You may submit the bugs via the web form + (http://aspectj.org/bugs) + or via email + (jitterbug@aspectj.org). + + + One of the benefits of open-source is that you can + find and fix the bug for yourself; when you submit + the fix back to us, we can validate the fix for you + and incorporate it into the next release. Email + support@aspectj.org + for instructions on submitting a patch. + + + + + + + How do I write bugs for the AspectJ compiler? + + + + + The best compiler bug report is a reproducible test case, + standalone code that demonstrates the problem. + Sometimes with aspects, a test case requires several + files, if not some way to capture the behavior. + Here's how we recommend submitting test cases: + + + + Write the test case so that when the compiler bug + is fixed, the test completes normally without output + (e.g., expected compiler errors are issued, + or classes produced run correctly). This usually + means writing one or more source files. + + + + + In the bug report, briefly summarize the bug. + If it is not obvious, be sure to specify + the expected output/behavior (e.g., compiler error on line 32) + and, if the compile should complete, the main class to run. + + + + + At the end of the report, append each source file, + separated with a line and the file name. + (Include all sources, and do not send attachments.) + + + + + Submit the bugs via the web form + (http://aspectj.org/bugs) + or via email + (jitterbug@aspectj.org). + + + + + + + + + + Can you recommend reading or teaching material for AspectJ? + + + + The documentation available on this site is a primary source of + material on AspectJ: + + + + + + + Selected AspectJ Papers and Presentations + + + Papers presented at various conferences; tutorial + slide presentations. + + + + + + Aspect-Oriented Programming + + + + The seminal AOP/AspectJ paper + + + + + + The AspectJ Programming Guide + + + A practical guide for programmers. + Includes a number of examples, some quite + sophisticated. + + + + + The AspectJ Tutorial + + Slides from a day-long tutorial presentation on + AspectJ. + + + + + + + + + + + + Where can our group get consulting and support? + + + + Beyond what's available on the aspectj.org web site, + the AspectJ team does a limited amount of consulting + and support for qualified groups. For more information, + see . + + + + + + + What has changed since the last FAQ version? + + + + + Entries changed since the earlier September 13 version: + + + + + + + + + + + + + + + + + + + + + + + About the AspectJ Project + + + What does the fact that AspectJ is an Open Source + Project mean to me? + + + + Open source protects your interest in a correct, long-lived, + up-to-date, and widely-accepted implementation of AspectJ. + + + With the source code, you control your own destiny + in perpetuity. You can continue to use the implementation + and update it as necessary to fix bugs and add things you need. + + + + Because the code is available to all, anyone can find + and fix bugs. There is no need to hope for it to be fixed + in the next product release. Those who encounter the bugs + are motivated to fix them, and there are more eyeballs on + the code than in closed-source, so the quality tends to be high. + This can be particularly true for the AspectJ community, + which tends to be highly skilled. + + + + The same is true of new features or behavior, so the + implementation should be up-to-date. This is important as + the field of AOP develops, to capture the latest solutions. + + + + For a programming language which forms the basis of + an entire solution stack, open source facilitates the kind + of adoption -- tool integrations and significant projects -- + that develop and prove the technology for wider adoption. This + limits delays caused by waiting for the completion of standards + process or promulgation by industry leaders, and also provides + the proofs necessary for such adoption. + + + + + + + + + What are your plans to make AspectJ a general feature + of Java supported by Sun and the other key players in the Java + Industry? + + + + Although we are committed to making AspectJ available to a wide + range of users, it is too early to decide on a strategy. Some + options include continuing AspectJ as a stand-alone product, + integrating it into IDEs, or possibly incorporating it into + standard Java with Sun's blessing. + + We currently focus on developing for the 1.1 implementation + which improves AspectJ in key areas: rapid + incremental compilation, bytecode weaving, and IDE integration. + + Through all of this our goal is to make AspectJ integrate as + seamlessly as possible with the Java programming language. The + AspectJ language design is becoming more integrated, the compiler + is becoming faster and more integrated, the IDE extensions are + becoming more integrated. All of this is designed to help users + really use AspectJ and give us feedback on it. + + As the system is improved and we work more closely + with users, we will be in good position to explore the best path + for AspectJ in the long term. + + + + + + When will AspectJ work from class files? + When will it work at class-loading time? + + + + Bytecode weaving is scheduled for AspectJ 1.1. We believe it + will work as described in an email to the users list by Jim Hugugin: + + + The AspectJ language was designed to support weaving at many different times: + compile, load, or even run-time in the JVM. Weaving into bytecodes at both + compile and load-time will definitely be provided in a future release. This + will allow weaving at compile-time into libraries for which source code is + not available. It will also support aspect-aware class loaders that can + perform weaving at load time on arbitrary classes. One advantage of a + language like AspectJ, rather than an explicit meta-tool like jiapi, is + that it separates the specification of a crosscutting concern from any + particular implementation strategy for weaving. + + + ...AspectJ provides a language that can cleanly + capture crosscutting concerns while preserving the static type checking, + modularity, and composability of Java. + + If you have an application for using aspects and bytecode, + please let the AspectJ team know of your requirements. + + + + + + What are the differences between the current and + previously released versions of AspectJ? + + + + The AspectJ team aims to keep the implementation up-to-date + and bug-free, but to limit language changes to those that + are carefully considered, compelling, and backwards-compatible, + and to deliver those language changes only in significant releases (1.0, 1.1). + + + + + + + Version + Description + + + AspectJ 1.0 + Many language changes, fixes, cleanup and + clarifications, some significant. + + + + AspectJ 0.8 + More cleanup of the syntax and semantics. + + + AspectJ 0.7 + Clean up of the semantics, 0.7 beta 4 is the first + open source release. + + + + AspectJ 0.6 + Advice and crosscuts get explicit type signatures + which describe the values that are available to advice at a + crosscut. + + + + AspectJ 0.5 + Improved tool support: better Emacs environment + support and ajdoc to parallel + javadoc. around advice is added, and the + aspect keyword is removed and replaced + by the Java keyword class. + + + + AspectJ 0.4 + Clear separation of crosscuts and crosscut actions + makes it possible to define extensible library + aspects. + + + + AspectJ 0.3 + First all Java implementation, also includes many + small language improvements. + + + + AspectJ 0.2 + General-purpose support for crosscutting. Users could + program any kind of aspects, not just coordination. This + release dropped COOL. + + + + AspectJ 0.1 + A single domain-specific aspect language, called COOL, + for programming coordination in multi-threaded + programs. + + + + +
    + More detailed comments are available in the + doc/changes.html file in the + distribution. + +
    +
    + + + + What is the AspectJ development schedule? + + + + + The AspectJ Development Schedule + + + + Version + Description + + + 1.0 + Final syntax and semantic changes. Standalone structure + browser. Complete documentation. + + + + 1.1 + Faster incremental compilation, bytecode weaving, + and a small number of language changes. + + + 2.0 + New, dynamic crosscuts (bytecode-only) + + + +
    +
    +
    +
    +
    + AspectJ is a registered trademark of Palo Alto Research Center, Incorporated (PARC). + Java and all Java-based marks are trademarks or registered trademarks of + Sun Microsystems, Inc. in the United States and other countries. All other + trademarks are the property of their respective owners. + +
    + diff --git a/docs/install/finish.html b/docs/install/finish.html new file mode 100644 index 000000000..ef1bef64e --- /dev/null +++ b/docs/install/finish.html @@ -0,0 +1,20 @@ + + + + + + + +New Page 1 + + + + +

    The automatic installation process is complete.

    + +

    See ${installer.output.readme} for more information about +the contents of this package.

    + + + + diff --git a/docs/install/install-finish.html b/docs/install/install-finish.html new file mode 100644 index 000000000..811f11400 --- /dev/null +++ b/docs/install/install-finish.html @@ -0,0 +1,20 @@ + + + + + + + +New Page 1 + + + + +

     

    + +

    The automatic installation process is complete.  Press Next for +some final instructions.

    + + + + diff --git a/docs/install/install-start.html b/docs/install/install-start.html new file mode 100644 index 000000000..858ed8512 --- /dev/null +++ b/docs/install/install-start.html @@ -0,0 +1,21 @@ + + + + + + + +New Page 1 + + + + +

     

    + +

    Now installing to ${installer.output.dir}.

    + +

    Press Cancel to interrupt the installation.

    + + + + diff --git a/docs/install/intro.html b/docs/install/intro.html new file mode 100644 index 000000000..55de23fbf --- /dev/null +++ b/docs/install/intro.html @@ -0,0 +1,24 @@ + + + + + + + +New Page 1 + + + + +

    Installer for AspectJ(TM) Documentation and Examples

    + +

    Version ${build.version.long} built on ${build.date}

    +

    ${copyright.allRights.from1998}

    +

    + +

    Press Next to continue. At any time you may press Cancel +to exit the installation process.

    + + + + diff --git a/docs/install/location.html b/docs/install/location.html new file mode 100644 index 000000000..5eb2c5a8c --- /dev/null +++ b/docs/install/location.html @@ -0,0 +1,23 @@ + + + + + + + +New Page 1 + + + + +

     

    + +

    Please select a directory into which to install the aspectj documentation and +examples.  If you've already installed the compiler and core tools, we +recommend that you install the documentation and examples to the same directory +for convenience.

    +

    Press Install to begin the installation process to this directory.

    + + + + diff --git a/docs/progGuideDB/aspectjdoc.dsl b/docs/progGuideDB/aspectjdoc.dsl new file mode 100644 index 000000000..37ce64bd6 --- /dev/null +++ b/docs/progGuideDB/aspectjdoc.dsl @@ -0,0 +1,124 @@ + + +]> + + + + + + + + +;; Specify the CSS stylesheet to use +(define %stylesheet% "../../style.css") + +;; Suppress Lists of Tables, Examples, ... +(define ($generate-book-lot-list$) + '()) + +;; Display only the first two section levels in the table of contents +(define (toc-depth nd) + (if (string=? (gi nd) (normalize "book")) + 2 + 1)) + +;; Make references be appendices (or chapters), not parts. +(define (en-label-number-format-list) + (list + (list (normalize "set") "1") + (list (normalize "book") "1") + (list (normalize "prefix") "1") + (list (normalize "part") "I") + (list (normalize "chapter") "1") + (list (normalize "appendix") "A") + ;;(list (normalize "reference") "1") ; references-as-chapters + (list (normalize "reference") "A") ; references-as-appendices + (list (normalize "example") "1") + (list (normalize "figure") "1") + (list (normalize "table") "1") + (list (normalize "procedure") "1") + (list (normalize "step") "1") + (list (normalize "refsect1") "1") + (list (normalize "refsect2") "1") + (list (normalize "refsect3") "1") + (list (normalize "sect1") "1") + (list (normalize "sect2") "1") + (list (normalize "sect3") "1") + (list (normalize "sect4") "1") + (list (normalize "sect5") "1") + (list (normalize "section") "1") + )) + ;;; for references-as-appendices + (define (reference-number-sibling-list cmp) (list (normalize "appendix"))) + (define (appendix-number-sibling-list cmp) (list (normalize "reference"))) + ;;; for references-as-chapters + ;;(define (reference-number-sibling-list cmp) (list (normalize "chapter"))) + ;;(define (chapter-number-sibling-list cmp) (list (normalize "reference"))) + + + + + + + + + + + + +;; Suppress Lists of Tables, Examples, ... +(define ($generate-book-lot-list$) + '()) + +;; Display only the first two section levels in the table of contents +(define (toc-depth nd) + (if (string=? (gi nd) (normalize "book")) + 2 + 1)) + +(define %two-side% #t) +(define bop-footnotes #t) ; doesn't seem to work + +;; Make references be appendices (or chapters), not parts. +(define (en-label-number-format-list) + (list + (list (normalize "set") "1") + (list (normalize "book") "1") + (list (normalize "prefix") "1") + (list (normalize "part") "I") + (list (normalize "chapter") "1") + (list (normalize "appendix") "A") + ;;(list (normalize "reference") "1") ; references-as-chapters + (list (normalize "reference") "A") ; references-as-appendices + (list (normalize "example") "1") + (list (normalize "figure") "1") + (list (normalize "table") "1") + (list (normalize "procedure") "1") + (list (normalize "step") "1") + (list (normalize "refsect1") "1") + (list (normalize "refsect2") "1") + (list (normalize "refsect3") "1") + (list (normalize "sect1") "1") + (list (normalize "sect2") "1") + (list (normalize "sect3") "1") + (list (normalize "sect4") "1") + (list (normalize "sect5") "1") + (list (normalize "section") "1") + )) + ;;; for references-as-appendices + (define (reference-number-sibling-list cmp) (list (normalize "appendix"))) + (define (appendix-number-sibling-list cmp) (list (normalize "reference"))) + ;;; for references-as-chapters + ;;(define (reference-number-sibling-list cmp) (list (normalize "chapter"))) + ;;(define (chapter-number-sibling-list cmp) (list (normalize "reference"))) + + + + + + + + + + diff --git a/docs/progGuideDB/aspects.gif b/docs/progGuideDB/aspects.gif new file mode 100644 index 000000000..8bca684ad Binary files /dev/null and b/docs/progGuideDB/aspects.gif differ diff --git a/docs/progGuideDB/bibliography.xml b/docs/progGuideDB/bibliography.xml new file mode 100644 index 000000000..4d6c1f80f --- /dev/null +++ b/docs/progGuideDB/bibliography.xml @@ -0,0 +1,70 @@ + + + Bibliography + + + + + + + + + + + + + + + + + + + + + Doug Lea + + + Concurrent Programming in Java, Second Edition + + Addison-Wesley +
    Reading, MA
    +
    + 1999 +
    + + + + + Gregor Kiczales, et al + + + An Overview of AspectJ + + in Proceedings of the 5th European Conference on Object + Oriented Programming (ECOOP), Springer +
    Budapest, Hungary
    +
    + 2001 +
    + + + + + BetrandMeyer + + + Object-Oriented Software Construction, 2/e + + Prentice-Hall +
    New York, NY
    +
    + 1999 +
    + +
    + + + + + + diff --git a/docs/progGuideDB/build.sh b/docs/progGuideDB/build.sh new file mode 100644 index 000000000..19499ff3b --- /dev/null +++ b/docs/progGuideDB/build.sh @@ -0,0 +1,79 @@ +#/bin/sh + +JAVA_HOME="/opt/IBMJava2-13" +DOCBOOK_HOME="/usr/local/docbook" + +SAXON="/home/vladimir/aspectj-external-lib/saxon" +XERCES="/usr/local/xerces-1_4_3" + +saxon() { java -cp $SAXON/saxon.jar com.icl.saxon.StyleSheet $*; } +xerces() { java -cp $XERCES/xercesSamples.jar sax.SAXCount -v $* ; } + +# echo ""; echo "" +# echo "The following REMARKS still exist:"; echo "" +# egrep -n -A3 "" *.xml +# echo ""; echo "" + +# echo "Checking for required RPMS..." +# for RPM in docbook-dtd docbook-xsl; do +# rpm -q $RPM >/dev/null +# if [ $? = 1 ]; then +# echo "${RPM}: Required RPM not installed. Exiting..." +# exit 1 +# fi +# done + +# echo "Checking for required programs..." +# for PROG in java tex; do +# type $PROG >/dev/null 2>/dev/null +# if [ $? = 1 ]; then +# echo "$prog not found in PATH. Exiting..." +# exit 1 +# fi +# done + +# echo "Checking for required files..." +# for FILE in $JAVA_HOME/jre/lib/ext/saxon.jar; do +# if [ ! -s $FILE ]; then +# echo "$FILE not found. Exiting..." +# exit 1 +# fi +# done + +OPT=$1 +shift 1 + +if [ "$OPT" == "-v" ]; then + COMMAND="xerces -v progguide.xml" + echo " Validating the XML source: $COMMAND" + ${COMMAND} +fi + +if [ "$OPT" == "-t" ]; then + COMMAND='openjade -t tex -d aspectjdoc.dsl#print /usr/share/sgml/xml.dcl progguide.xml' + echo " Creating TeX from XML: $COMMAND" + ${COMMAND} + COMMAND="pdfjadetex progguide.tex" + echo " Creating PDF from TeX: $COMMAND" + ${COMMAND} + ${COMMAND} + exit +fi + +COMMAND="saxon -w0 progguide.xml progguide.html.xsl" +echo " Transforming XML to HTML: $COMMAND" +${COMMAND} + +# echo "Transforming XML to FO..." +# saxon -w0 -o progguide.fo progguide.xml ${XSL_STYLESHEET_HOME}/fo/docbook.xsl >progguide.fo.log 2>&1 + +# echo -n "Transforming FO to PostScript" +# tex --interaction nonstopmode -fmt /usr/local/texmf/tex/xmltex/base/xmltex progguide.fo >|progguide.ps.1.log 2>&1 +# echo "Pass 2..." +# tex --interaction nonstopmode -fmt /usr/local/texmf/tex/xmltex/base/xmltex progguide.fo >|progguide.ps.2.log 2>&1 +# dvips progguide -o + +# echo "Transforming FO to PDF..." +# pdflatex --interaction nonstopmode -fmt /usr/local/texmf/tex/xmltex/base/pdfxmltex progguide.fo >|progguide.pdf.log + + diff --git a/docs/progGuideDB/examples.xml b/docs/progGuideDB/examples.xml new file mode 100644 index 000000000..2e6a1715d --- /dev/null +++ b/docs/progGuideDB/examples.xml @@ -0,0 +1,2343 @@ + + Examples + + + About this Chapter + + This chapter consists entirely of examples of AspectJ use. + + + + + The examples can be grouped into four categories: + + + technique + Examples which illustrate how to use one or more features of the + language. + + development + Examples of using AspectJ during the development phase of a + project. + + production + Examples of using AspectJ to provide functionality in an + application. + + reusable + Examples of reuse of aspects and pointcuts. + + + + + + + Obtaining, Compiling and Running the Examples + + The examples source code is part of AspectJ's documentation + distribution which may be downloaded from the AspectJ download page. + + Compiling most examples should be straightforward. Go the + InstallDir/examples + directory, and look for a .lst file in one of the + example subdirectories. Use the -arglist option to + ajc to compile the example. For instance, to compile + the telecom example with billing, type + + +ajc -argfile telecom/billing.lst + + + To run the examples, your classpath must include the AspectJ run-time + Java archive (aspectjrt.jar). You may either set + the CLASSPATH environment variable or use the + -classpath command line option to the Java + interpreter: + + +(In Unix use a : in the CLASSPATH) +java -classpath ".:InstallDir/lib/aspectjrt.jar" telecom.billingSimulation + + + +(In Windows use a ; in the CLASSPATH) +java -classpath ".;InstallDir/lib/aspectjrt.jar" telecom.billingSimulation + + + + + + + + + + + Basic Techniques + + This section presents two basic techniques of using AspectJ, one each + from the two fundamental ways of capturing crosscutting concerns: with + dynamic join points and advice, and with static introduction. Advice + changes an application's behavior. Introduction changes both an + application's behavior and its structure. + + The first example, , is about gathering and using + information about the join point that has triggered some advice. The + second example, , concerns changing an existing class + hierarchy. + + + + + Join Points and <literal>thisJoinPoint</literal> + Join Points and + thisJoinPoint + + (The code for this example is in + InstallDir/examples/tjp.) + + A join point is some point in the + execution of a program together with a view into the execution context + when that point occurs. Join points are picked out by pointcuts. When a + join point is reached, before, after or around advice on that join + point may be run. + + When dealing with pointcuts that pick out join points of specific + method calls, field gets, or the like, the advice will know exactly what + kind of join point it is executing under. It might even have access to + context given by its pointcut. Here, for example, since the only join + points reached will be calls of a certain method, we can get the target + and one of the args of the method directly. + + + + + But sometimes the join point is not so clear. For + instance, suppose a complex application is being debugged, and one + would like to know when any method in some class is being executed. + Then, the pointcut + + + + will select all join points where a method defined within the class + ProblemClass is being executed. But advice + executes when a particular join point is matched, and so the question, + "Which join point was matched?" naturally arises. + + Information about the join point that was matched is available to + advice through the special variable thisJoinPoint, + of type org.aspectj.lang.JoinPoint. This + class provides methods that return + + + the kind of join point that was matched + + the source location of the current join point + + normal, short and long string representations of the + current join point + the actual argument(s) to the method or field selected + by the current join point + the signature of the method or field selected by the + current join point + the target object + the currently executing object + a reference to the static portion of the object + representing the current join point. This is also available through + the special variable thisJoinPointStaticPart. + + + + + The <classname>Demo</classname> class + + The class tjp.Demo in + tjp/Demo.java defines two methods + foo and bar with different + parameter lists and return types. Both are called, with suitable + arguments, by Demo's go + method which was invoked from within its main + method. + + + + + + + The Aspect <literal>GetInfo</literal> + + This aspect uses around advice to intercept the execution of + methods foo and bar in + Demo, and prints out information garnered from + thisJoinPoint to the console. + + + Defining the scope of a pointcut + + The pointcut goCut is defined as + so that only executions made in the control + flow of Demo.go are intercepted. The control + flow from the method go includes the execution of + go itself, so the definition of the around + advice includes !execution(* go()) to exclude it + from the set of executions advised. + + + + Printing the class and method name + + The name of the method and that method's defining class are + available as parts of the Signature, + found using the method getSignature of either + thisJoinPoint or + thisJoinPointStaticPart. + + + + + + Printing the parameters + + + The static portions of the parameter details, the name and + types of the parameters, can be accessed through the CodeSignature + associated with the join point. All execution join points have code + signatures, so the cast to CodeSignature + cannot fail. + + + The dynamic portions of the parameter details, the actual + values of the parameters, are accessed directly from the execution + join point object. + + + + + + Roles and Views Using Introduction + Roles and Views Using + Introduction + + (The code for this example is in + InstallDir/examples/introduction.) + + Like advice, pieces of introduction are members of an aspect. They + define new members that act as if they were defined on another + class. Unlike advice, introduction affects not only the behavior of the + application, but also the structural relationship between an + application's classes. + + This is crucial: Affecting the class structure of an application at + makes these modifications available to other components of the + application. + + Introduction modifies a class by adding or changing + + member fields + member methods + nested classes + + + and by making the class + + + implement interfaces + extend classes + + + + This example provides three illustrations of the use of introduction to + encapsulate roles or views of a class. The class we will be introducing + into, Point, is a simple class with rectangular + and polar coordinates. Our introduction will make the class + Point, in turn, cloneable, hashable, and + comparable. These facilities are provided by introduction forms without + having to modify the class Point. + + + + The class <classname>Point</classname> + + The class Point defines geometric points + whose interface includes polar and rectangular coordinates, plus some + simple operations to relocate points. Point's + implementation has attributes for both its polar and rectangular + coordinates, plus flags to indicate which currently reflect the + position of the point. Some operations cause the polar coordinates to + be updated from the rectangular, and some have the opposite effect. + This implementation, which is in intended to give the minimum number + of conversions between coordinate systems, has the property that not + all the attributes stored in a Point object + are necessary to give a canonical representation such as might be + used for storing, comparing, cloning or making hash codes from + points. Thus the aspects, though simple, are not totally trivial. + + + + The diagram below gives an overview of the aspects and their + interaction with the class Point. + + + + + + + + + + + + + + Making <classname>Point</classname>s Cloneable — The Aspect + <classname>CloneablePoint</classname> + + This first example demonstrates the introduction of a interface + (Cloneable) and a method + (clone) into the class + Point. In Java, all objects inherit the method + clone from the class + Object, but an object is not cloneable unless + its class also implements the interface + Cloneable. In addition, classes frequently + have requirements over and above the simple bit-for-bit copying that + Object.clone does. In our case, we want to update + a Point's coordinate systems before we + actually clone the Point. So we have to + override Object.clone with a new method that does + what we want. + + The CloneablePoint aspect uses the + declare parents form to introduce the interface + Cloneable into the class + Point. It then defines a method, + Point.clone, which overrides the method + clone that was inherited from + Object. Point.clone + updates the Point's coordinate systems before + invoking its superclass' clone method. + + + + Note that since aspects define types just as classes define + types, we can define a main method that is + invocable from the command line to use as a test method. + + + + Making <classname>Point</classname>s Comparable — The + Aspect <classname>ComparablePoint</classname> + + This second example introduces another interface and + method into the class Point. + + 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. + + The aspect ComparablePoint introduces + implements Comparable into + Point along with a + compareTo method that can be used to compare + Points. A Point + p1 is said to be less than + another Point p2 if + p1 is closer to the origin. + + + + + + Making <classname>Point</classname>s Hashable — The Aspect + <classname>HashablePoint</classname> + + The third aspect overrides two previously defined methods to + give to Point the hashing behavior we + want. + + The method Object.hashCode returns an unique + integer, suitable for use as a hash table key. Different + implementations are allowed return different integers, but must + return distinct integers for distinct objects, and the same integer + for objects that test equal. But since the default implementation + of Object.equal returns true + only when two objects are identical, we need to redefine both + equals and hashCode to work + correctly with objects of type Point. For + example, we want two Point objects to test + equal when they have the same x and + y values, or the same rho and + theta values, not just when they refer to the same + object. We do this by overriding the methods + equals and hashCode in the + class Point. + + The class HashablePoint introduces the + methods hashCode and equals + into the class Point. These methods use + Point's rectangular coordinates to generate a + hash code and to test for equality. The x and + y coordinates are obtained using the appropriate + get methods, which ensure the rectangular coordinates are up-to-date + before returning their values. + + + + Again, we supply a main method in the aspect + for testing. + + + + + + + + + + + + + Development Aspects + + + Tracing Aspects + + (The code for this example is in + InstallDir/examples/tracing.) + + + + Overview + + + Writing a class that provides tracing functionality is easy: a couple + of functions, a boolean flag for turning tracing on and off, a choice + for an output stream, maybe some code for formatting the output---these + are all elements that Trace classes have been + known to have. Trace classes may be highly + sophisticated, too, if the task of tracing the execution of a program + demands so. + + + + But developing the support for tracing is just one part of the effort + of inserting tracing into a program, and, most likely, not the biggest + part. The other part of the effort is calling the tracing functions at + appropriate times. In large systems, this interaction with the tracing + support can be overwhelming. Plus, tracing is one of those things that + slows the system down, so these calls should often be pulled out of the + system before the product is shipped. For these reasons, it is not + unusual for developers to write ad-hoc scripting programs that rewrite + the source code by inserting/deleting trace calls before and after the + method bodies. + + + + AspectJ can be used for some of these tracing concerns in a less ad-hoc + way. Tracing can be seen as a concern that crosscuts the entire system + and as such is amenable to encapsulation in an aspect. In addition, it + is fairly independent of what the system is doing. Therefore tracing is + one of those kind of system aspects that can potentially be plugged in + and unplugged without any side-effects in the basic functionality of + the system. + + + + + An Example Application + + + Throughout this example we will use a simple application that contains + only four classes. The application is about shapes. The + TwoDShape class is the root of the shape + hierarchy: + + + + + + TwoDShape has two subclasses, + Circle and Square: + + + + + + + + To run this application, compile the classes. You can do it with or + without ajc, the AspectJ compiler. If you've installed AspectJ, go to + the directory + InstallDir/examples and + type: + + + +ajc -argfile tracing/notrace.lst + + + To run the program, type + + +java tracing.ExampleMain + + + (we don't need anything special on the classpath since this is pure + Java code). You should see the following output: + + + + + + Tracing—Version 1 + + + In a first attempt to insert tracing in this application, we will start + by writing a Trace class that is exactly what we + would write if we didn't have aspects. The implementation is in + version1/Trace.java. Its public interface is: + + + + + + If we didn't have AspectJ, we would have to insert calls to + traceEntry and traceExit in all + methods and constructors we wanted to trace, and to initialize + TRACELEVEL and the stream. If we wanted to trace all + the methods and constructors in our example, that would amount to + around 40 calls, and we would hope we had not forgotten any method. But + we can do that more consistently and reliably with the following + aspect (found in version1/TraceMyClasses.java): + + + + + + This aspect performs the tracing calls at appropriate times. According + to this aspect, tracing is performed at the entrance and exit of every + method and constructor defined within the shape hierarchy. + + + + What is printed at before and after each of the traced + join points is the signature of the method executing. Since the + signature is static information, we can get it through + thisJoinPointStaticPart. + + + + To run this version of tracing, go to the directory + InstallDir/examples and + type: + + + + + + Running the main method of + tracing.version1.TraceMyClasses should produce + the output: + + + tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Circle(double, double, double) + <-- tracing.Circle(double, double, double) + --> tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Circle(double, double, double) + <-- tracing.Circle(double, double, double) + --> tracing.Circle(double) + <-- tracing.Circle(double) + --> tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Square(double, double, double) + <-- tracing.Square(double, double, double) + --> tracing.Square(double, double) + <-- tracing.Square(double, double) + --> double tracing.Circle.perimeter() + <-- double tracing.Circle.perimeter() +c1.perimeter() = 12.566370614359172 + --> double tracing.Circle.area() + <-- double tracing.Circle.area() +c1.area() = 12.566370614359172 + --> double tracing.Square.perimeter() + <-- double tracing.Square.perimeter() +s1.perimeter() = 4.0 + --> double tracing.Square.area() + <-- double tracing.Square.area() +s1.area() = 1.0 + --> double tracing.TwoDShape.distance(TwoDShape) + --> double tracing.TwoDShape.getX() + <-- double tracing.TwoDShape.getX() + --> double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.distance(TwoDShape) +c2.distance(c1) = 4.242640687119285 + --> double tracing.TwoDShape.distance(TwoDShape) + --> double tracing.TwoDShape.getX() + <-- double tracing.TwoDShape.getX() + --> double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.distance(TwoDShape) +s1.distance(c1) = 2.23606797749979 + --> String tracing.Square.toString() + --> String tracing.TwoDShape.toString() + <-- String tracing.TwoDShape.toString() + <-- String tracing.Square.toString() +s1.toString(): Square side = 1.0 @ (1.0, 2.0) +]]> + + + When TraceMyClasses.java is not provided to + ajc, the aspect does not have any affect on the + system and the tracing is unplugged. + + + + + Tracing—Version 2 + + + Another way to accomplish the same thing would be to write a reusable + tracing aspect that can be used not only for these application classes, + but for any class. One way to do this is to merge the tracing + functionality of Trace—version1 with the + crosscutting support of + TraceMyClasses—version1. We end up with a + Trace aspect (found in + version2/Trace.java) with the following public + interface + + + + + + In order to use it, we need to define our own subclass that knows about + our application classes, in version2/TraceMyClasses.java: + + + + + + Notice that we've simply made the pointcut classes, + that was an abstract pointcut in the super-aspect, concrete. To run + this version of tracing, go to the directory + examples and type: + + + + + + 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. + + + + The entire implementation of the new Trace class + is: + + + " + str); + } + private static void printExiting(String str) { + printIndent(); + stream.println("<-- " + str); + } + private static void printIndent() { + for (int i = 0; i < callDepth; i++) + stream.print(" "); + } + + // protocol part + + abstract pointcut myClass(); + + pointcut myConstructor(): myClass() && execution(new(..)); + pointcut myMethod(): myClass() && execution(* *(..)); + + before(): myConstructor() { + traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myConstructor() { + traceExit("" + thisJoinPointStaticPart.getSignature()); + } + + before(): myMethod() { + traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myMethod() { + traceExit("" + thisJoinPointStaticPart.getSignature()); + } +} +]]> + + + This version differs from version 1 in several subtle ways. The first + thing to notice is that this Trace class merges + the functional part of tracing with the crosscutting of the tracing + calls. That is, in version 1, there was a sharp separation between the + tracing support (the class Trace) and the + crosscutting usage of it (by the class + TraceMyClasses). In this version those two + things are merged. That's why the description of this class explicitly + says that "Trace messages are printed before and after constructors and + methods are," which is what we wanted in the first place. That is, the + placement of the calls, in this version, is established by the aspect + class itself, leaving less opportunity for misplacing calls. + + + A consequence of this is that there is no need for providing traceEntry + and traceExit as public operations of this class. You can see that they + were classified as protected. They are supposed to be internal + implementation details of the advice. + + + + The key piece of this aspect is the abstract pointcut classes that + serves as the base for the definition of the pointcuts constructors and + methods. Even though classes is abstract, and + therefore no concrete classes are mentioned, we can put advice on it, + as well as on the pointcuts that are based on it. The idea is "we don't + know exactly what the pointcut will be, but when we do, here's what we + want to do with it." In some ways, abstract pointcuts are similar to + abstract methods. Abstract methods don't provide the implementation, + but you know that the concrete subclasses will, so you can invoke those + methods. + + + + + + + + + + Production Aspects + + + + + A Bean Aspect + + (The code for this example is in + InstallDir/examples/bean.) + + + + This example examines an aspect that makes Point objects into a Java beans + with bound properties. + + + Introduction + + Java beans are reusable software components that can be visually + manipulated in a builder tool. The requirements for an object to be a + bean are few. Beans must define a no-argument constructor and must be + either 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 + getproperty 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 setproperty methods. + + + Point is a simple class representing points with + rectangular coordinates. Point does not know + anything about being a bean: there are set methods for + x and y but they do not fire + events, and the class is not serializable. Bound is an aspect that + makes Point a serializable class and makes its + get and set methods support the + bound property protocol. + + + + + The Class <classname>Point</classname> + + + The class Point is a very simple class with + trivial getters and setters, and a simple vector offset method. + + + + + + + + The Aspect <classname>BoundPoint</classname> + + + The aspect BoundPoint adds "beanness" to + Point objects. The first thing it does is + privately introduce a reference to an instance of + PropertyChangeSupport into all + Point objects. The property change + support object must be constructed with a reference to the bean for + which it is providing support, so it is initialized by passing it this, + an instance of Point. The support field is + privately introduced, so only the code in the aspect can refer to it. + + + + Methods for registering and managing listeners for property change + events are introduced into Point by the + introductions. These methods delegate the work to the + property change support object. + + + + The introduction also makes Point implement the + Serializable interface. Implementing + Serializable does not require any methods to be + implemented. Serialization for Point objects is + provided by the default serialization method. + + + + The pointcut setters names the + set methods: reception by a + Point object of any method whose name begins + with 'set' and takes one parameter. The around + advice on setters() stores the values + of the X and Y properties, calls + the original set method and then fires the + appropriate property change event according to which set method was + called. Note that the call to the method proceed needs to pass along + the Point p. The rule of thumb is that context that + an around advice exposes must be passed forward to continue. + + + + + + + + The Test Program + + + The test program registers itself as a property change listener to a + Point object that it creates and then performs + simple manipulation of that point: calling its set methods and the + offset method. Then it serializes the point and writes it to a file and + then reads it back. The result of saving and restoring the point is that + a new point is created. + + + + + + + Compiling and Running the Example + To compile and run this example, go to the examples directory and type: + + + + + + + + + + + The Subject/Observer Protocol + + (The code for this example is in + InstallDir/examples/observer.) + + + + This demo illustrates how the Subject/Observer design pattern can be + coded with aspects. + + + Overview + + The demo consists of the following: A colored label is a renderable + object that has a color that cycles through a set of colors, and a + number that records the number of cycles it has been through. A button + is an action item that records when it is clicked. + + + + With these two kinds of objects, we can build up a Subject/Observer + relationship in which colored labels observe the clicks of buttons; + that is, where colored labels are the observers and buttons are the + subjects. + + + + The demo is designed and implemented using the Subject/Observer design + pattern. The remainder of this example explains the classes and aspects + of this demo, and tells you how to run it. + + + + + Generic Components + + + The generic parts of the protocol are the interfaces + Subject and Observer, and + the abstract aspect SubjectObserverProtocol. The + Subject interface is simple, containing methods + to add, remove, and view Observer objects, and a + method for getting data about state changes: + + + + + The Observer interface is just as simple, + with methods to set and get Subject objects, and + a method to call when the subject gets updated. + + + + + + The SubjectObserverProtocol aspect contains + within it all of the generic parts of the protocol, namely, how to fire + the Observer objects' update methods when some + state changes in a subject. + + + + + + Note that this aspect does three things. It define an abstract pointcut + that extending aspects can override. It defines advice that should run + after the join points of the pointcut. And it introduces state and + behavior onto the Subject and + Observer interfaces. + + + + + Application Classes + + Button objects extend + java.awt.Button, and all they do is make sure + the void click() method is called whenever a button + is clicked. + + + + + + Note that this class knows nothing about being a Subject. + + + ColorLabel objects are labels that support the void colorCycle() + method. Again, they know nothing about being an observer. + + + + + + Finally, the SubjectObserverProtocolImpl + implements the subject/observer protocol, with + Button objects as subjects and + ColorLabel objects as observers: + + + + + + It does this by introducing the appropriate interfaces onto the + Button and ColorLabel + classes, making sure the methods required by the interfaces are + implemented, and providing a definition for the + stateChanges pointcut. Now, every time a + Button is clicked, all + ColorLabel objects observing that button will + colorCycle. + + + + + Compiling and Running + + Demo is the top class that starts this + demo. It instantiates a two buttons and three observers and links them + together as subjects and observers. So to run the demo, go to the + examples directory and type: + + + + + + + + + + + A Simple Telecom Simulation + + (The code for this example is in + InstallDir/examples/telecom.) + + + + This example illustrates some ways that dependent concerns can be encoded + with aspects. It uses an example system comprising a simple model of + telephone connections to which timing and billing features are added + using aspects, where the billing feature depends upon the timing feature. + + + + The Application + + + The example application is a simple simulation of a telephony system in + which customers make, accept, merge and hang-up both local and long + distance calls. The application architecture is in three layers. + + + + + The basic objects provide basic functionality to simulate + customers, 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. + + + + + + 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. + + + + + The simulation of system has three configurations: basic, timing and + billing. Programs for the three configurations are in classes + BasicSimulation, + TimingSimulation and + BillingSimulation. These share a common + superclass AbstractSimulation, which defines the + method run with the simulation itself and the method wait used to + simulate elapsed time. + + + + + The Basic Objects + + + The telecom simulation comprises the classes + Customer, Call and the + abstract class Connection with its two concrete + subclasses Local and + LongDistance. Customers have a name and a + numeric area code. They also have methods for managing calls. Simple + calls are made between one customer (the caller) and another (the + receiver), a 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. + + + + + + + + + + The Class <classname>Customer</classname> + + + Customer has methods call, + pickup, hangup and + merge for managing calls. + + + + + + + + The Class <classname>Call</classname> + + + Calls are created with a caller and receiver who are customers. If the + caller and receiver have the same area code then the call can be + established with a Local connection (see below), + otherwise a LongDistance connection is required. + A call comprises a number of connections between customers. Initially + there is only the connection between the caller and receiver but + additional connections can be added if calls are merged to form + conference calls. + + + + + The Class <classname>Connection</classname> + + The class Connection models the physical + details of establishing a connection between customers. It does this + with a simple state machine (connections are initially + PENDING, then COMPLETED and + finally DROPPED). Messages are printed to the + console so that the state of connections can be observed. Connection is + an abstract class with two concrete subclasses: + Local and LongDistance. + + + + + + + + The Class Local + + + + + + + The Class LongDistance + + + + + + + Compiling and Running the Basic Simulation + + + The source files for the basic system are listed in the file + basic.lst. To build and run the basic system, in a + shell window, type these commands: + + + + + + + + Timing + + The Timing aspect keeps track of total + connection time for each Customer by starting + and stopping a timer associated with each connection. It uses some + helper classes: + + + + The Class <classname>Timer</classname> + + + A Timer object simply records the current time + when it is started and stopped, and returns their difference when + asked for the elapsed time. The aspect + TimerLog (below) can be used to cause the + start and stop times to be printed to standard output. + + + + + + + + + The Aspect <classname>TimerLog</classname> + + + The aspect TimerLog can be included in a + build to get the timer to announce when it is started and stopped. + + + + + + + + The Aspect <classname>Timing</classname> + + + The aspect Timing introduces attribute + totalConnectTime into the class + Customer to store the accumulated connection + time per Customer. It introduces attribute + timer into Connection to associate a timer + with each Connection. Two pieces of after + advice ensure that the timer is started when a connection is + completed and and stopped when it is dropped. The pointcut + endTiming is defined so that it can be used by the + Billing aspect. + + + + + + + + Billing + + + The Billing system adds billing functionality to the telecom + application on top of timing. + + + + The Aspect <classname>Billing</classname> + + + The aspect Billing introduces attribute + payer into Connection + to indicate who initiated the call and therefore who is + responsible to pay for it. It also introduces method + callRate into Connection + so that local and long distance calls can be charged + differently. The call charge must be calculated after the timer is + stopped; the after advice on pointcut + Timing.endTiming does this and + Billing dominates Timing to make + sure that this advice runs after Timing's + advice on the same join point. It introduces attribute + totalCharge and its associated methods into + Customer (to manage the + customer's bill information. + + + + + + + + + Accessing the Introduced State + + + Both the aspects Timing and + Billing contain the definition of operations + that the rest of the system may want to access. For example, when + running the simulation with one or both aspects, we want to find out + how much time each customer spent on the telephone and how big their + bill is. That information is also stored in the classes, but they are + accessed through static methods of the aspects, since the state they + refer to is private to the aspect. + + + + Take a look at the file TimingSimulation.java. The + most important method of this class is the method + report(Customer c), which is used in the method + run of the superclass AbstractSimulation. This + method is intended to print out the status of the customer, with + respect to the Timing feature. + + + + + + + + Compiling and Running + + + The files timing.lst and billing.lst contain file lists for the timing + and billing configurations. To build and run the application with only + the timing feature, go to the directory examples and type: + + + + + + To build and run the application with the timing and billing features, + go to the directory examples and type: + + + + + + + + Discussion + + + There are some explicit dependencies between the aspects Billing and + Timing: + + + + Billing is declared to dominate Timing so that Billing's after + advice runs after that of Timing when they are on the same join + point. + + + + + + Billing uses the pointcut Timing.endTiming. + + + + + + Billing needs access to the timer associated with a connection. + + + + + + + + + + + + + Reusable Aspects + + + Tracing Aspects Revisited + + (The code for this example is in + InstallDir/examples/tracing.) + + + + Tracing—Version 3 + + + 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. + + + + Consider, again, the program without AspectJ. Suppose, for example, + that at some point later the requirements for tracing change, stating + that the trace messages should always include the string representation + of the object whose methods are being traced. This can be achieved in + at least two ways. One way is keep the interface of the methods + traceEntry and traceExit as it + was before, + + + + + + In this case, the caller is responsible for ensuring that the string + representation of the object is part of the string given as argument. + So, calls must look like: + + + + + + Another way is to enforce the requirement with a second argument in the + trace operations, e.g. + + + + + + In this case, the caller is still responsible for sending the right + object, but at least there is some guarantees that some object will be + passed. The calls will look like: + + + + + + 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! + + + + Here's another advantage of doing tracing with an aspect. We've already + seen that in version 2 traceEntry and + traceExit are not publicly exposed. So changing + their interfaces, or the way they are used, has only a small effect + inside the Trace class. Here's a partial view at + the implementation of Trace, version 3. The + differences with respect to version 2 are stressed in the + comments: + + + + + + As you can see, we decided to apply the first design by preserving the + interface of the methods traceEntry and + traceExit. But it doesn't matter—we could as + easily have applied the second design (the code in the directory + examples/tracing/version3 has the second design). + The point is that the effects of this change in the tracing + requirements are limited to the Trace aspect + class. + + + + One implementation change worth noticing is the specification of the + pointcuts. They now expose the object. To maintain full consistency + with the behavior of version 2, we should have included tracing for + static methods, by defining another pointcut for static methods and + advising it. We leave that as an exercise. + + + + Moreover, we had to exclude the execution join point of the method + toString from the methods + pointcut. The problem here is that toString is being + called from inside the advice. Therefore if we trace it, we will end + up in an infinite recursion of calls. This is a subtle point, and one + that you must be aware when writing advice. If the advice calls back to + the objects, there is always the possibility of recursion. Keep that in + mind! + + + + In fact, esimply excluding the execution join point may not be enough, + if there are calls to other traced methods within it -- in which case, + the restriction should be + + + + + + 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 + to make a couple of changes in the implementation of the + Trace aspect class, including changing the + specification of the pointcuts. That's only natural. But the + implementation changes were limited to this aspect. Without aspects, we + would have to change the implementation of every application class. + + + + Finally, to run this version of tracing, go to the directory + examples and type: + + + + + + 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 + + + + + The output should be: + + tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Circle(double, double, double) + <-- tracing.Circle(double, double, double) + --> tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Circle(double, double, double) + <-- tracing.Circle(double, double, double) + --> tracing.Circle(double) + <-- tracing.Circle(double) + --> tracing.TwoDShape(double, double) + <-- tracing.TwoDShape(double, double) + --> tracing.Square(double, double, double) + <-- tracing.Square(double, double, double) + --> tracing.Square(double, double) + <-- tracing.Square(double, double) + --> double tracing.Circle.perimeter() + <-- double tracing.Circle.perimeter() +c1.perimeter() = 12.566370614359172 + --> double tracing.Circle.area() + <-- double tracing.Circle.area() +c1.area() = 12.566370614359172 + --> double tracing.Square.perimeter() + <-- double tracing.Square.perimeter() +s1.perimeter() = 4.0 + --> double tracing.Square.area() + <-- double tracing.Square.area() +s1.area() = 1.0 + --> double tracing.TwoDShape.distance(TwoDShape) + --> double tracing.TwoDShape.getX() + <-- double tracing.TwoDShape.getX() + --> double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.distance(TwoDShape) +c2.distance(c1) = 4.242640687119285 + --> double tracing.TwoDShape.distance(TwoDShape) + --> double tracing.TwoDShape.getX() + <-- double tracing.TwoDShape.getX() + --> double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.getY() + <-- double tracing.TwoDShape.distance(TwoDShape) +s1.distance(c1) = 2.23606797749979 + --> String tracing.Square.toString() + --> String tracing.TwoDShape.toString() + <-- String tracing.TwoDShape.toString() + <-- String tracing.Square.toString() +s1.toString(): Square side = 1.0 @ (1.0, 2.0) +]]> + + + + + + + diff --git a/docs/progGuideDB/figureUML.gif b/docs/progGuideDB/figureUML.gif new file mode 100644 index 000000000..c4bf8db9a Binary files /dev/null and b/docs/progGuideDB/figureUML.gif differ diff --git a/docs/progGuideDB/gettingstarted.xml b/docs/progGuideDB/gettingstarted.xml new file mode 100644 index 000000000..7cd6becbd --- /dev/null +++ b/docs/progGuideDB/gettingstarted.xml @@ -0,0 +1,1090 @@ + + + Getting Started with AspectJ + + + Introduction + + Many software developers are attracted to the idea of aspect-oriented + programming + + aspect-oriented programming + + (AOP) + + AOP + aspect-oriented programming + + but unsure about how to begin using the technology. They + recognize the concept of crosscutting concerns, and know that they have + had problems with the implementation of such concerns in the past. But + there are many questions about how to adopt AOP into the development + process. Common questions include: + + + Can I use aspects in my existing code? + + + What kinds of benefits can I expect to get from using aspects? + + + + How do I find aspects in my programs? + + + How steep is the learning curve for AOP? + + + What are the risks of using this new technology? + + + + This chapter addresses these questions in the context of AspectJ a + general-purpose aspect-oriented extension to Java. A series of abridged + examples illustrate the kinds of aspects programmers may want to + implement using AspectJ and the benefits associated with doing so. + Readers who would like to understand the examples in more detail, or who + want to learn how to program examples like these, can find the complete + examples and supporting material on the AspectJ web site(). + + A significant risk in adopting any new technology is going too + far too fast. Concern about this risk causes many organizations to + be conservative about adopting new technology. To address this + issue, the examples in this chapter are grouped into three broad + categories, with aspects that are easier to adopt into existing + development projects coming earlier in this chapter. The next + section, , we present the core + of AspectJ's semantics, and in , + we present aspects that facilitate tasks such as debugging, + testing and performance tuning of applications. And, in the section + following, , we present aspects + that implement crosscutting functionality common in Java + applications. We will defer discussing a third category of aspects, + reusable aspects until . + + These categories are informal, and this ordering is not the only way + to adopt AspectJ. Some developers may want to use a production aspect + right away. But our experience with current AspectJ users suggests that + this is one ordering that allows developers to get experience with (and + benefit from) AOP technology quickly, while also minimizing risk. + + + + + AspectJ Semantics + + + AspectJ + semantics + overview + + + This section presents a brief introduction to the features of AspectJ + used later in this chapter. These features are at the core of the + language, but this is by no means a complete overview of AspectJ. + + The semantics are presented using a simple figure editor system. A + Figure consists of a number of + FigureElements, which can be either + Points or Lines. The + Figure class provides factory services. There is + also a Display. Most example programs later in + this chapter are based on this system as well. + + + + + + + UML for the FigureEditor + example + + + + The motivation for AspectJ (and likewise for aspect-oriented + programming) is the realization that there are issues or concerns + that are not well captured by traditional programming + methodologies. Consider the problem of enforcing a security policy + in some application. By its nature, security cuts across many of + the natural units of modularity of the application. Moreover, the + security policy must be uniformly applied to any additions as the + application evolves. And the security policy that is being applied + might itself evolve. Capturing concerns like a security policy in + a disciplined way is difficult and error-prone in a traditional + programming language. + + Concerns like security cut across the natural units of + modularity. For object-oriented programming languages, the natural + unit of modularity is the class. But in object-oriented + programming languages, crosscutting concerns are not easily turned + into classes precisely because they cut across classes, and so + these aren't reusable, they can't be refined or inherited, + they are spread through out the program in an undisciplined way, + in short, they are difficult to work with. + + Aspect-oriented programming is a way of modularizing + crosscutting concerns much like object-oriented programming is a + way of modularizing common concerns. AspectJ is an implementation + of aspect-oriented programming for Java. + + AspectJ adds to Java just one new concept, a join point, and + a few new constructs: pointcuts, advice, introduction and aspects. + Pointcuts and advice dynamically affect program flow, and + introduction statically affects a program's class + heirarchy. + + A join point + join point + is a well-defined point in the program flow. + Pointcuts + pointcut + select certain join points and values at those points. + Advice + advice + defines code that is executed when a pointcut is reached. These + are, then, the dynamic parts of AspectJ. + + AspectJ also has a way of affecting a program statically. + Introduction + introduction + is how AspectJ modifies a program's static structure, namely, the + members of its classes and the relationship between + classes. + + The last new construct in AspectJ is the + aspect. + aspect + Aspects, are AspectJ's unit of modularity for crosscutting + concerns They are defined in terms of pointcuts, advice and + introduction. + + In the sections immediately following, we are first going to look at + join points and how they compose into pointcuts. Then we will look + at advice, the code which is run when a pointcut is reached. We + will see how to combine pointcuts and advice into aspects, AspectJ's + reusable, inheritable unit of modularity. Lastly, we will look at + how to modify a program's class structure with introduction. + + + The Dynamic Join Point Model + + join point + model + + + A critical element in the design of any aspect-oriented + language is the join point model. The join point model provides + the common frame of reference that makes it possible to define + the dynamic structure of crosscutting concerns. + + This chapter describes AspectJ's dynamic join points, in + which join points are certain well-defined points in the + execution of the program. Later we will discuss introduction, + AspectJ's form for modifying a program statically. + + AspectJ provides for many kinds of join points, but this + chapter discusses only one of them: method call join points. A + method call join point encompasses the actions of an object + receiving a method call. It includes all the actions that + comprise a method call, starting after all arguments are + evaluated up to and including normal or abrupt return. + + Each method call itself is one join point. The dynamic + context of a method call may include many other join points: all + the join points that occur when executing the called method and + any methods that it calls. + + + + + Pointcut Designators + + In AspectJ, pointcut designators (or + simply pointcuts) identify certain join points in the program + flow. For example, the pointcut + + +call(void Point.setX(int)) + + identifies any call to the method setX + defined on Point objects. Pointcuts can be + composed using a filter composition semantics, so for example: + + +call(void Point.setX(int)) || +call(void Point.setY(int)) + + identifies any call to either the setX or + setY methods defined by + Point. + + Programmers can define their own pointcuts, and pointcuts + can identify join points from many different classes — in + other words, they can crosscut classes. So, for example, the + following declares a new, named pointcut: + + +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)); + + The effect of this declaration is that move is + now a pointcut that identifies any call to methods that move figure + elements. + + + Property-Based Primitive Pointcuts + + pointcut + primitive + + + pointcut + name-based + + + pointcut + property-based + + + The previous pointcuts are all based on explicit enumeration + of a set of method signatures. We call this + name-based crosscutting. AspectJ also + provides mechanisms that enable specifying a pointcut in terms + of properties of methods other than their exact name. We call + this property-based crosscutting. The + simplest of these involve using wildcards in certain fields of + the method signature. For example: + + +call(void Figure.make*(..)) + + identifies calls to any method defined on + Figure, for which the name begins with + "make", specifically the factory methods + makePoint and makeLine; + and + + +call(public * Figure.* (..)) + + identifies calls to any public method defined on + Figure. + + One very powerful primitive pointcut, + cflow, identifies join points based on whether + they occur in the dynamic context of another pointcut. So + + +cflow(move()) + + identifies all join points that occur between receiving method + calls for the methods in move and returning from + those calls (either normally or by throwing an exception.) + + + + + + + Advice + + advice + + + Pointcuts are used in the definition of advice. AspectJ has + several different kinds of advice that define additional code that + should run at join points. Before advice + + advice + before + + runs when a join point is reached and + before the computation proceeds, i.e. it runs when computation + reaches the method call and before the actual method starts running. + After advice + + advice + after + + runs after the computation 'under the join point' finishes, i.e. after + the method body has run, and just before control is returned to the + caller. Around advice + + advice + around + + runs when the join point is reached, and has explicit control over + whether the computation under the join point is allowed to run at + all. (Around advice and some variants of after advice are not + discussed in this chapter.) + + + + + Exposing Context in Pointcuts + + Pointcuts can also expose part of the execution context at + their join points. Values exposed by a pointcut can be used in + the body of advice declarations. In the following code, the + pointcut exposes three values from calls to + setXY: the + FigureElement receiving the call, the + new value for x and the new value for + y. The advice then prints the figure + element that was moved and its new x and + y coordinates after each + setXY method call. + + + + + + + + + Introduction + aspect + + Introduction is AspectJ's form for modifying classes and their + hierarchy. Introduction adds new members to classes and alters the + inheritance relationship between classes. Unlike advice that operates + primarily dynamically, introduction operates statically, at compilation + time. Introduction changes the declaration of classes, and it is these + changed classes that are inherited, extended or instantiated by the + rest of the program. + + Consider the problem of adding a new capability to some existing + classes that are already part of a class heirarchy, i.e. they already + extend a class. In Java, one creates an interface that captures + this new capability, and then adds to each affected + class a method that implements this interface. + + AspectJ can do better. The new capability is a crosscutting concern + because it affects multiple classes. Using AspectJ's introduction form, + we can introduce into existing classes the methods or fields that are + necessary to implement the new capability. + + + Suppose we want to have Screen objects + observe changes to Point objects, where + Point is an existing class. We can implement + this by introducing into the class Point an + instance field, observers, that keeps track of the + Screen objects that are observing + Points. Observers are added or removed with the + static methods addObserver and + removeObserver. The pointcut + changes defines what we want to observe, and the + after advice defines what we want to do when we observe a change. Note + that neither Screen's nor + Point's code has to be modified, and that all + the changes needed to support this new capability are local to this + aspect. + + + + + + Aspect Declarations + + An aspect + aspect is a modular unit of + crosscutting implementation. It is defined very much like a class, + and can have methods, fields, and initializers. The crosscutting + implementation is provided in terms of pointcuts, advice and + introductions. Only aspects may include advice, so while AspectJ + may define crosscutting effects, the declaration of those effects is + localized. + + The next three sections present the use of aspects in + increasingly sophisticated ways. Development aspects are easily removed + from production builds. Production aspects are intended to be used in + both development and in production, but tend to affect only a few + classes. Finally, reusable aspects require the most experience to get + right. + + + + + + + Development Aspects + + aspect + development + + + This section presents examples of aspects that can be used during + development of Java applications. These aspects facilitate debugging, + testing and performance tuning work. The aspects define behavior that + ranges from simple tracing, to profiling, to testing of internal + consistency within the application. Using AspectJ makes it possible to + cleanly modularize this kind of functionality, thereby making it possible + to easily enable and disable the functionality when desired. + + + Tracing, Logging, and Profiling + + tracing + + + logging + + + profiling + + + This first example shows how to increase the visibility of the + internal workings of a program. It is a simple tracing aspect that + prints a message at specified method calls. In our figure editor + example, one such aspect might simply trace whenever points are + drawn. + + + + This code makes use of the thisJoinPoint special + variable. Within all advice bodies this variable is bound to an object + that describes the current join point. The effect of this code + is to print a line like the following every time a figure element + receives a draw method call: + + + + To understand the benefit of coding this with AspectJ consider + changing the set of method calls that are traced. With AspectJ, this + just requires editing the definition of the + tracedCalls pointcut and recompiling. The + individual methods that are traced do not need to be edited. + + When debugging, programmers often invest considerable effort in + figuring out a good set of trace points to use when looking for a + particular kind of problem. When debugging is complete or appears to + be complete it is frustrating to have to lose that investment by + deleting trace statements from the code. The alternative of just + commenting them out makes the code look bad, and can cause trace + statements for one kind of debugging to get confused with trace + statements for another kind of debugging. + + With AspectJ it is easy to both preserve the work of designing a + good set of trace points and disable the tracing when it isn t being + used. This is done by writing an aspect specifically for that tracing + mode, and removing that aspect from the compilation when it is not + needed. + + This ability to concisely implement and reuse debugging + configurations that have proven useful in the past is a direct result + of AspectJ modularizing a crosscutting design element the set of + methods that are appropriate to trace when looking for a given kind of + information. + + + Profiling and Logging + logging + profiling + + Our second example shows you how to do some very specific + profiling. Although many sophisticated profiling tools are available, + and these can gather a variety of information and display the results + in useful ways, you may sometimes want to profile or log some very + specific behavior. In these cases, it is often possible to write a + simple aspect similar to the ones above to do the job. + + For example, the following aspect + Since aspects are by default singleton aspects, i.e. there is + only one instance of the aspect, fields in a singleton aspect are + similar to static fields in class. will count + the number of calls to the rotate method on a + Line and the number of calls to the + set* methods of a Point + that happen within the control flow of those calls to + rotate: + + + + Aspects have an advantage over standard profiling or logging + tools because they can be programmed to ask very specific and complex + questions like, "How many times is the 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"? + + + + + + + Pre- and Post-Conditions + + pre-condition + post-condition + assertion + + Many programmers use the "Design by Contract" style popularized by + Bertand Meyer in Object-Oriented Software Construction, + 2/e. In this style of programming, explicit + pre-conditions test that callers of a method call it properly and + explicit post-conditions test that methods properly do the work they + are supposed to. + + + AspectJ makes it possible to implement pre- and post-condition testing + in modular form. For example, this code + + + 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."); + } +} +]]> + + implements the bounds checking aspect of pre-condition testing for + operations that move points. Notice that the setX + pointcut refers to all the operations that can set a point's + x coordinate; this includes the + setX method, as well as half of the + setXY method. In this sense the + setX pointcut can be seen as involving very + fine-grained crosscutting—it names the the + setX method and half of the + setXY method. + + Even though pre- and post-condition testing aspects can often be + used only during testing, in some cases developers may wish to include + them in the production build as well. Again, because AspectJ makes it + possible to modularize these crosscutting concerns cleanly, it gives + developers good control over this decision. + + + + + Contract Enforcement + contract enforcement + + + + + + + The property-based crosscutting mechanisms can be very useful in + defining more sophisticated contract enforcement. One very powerful + use of these mechanisms is to identify method calls that, in a correct + program, should not exist. For example, the following aspect enforces + the constraint that only the well-known factory methods can add an + element to the registry of figure elements. Enforcing this constraint + ensures that no figure element is added to the registry more than + once. + + + + This aspect uses the withincode primitive pointcut to denote all + join points that occur within the body of the factory methods on + FigureElement (the methods with names that begin + with "make"). This is a property-based pointcut + because it identifies join points based not on their signature, but + rather on the property that they occur specifically within the code of + another method. The before advice declaration effectively says signal + an error for any calls to register that are not within the factory + methods. + + + + + Configuration Management + + configuration management + + + Configuration management for aspects can be handled using a variety + of make-file like techniques. To work with optional aspects, the + programmer can simply define their make files to either include the + aspect in the call to the AspectJ compiler or not, as desired. + + Developers who want to be certain that no aspects are included in + the production build can do so by configuring their make files so that + they use a traditional Java compiler for production builds. To make it + easy to write such make files, the AspectJ compiler has a command-line + interface that is consistent with ordinary Java compilers. + + + + + + Production Aspects + + aspect + production + + + This section presents examples of aspects that are inherently + intended to be included in the production builds of an application. + Production aspects tend to add functionality to an application rather + than merely adding more visibility of the internals of a program. Again, + we begin with name-based aspects and follow with property-based aspects. + Name-based production aspects tend to affect only a small number of + methods. For this reason, they are a good next step for projects + adopting AspectJ. But even though they tend to be small and simple, they + can often have a significant effect in terms of making the program easier + to understand and maintain. + + + Change Monitoring + change monitoring + + The first example production aspect shows how one might implement + some simple functionality where it is problematic to try and do it + explicitly. It supports the code that refreshes the display. The role + of the aspect is to maintain a dirty bit indicating whether or not an + object has moved since the last time the display was refreshed. + + Implementing this functionality as an aspect is straightforward. + The testAndClear method is called by the display + code to find out whether a figure element has moved recently. This + method returns the current state of the dirty flag and resets it to + false. The pointcut move captures all the method + calls that can move a figure element. The after advice on + move sets the dirty flag whenever an object + moves. + + + + Even this simple example serves to illustrate some of the important + benefits of using AspectJ in production code. Consider implementing + this functionality with ordinary Java: there would likely be a helper + class that contained the dirty flag, the + testAndClear method, as well as a + setFlag method. Each of the methods that could + move a figure element would include a call to the + setFlag method. Those calls, or rather the concept + that those calls should happen at each move operation, are the + crosscutting concern in this case. + + The AspectJ implementation has several advantages over the standard + implementation: + + The structure of the crosscutting concern is captured + explicitly. The moves pointcut clearly states all the + methods involved, so the programmer reading the code sees not just + individual calls to setFlag, but instead sees the + real structure of the code. The IDE support included with AspectJ + automatically reminds the programmer that this aspect advises each of + the methods involved. The IDE support also provides commands to jump + to the advice from the method and vice-versa. + + Evolution is easier. If, for example, the + aspect needs to be revised to record not just that some figure element + moved, but rather to record exactly which figure elements moved, the + change would be entirely local to the aspect. The pointcut would be + updated to expose the object being moved, and the advice would be + updated to record that object. The paper An Overview of + AspectJ, presented at ECOOP 2001, presents a detailed + discussion of various ways this aspect could be expected to + evolve.) + + The functionality is easy to plug in and out. + Just as with development aspects, production aspects may need to be + removed from the system, either because the functionality is no longer + needed at all, or because it is not needed in certain configurations of + a system. Because the functionality is modularized in a single aspect + this is easy to do. + + The implementation is more stable. If, for + example, the programmer adds a subclass of Line + that overrides the existing methods, this advice in this aspect will + still apply. In the ordinary Java implementation the programmer would + have to remember to add the call to setFlag in the + new overriding method. This benefit is often even more compelling for + property-based aspects (see the section ). + + + + Context Passing + + The crosscutting structure of context passing can be a significant + source of complexity in Java programs. Consider implementing + functionality that would allow a client of the figure editor (a program + client rather than a human) to set the color of any figure elements + that are created. Typically this requires passing a color, or a color + factory, from the client, down through the calls that lead to the + figure element factory. All programmers are familiar with the + inconvenience of adding a first argument to a number of methods just to + pass this kind of context information. + + Using AspectJ, this kind of context passing can be implemented in a + modular way. The following code adds after advice that runs only when + the factory methods of Figure are called in the + control flow of a method on a + ColorControllingClient. + + + + This aspect affects only a small number of methods, but note that + the non-AOP implementation of this functionality might require editing + many more methods, specifically, all the methods in the control flow + from the client to the factory. This is a benefit common to many + property-based aspects while the aspect is short and affects only a + modest number of benefits, the complexity the aspect saves is + potentially much larger. + + + + + Providing Consistent Behavior + + This example shows how a property-based aspect can be used to + provide consistent handling of functionality across a large set of + operations. This aspect ensures that all public methods of the + com.xerox package log any errors (a kind of + throwable, different from Exception) they throw to their caller. The + publicMethodCall pointcut captures the public + method calls of the package, and the after advice runs whenever one of + those calls returns throwing an exception. The advice logs the + exception and then the throw resumes. + + + + In some cases this aspect can log an exception twice. This happens + if code inside the com.xerox package itself calls a + public method of the package. In that case this code will log the error + at both the outermost call into the com.xerox + package and the re-entrant call. The cflow + primitive pointcut can be used in a nice way to exclude these + re-entrant calls: + + + + + The following aspect is taken from work on the AspectJ compiler. + The aspect advises about 35 methods in the + JavaParser class. The individual methods handle + each of the different kinds of elements that must be parsed. They have + names like parseMethodDec, + parseThrows, and + parseExpr. + + + + 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 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 + crosscutting modularity. Namely that all parse* + methods that return ASTObjects, except for + parseVarDec share a common behavior for + establishing the parse context of their result. + + The process of writing an aspect with a large property-based + pointcut, and of developing the appropriate exceptions can clarify the + structure of the system. This is especially true, as in this case, when + refactoring existing code to use aspects. When we first looked at the + code for this aspect, we were able to use the IDE support provided in + AJDE for JBuilder to see what methods the aspect was advising compared + to our manual coding. We quickly discovered that there were a dozen + places where the aspect advice was in effect but we had not manually + inserted the required functionality. Two of these were bugs in our + prior non-AOP implementation of the parser. The other ten were needless + performance optimizations. So, here, refactoring the code to express + the crosscutting structure of the aspect explicitly made the code more + concise and eliminated latent bugs. + + + + + + + Static Crosscutting: Introduction + introduction + + Up until now we have only seen constructs that allow us to + implement dynamic crosscutting, crosscutting that changes the way a + program executes. AspectJ also allows us to implement static + crosscutting, crosscutting that affects the static structure of our + progams. This is done using forms called introduction. + + An introduction is a member of an aspect, but + it defines or modifies a member of another type (class). With + introduction we can + + + add methods to an existing class + + + add fields to an existing class + + + extend an existing class with another + + + implement an interface in an existing class + + + convert checked exceptions into unchecked exceptions + + + + Suppose we want to change the class + Point to support cloning. By using introduction, + we can add that capability. The class itself doesn't change, but its + users (here the method main) may. In the example + below, the aspect CloneablePoint does three + things: + + + declares that the class + Point implements the interface + Cloneable, + + + declares that the methods in Point whose + signature matches Object clone() should have + their checked exceptions converted into unchecked exceptions, + and + + + adds a method that overrides the method + clone in Point, which + was inherited from Object. + + + + +class Point { + private int x, y; + + Point(int x, int y) { this.x = x; this.y = y; } + + int getX() { return this.x; } + int getY() { return this.y; } + + void setX(int x) { this.x = x; } + void setY(int y) { this.y = y; } + + public static void main(String[] args) { + + Point p = new Point(3,4); + Point q = (Point) p.clone(); + } +} + +aspect CloneablePoint { + declare parents: Point implements Cloneable; + + declare soft: CloneNotSupportedException: execution(Object clone()); + + Object Point.clone() { return super.clone(); } +} + + Introduction is a powerful mechanism for capturing crosscutting + concerns because it not only changes the behavior of components in an + application, but also changes their relationship. + + + + + Conclusion + + AspectJ is a simple and practical aspect-oriented extension to + Java. With just a few new constructs, AspectJ provides support for modular + implementation of a range of crosscutting concerns. + + Adoption of AspectJ into an existing Java development project can be + a straightforward and incremental task. One path is to begin by + using only development aspects, going on to using production aspects and + then reusable aspects after building up experience with AspectJ. Adoption + can follow other paths as well. For example, some developers will + benefit from using production aspects right away. Others may be able to + write clean reusable aspects almost right away. + + AspectJ enables both name-based and property based crosscutting. + Aspects that use name-based crosscutting tend to affect a small number of + other classes. But despite their small scale, they can often eliminate + significant complexity compared to an ordinary Java implementation. + Aspects that use property-based crosscutting can have small or large + scale. + + Using AspectJ results in clean well-modularized implementations of + crosscutting concerns. When written as an AspectJ aspect the structure + of a crosscutting concern is explicit and easy to understand. Aspects + are also highly modular, making it possible to develop plug-and-play + implementations of crosscutting functionality. + + AspectJ provides more functionality than was covered by this short + introduction. The next chapter, , covers + in detail all the features of the AspectJ language. The following + chapter, , 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/glossary.xml b/docs/progGuideDB/glossary.xml new file mode 100644 index 000000000..4516ce2bd --- /dev/null +++ b/docs/progGuideDB/glossary.xml @@ -0,0 +1,192 @@ + + + Glossary + + + + + + +advice + + Code, similar to a method, that is executed when a join + point is reached. There are three kinds of + advice: before advice that runs when a join point is reached, but + before the method in question executes, after advice that executes + after the method body executes, but before control returns to the + caller, and around advice that runs before and after the method in + question runs, and also has explicit control over whether the method + is run at all. + + + + +AOP + + See aspect-oriented programming. + + + + +aspect + + A modular unit of crosscutting implementation in + aspect-oriented programming, just as classes are + the modular unit of implementation in object-oriented + programming. + + + + +aspect-oriented programming + + A type or style of programming that explicitly takes into + account crosscutting concerns, just as + object-oriented programming explicitly takes into account classes and + objects. + + + + +crosscutting concerns + + Issues or programmer concerns that are not local to the natural + unit of modularity. + + + + +dynamic context + + The state of a program while it is executing. Contrast with + lexical context. + + + + +join point + + A well-defined instant in the execution of a program. In + AspectJ, join points are also principled, i.e. not every possible + instance in the execution of a program is a potential join point. + + + + + +lexical context + + The state of a program as it is written. Contrast with + dynamic context. + + + + +name-based pointcut designator + + A type of pointcut designator that enumerates and composes + explicitly named join points. For example, + +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)); + is a pointcut designator that explicitly names five join + points. See also property-based pointcut + designator. + + + + + +pointcut + + A collection of join points. + + + + +pointcut designator + + The name of a pointcut, or an expression which identifies a + pointcut. Pointcut designators can be primitive or composite. + Composite pointcut designators are primitive pointcut designators + composed using the operators ||, + &&, and !. See also + name-based pointcut designator and + property-based pointcut sesignator. + + + + +post-condition + + A test or assertion that must be true after a method has + executed. + + + + +pre-condition + + A test or assertion that must be true when a method is + called. + + + + +property-based pointcut designator + + A type of pointcut designator that specifies pointcuts in terms + of the properties of methods rather than just their names. For + example, + +call(public * Figure.*(..)) + specifies all the public methods in the class + Figure regardless of the type and number of + their arguments or return type. See also name-based + pointcut designator. + + + + +reusable aspect + + An aspect that can be extended or inherited from. + + + + +signature + + The number, order and type of the arguments to a method. + + + + +thisJoinPoint + + The special variable that identifies the current join point + when a non-static join point is reached. + + + + + + + + + + + + diff --git a/docs/progGuideDB/idioms.xml b/docs/progGuideDB/idioms.xml new file mode 100644 index 000000000..5898dbd9e --- /dev/null +++ b/docs/progGuideDB/idioms.xml @@ -0,0 +1,104 @@ + + Idioms + + + About this Chapter + + 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 + 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. + + + + + Any call to an instance of a subtype of AbstractFacade whose class is + not exactly equal to AbstractFacade: + + + + If AbstractFacade is an abstract class or an interface, then every + instance must be of a subtype and you can replace this with: + + + + Any call to a method which is defined by a subtype of + AbstractFacade, but which isn't defined by the type AbstractFacade itself: + + + + + 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: + + + + + To use a per-class variable declared on many classes, + you can defer initialization until you are in a non-static instance context + so you can refer to the particular class member. If you want to use + it from advice (without knowing the particular class at compile-time), + you can declare a method on the type. + + + + + + diff --git a/docs/progGuideDB/language.xml b/docs/progGuideDB/language.xml new file mode 100644 index 000000000..0f5e23561 --- /dev/null +++ b/docs/progGuideDB/language.xml @@ -0,0 +1,1226 @@ + + + The AspectJ Language + + + Introduction + + The previous chapter, , 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. + + + We will start out by looking at an example aspect that we'll build + out of a pointcut, an introduction, and two pieces of advice. This + example aspect will gives us something concrete to talk about. + + + + + The Anatomy of an Aspect + + + This lesson explains the parts of AspectJ's aspects. By reading this + lesson you will have an overview of what's in an aspect and you will be + exposed to the new terminology introduced by AspectJ. + + + + An Example Aspect + + + Here's an example of an aspect definition in AspectJ: + + + + + + The FaultHandler consists of one variable introduced + onto Server (line 03), two methods (lines 05-07 + and 09-11), one pointcut (line 13), and two pieces of advice (lines + 15-17 and 19-22). + + + + This covers the basics of what aspects can contain. In general, aspects + consist of an association with other program entities, ordinary + variables and methods, pointcuts, introductions, and advice, where + advice may be before, after or around advice. The remainder of this + lesson focuses on those crosscut-related constructs. + + + + + Pointcuts + + + AspectJ's pointcuts define collections of events, i.e. interesting + points in the execution of a program. These events, or points in the + execution, can be method or constructor invocations and executions, + handling of exceptions, field assignments and accesses, etc. Take, for + example, the pointcut declaration in line 13: + + + + + + This pointcut, named services, picks out those points + in the execution of the program when instances of the + Server class have their public methods called. + + + + The idea behind this pointcut in the FaultHandler + aspect is that fault-handling-related behavior must be triggered on the + calls to public methods. For example, the server may be unable to + proceed with the request because of some fault. The calls of those + methods are, therefore, interesting events for this aspect, in the + sense that certain fault-related things will happen when these events + occur. + + + + Part of the context in which the events occur is exposed by the formal + parameters of the pointcut. In this case, that consists of objects of + type server. That formal parameter is then being used on the right + hand side of the declaration in order to identify which events the + pointcut refers to. In this case, a pointcut picking out join points + where a Server is the target of some operation (target(s)) is being + composed (, meaning and) with a + pointcut picking out call join points (call(...)). The calls are + identified by signatures that can include wild cards. In this case, + there are wild cards in the return type position (first *), in the name + position (second *) and in the argument list position (..); the only + concrete information is given by the qualifier public. + + + + What else? + + + Pointcuts define arbitrarily large sets of points in the execution + of a program. But they use only a finite number of + kinds of points. Those kinds of points + correspond to some of the most important concepts in Java. Here is + an incomplete list: method invocation, method execution, exception + handling, instantiation, constructor execution. Each of these has a + specific syntax that you will learn about in other parts of this + guide. + + + + + + Advice + + + Advice defines pieces of aspect implementation that execute at join + points picked out by a pointcut. For example, the advice in lines 15-17 + specifies that the following piece of code + + + + + + is executed when instances of the Server class have their public + methods called, as specified by the pointcut services. More + specifically, it runs when those calls are made, just before the + corresponding methods are executed. + + + + The advice in lines 19-22 defines another piece of implementation + that is executed on the same pointcut: + + + + + + But this second method executes whenever those operations throw + exception of type FaultException. + + + + What else? + + There are two other variations of after advice: upon successful + return and upon return, either successful or with an exception. + There is also a third kind of advice called around. You will see + those in other parts of this guide. + + + + + + + + Join Points and Pointcuts + + + Consider the following Java class: + + + + + + In order to get an intuitive understanding of AspectJ's pointcuts, let's + go back to some of the basic principles of Java. Consider the following a + method declaration in class Point: + + + + + + What this piece of program states is that when an object of type Point + has a method called setX with an integer as the argument called on it, + then the method body { this.x = x; } is executed. Similarly, the + constructor given in that class states that when an object of type Point + is instantiated through a constructor with two integers as arguments, + then the constructor body { this.x = x; this.y = y; } is executed. + + + + One pattern that emerges from these descriptions is when something + happens, then something gets executed. In object-oriented programs, there + are several kinds of "things that happen" that are determined by the + language. We call these the join points of Java. Join points comprised + method calls, method executions, instantiations, constructor executions, + field references and handler executions. (See the quick reference for + complete listing.) + + + + Pointcuts pick out these join points. For example, the pointcut + + + + + + describes the calls to setX(int) or + setY(int) methods of any instance of Point. Here's + another example: + + + + + + This pointcut picks out the join points at which exceptions of type + IOException are handled inside the code defined by class MyClass. + + + + Pointcuts consist of a left-hand side and a right-hand side, separated by + a colon. The left-hand side defines the pointcut name and the pointcut + parameters (i.e. the data available when the events happen). The + right-hand side defines the events in the pointcut. + + + + Pointcuts can then be used to define aspect code in advice, as we will + see later. But first let's see what types of events can be captured and + how they are described in AspectJ. + + + + Designators + + + Here are examples of designators of + + + + + when a particular method body executes + + + execution(void Point.setX(int)) + + + + + + when a method is called + + + call(void Point.setX(int)) + + + + + + when an exception handler executes + + + handler(ArrayOutOfBoundsException) + + + + + + when the object currently executing + (i.e. this) is of type SomeType + + + this(SomeType) + + + + + + when the target object is of type + SomeType + + + target(SomeType) + + + + + + when the executing code belongs to + class MyClass + + + within(MyClass) + + + + + + when the join point is in the control flow of a call to a + Test's no-argument main method + + + + cflow(void Test.main()) + + + + + + + + + Designators compose through the operations or + ("||"), and + ("") and not + ("!"). + + + + + + It is possible to use wildcards. So + + + + execution(* *(..)) + + + + + + call(* set(..)) + + + + means (1) all the executions of methods with any return and + parameter types and (2) method calls of set methods with any + return and parameter types -- in case of overloading there may be + more than one; this designator picks out all of them. + + + + + + You can select elements based on types. For example, + + + + execution(int *()) + + + + + + call(* setY(long)) + + + + + + call(* Point.setY(int)) + + + + + + call(*.new(int, int)) + + + + + means (1) all executions of methods with no parameters, returning + an int (2) the calls of + setY methods that take a + long as an argument, regardless of their return + type or defining type, (3) the calls of class + Point's setY methods that + take an int as an argument, regardless of the + return type, and (4) the calls of all classes' constructors that + take two ints as arguments. + + + + + + You can compose designators. For example, + + + + target(Point) call(int *()) + + + + + + call(* *(..)) (within(Line) || within(Point)) + + + + + + within(*) execution(*.new(int)) + + + + + + this(*) !this(Point) + call(int *(..)) + + + + + means (1) all calls to methods received by instances of class + Point, with no parameters, returning an + int, (2) calls to any method where the call is + made from the code in Point's or + Line's type declaration, (3) executions of + constructors of all classes, that take an int as + an argument, and + (4) all method calls of any method returning an + int, from all objects except + Point objects to any other objects. + + + + + + + You can select methods and constructors based on their modifiers + and on negations of modifiers. For example, you can say: + + + + call(public * *(..)) + + + + + + execution(!static * *(..)) + + + + + + execution(public !static * *(..)) + + + + + which means (1) all invocation of public methods, (2) all + executions of non-static methods, and (3) all signatures of + the public, non-static methods. + + + + + + Designators can also deal with interfaces. For example, given the + interface + + + + the designator call(* MyInterface.*(..)) + picks out the call join points for methods defined by the interface + MyInterface (or its superinterfaces). + + + + + + + + call vs. execution + + + When methods and constructors run, there are two interesting times + associated with them. That is when they are called, and when they + actually execute. + + + + AspectJ exposes these times as call and execution join points, + respectively, and allows them to be picked out specifically by call and + execution pointcuts. + + + + So what's the difference between these times? Well, there are a number + of differences: + + + + Firstly, the lexical pointcut declarations within + and withincode match differently. At a call join + point, the enclosing text is that of the call site. This means that + This means that call(void m()) within(void m()) + will only capture recursive calls, for example. At an execution join + point, however, the control is already executing the method. + + + + Secondly, the call join point does not capture super calls to + non-static methods. This is because such super calls are different in + Java, since they don't behave via dynamic dispatch like other calls to + non-static methods. + + + + The rule of thumb is that if you want to pick a join point that runs + when an actual piece of code runs, pick an execution, but if you want + to pick one that runs when a particular signature is called, pick a + call. + + + + + + + Pointcut composition + + Pointcuts are put together with the operators and (spelled + &&), or (spelled ||), and + not (spelled !). This allows the creation of very + powerful pointcuts from the simple building blocks of primitive + pointcuts. This composition can be somewhat confusing when used with + primitive pointcuts like cflow and cflowbelow. Here's an example: + + + cflow(P) picks out + the join points in the control flow of the join points picked out by + P. So, pictorially: + + + + P --------------------- + \ + \ cflow of P + \ + + + + What does cflow(P) && + cflow(Q) pick out? Well, it picks + out those join points that are in both the control flow of + P and in the control flow of + Q. So... + + + + P --------------------- + \ + \ cflow of P + \ + \ + \ + Q -------------\------- + \ \ + \ cflow of Q \ cflow(P) && cflow(Q) + \ \ + + + Note that P and Q might + not have any join points in common... but their control flows might have join + points in common. + + + But what does cflow(P + && Q) mean? Well, it means + the control flow of those join points that are both picked out by + P picked out by Q. + + + + P && Q ------------------- + \ + \ cflow of (P && Q) + \ + + + and if there are no join points that are both picked by + P and picked out by Q, + then there's no chance that there are any join points in the control flow of + (P && + Q). + + + Here's some code that expresses this. + + + + + + + + Pointcut Parameters + + + Consider, for example, the first pointcut you've seen here, + + + + + + As we've seen before, the right-hand side of the pointcut picks out the + calls to setX(int) or setY(int) + methods where the target is any object of type + Point. On the left-hand side, the pointcut is given + the name "setters" and no parameters. An empty parameter list means + that when those events happen no context is immediately available. But + consider this other version of the same pointcut: + + + + + + This version picks out exactly the same calls. But in this version, the + pointcut has one parameter of type Point. This means + that when the events described on the right-hand side happen, a + Point object, named by a parameter named "p", is + available. According to the right-hand side of the pointcut, that + Point object in the pointcut parameters is the + object that receives the calls. + + + + Here's another example that illustrates the flexible mechanism for + defining pointcut parameters: + + + + + + This pointcut also has a parameter of type Point. + Similarly to the "setters" pointcut, this means that when the events + described on the right-hand side happen, a Point + object, named by a parameter named "p", is available. But in this case, + looking at the right-hand side, we find that the object named in the + parameters is not the target Point object that receives the + call; it's the argument (of type Point) passed to the "equals" method on some other + target Point object. If we wanted access to both objects, then the pointcut + definition that would define target Point p1 + and argument Point p2 would be + + + + + + Let's look at another variation of the "setters" pointcut: + + + + + + In this case, a Point object and an integer value + are available when the calls happen. Looking at the events definition + on the right-hand side, we find that the Point + object is the object receiving the call, and the integer + value is the argument of the method . + + + + The definition of pointcut parameters is relatively flexible. The most + important rule is that when each of those events defined in the + right-hand side happen, all the pointcut parameters must be bound to + some value. So, for example, the following pointcut definition will + result in a compilation error: + + + + + + The right-hand side establishes that this pointcut picks out the call + join points consisting of the setX(int) method + called on a point object, or the setY(int) method + called on a point object. This is fine. The problem is that the + parameters definition tries to get access to two point objects. But + when setX(int) is called on a point object, there is + no other point object to grab! So in that case, the parameter + p2 is unbound, and hence, the compilation error. + + + + + + Example: <literal>HandleLiveness</literal> + + + The example below consists of two object classes (plus an exception + class) and one aspect. Handle objects delegate their public, non-static + operations to their Partner objects. The aspect + HandleLiveness ensures that, before the delegations, + the partner exists and is alive, or else it throws an exception. + + + + + + + + + Advice + + + Advice defines pieces of aspect implementation that execute at + well-defined points in the execution of the program. Those points can be + given either by named pointcuts (like the ones you've seen above) or by + anonymous pointcuts. Here is an example of an advice on a named pointcut: + + + + + + And here is exactly the same example, but using an anonymous + pointcut: + + + + + + Here are examples of the different advice: + + + + + + This before advice runs just before the execution of the actions + associated with the events in the (anonymous) pointcut. + + + + + + This after advice runs just after each join point picked out by the + (anonymous) pointcut, regardless of whether it returns normally or throws + an exception. + + + + + + This after returning advice runs just after each join point picked out by + the (anonymous) pointcut, but only if it returns normally. The return + value can be accessed, and is named x here. After the + advice runs, the return value is returned. + + + + + + This after throwing advice runs just after each join point picked out by + the (anonymous) pointcut, but only when it throws an exception of type + Exception. Here the exception value can be accessed + with the name e. The advice re-raises the exception + after it's done. + + + + + + This around advice traps the execution of the join point; it runs + instead of the join point. The original action + associated with the join point can be invoked through the special + proceed call. + + + + + + Introduction + + + Introduction declarations add whole new elements in the given types, and + so change the type hierarchy. Here are examples of introduction + declarations: + + + + + + This privately introduces a field named disabled in + Server and initializes it to + false. Because it is declared + private, only code defined in the aspect can access + the field. + + + + + + This publicly introduces a method named getX in + Point; the method returns an int, + it has no arguments, and its body is return x. + Because it is defined publically, any code can call it. + + + + + + This publicly introduces a constructor in Point; the constructor has + two arguments of type int, and its body is this.x = x; this.y = y; + + + + + + This publicly introduces a field named x of type int in Point; the + field is initialized to 0. + + + + + + This declares that the Point class now implements the + Comparable interface. Of course, this will be an error + unless Point defines the methods of + Comparable. + + + + + + This declares that the Point class now extends the + GeometricObject class. + + + + An aspect can introduce several elements in at the same time. For + example, the following declaration + + + + + + publicly introduces both a field and a method into class + Point. Note that the identifier "name" in the body of + the method is bound to the "name" field in Point, even + if the aspect defined another field called "name". + + + + One declaration can introduce several elements in several classes as + well. For example, + + + + + + publicly introduces three methods, one in Point, + another in Line and another in Square. The three + methods have the same name (getName), no parameters, return a String, and + have the same body (return name;). The purpose of introducing several + elements in one single declaration is that their bodies are the same. The + introduction is an error if any of Point, + Line, or Square do not have a + "name" field. + + + + An aspect can introduce fields and methods (even with bodies) onto + interfaces as well as classes. + + + + Introduction Scope + + + AspectJ allows private and package-protected (default) introduction in + addition to public introduction. Private introduction means private in + relation to the aspect, not necessarily the target type. So, if an + aspect makes a private introduction of a field on a type + + + + + + Then code in the aspect can refer to Foo's x field, but nobody else + can. Similarly, if an aspect makes a package-protected + introduction, + + + + + + then everything in the aspect's package (which may not be Foo's + package) can access x. + + + + + Example: <literal>PointAssertions</literal> + + The example below consists of one class and one aspect. The aspect + introduces all implementation that is related with assertions of the + class. It privately introduces two methods in the class Point, namely + assertX and assertY. It also advises the two set methods of Point with + before declarations that assert the validity of the given values. The + introductions are made privately because other parts of the program + have no business accessing the assert methods. Only the code inside of + the aspect can call those methods. + + += 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; + } + } + } +]]> + + + + + + + + Reflection + + + AspectJ provides a special reference variable, thisJoinPoint, that + contains reflective information about the current join point for the + advice to use. The thisJoinPoint variable can only be used in the context + of advice, just like this can only be used in the context of non-static + methods and variable initializers. In advice, thisJoinPoint is an object + of type JoinPoint. + + + + One way to use it is simply to print it out. Like all Java objects, + thisJoinPoint has a toString() method that makes quick-and-dirty tracing + easy. + + + + + + The type of thisJoinPoint includes a rich reflective class hierarchy of + signatures, and can be used to access both static and dynamic information + about join points. If, however, only the static information about the + join point (such as the Signature) is desired, a lightweight join-point + object is available from the thisJoinPointStaticPart special variable. + This object is the same object you would get from + + + + + + + The static part of a join point does not include dynamic information, + such as the arguments, which can be accessed with + + + + + + But it has the performance benefit that repeated execution of the code + containing thisJoinPointStaticPart (through, for + example, separate method calls) will not result in repeated construction + of the reflective object. + + + It is always the case that + + + + + + One more reflective variable is available: + thisEnclosingJoinPointStaticPart. This, like + thisJoinPointStaticPart, only holds the static part of + a join point, but it is not the current but the enclosing join point. + So, for example, it is possible to print out the calling source location + (if available) with + + + + + + + + + + + + + + + diff --git a/docs/progGuideDB/limitations.xml b/docs/progGuideDB/limitations.xml new file mode 100644 index 000000000..41e10db45 --- /dev/null +++ b/docs/progGuideDB/limitations.xml @@ -0,0 +1,123 @@ + + + Implementation Limitations + + + Certain elements of AspectJ's semantics are difficult to implement without + making modifications to the virtual machine. One way to deal with this + problem would be to specify only the behavior that is easiest to implement. + We have chosen a somewhat different approach, which is to specify an ideal + language semantics, as well as a clearly defined way in which + implementations are allowed to deviate from that semantics. This makes it + possible to develop conforming AspectJ implementations today, while still + making it clear what later, and presumably better, implementations should do + tomorrow. + + + + According to the AspectJ language semantics, the declaration + + + + + + 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. + + + + But AspectJ implementations are permitted to deviate from this in a + 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 + source code for any aspects and all the code they should affect available + during the compile. This means that if some class Client contains code with + the expression 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 is compiled at the same the aspect is + compiled. It also means that join points associated with code in precompiled + libraries (such as java.lang), and join points associated with code in + native methods (including their execution join points), can not be advised. + + + + Different join points have different requirements. Method call join points + can be advised only if ajc controls either the code for + the caller or the code for the receiver, and some call pointcut designators + may require caller context (what the static type of the receiver is, for + example) to pick out join points. Constructor call join points can be + advised only if ajc controls the code for the caller. Field reference or + assignment join points can be advised only if ajc controls the code for the + "caller", the code actually making the reference or assignment. + Initialization join points can be advised only if ajc controls the code of + the type being initialized, and execution join points can be advised only if + ajc controls the code for the method or constructor body in question. + + + + Aspects that are defined perthis or + pertarget also have restrictions based on control of the + code. In particular, at a join point where the source code for the + currently executing object is not available, an aspect defined + perthis of that join point will not be associated. So + aspects defined perthis(Object) will not create aspect + instances for every object, just those whose class the compiler controls. + Similar restrictions apply to pertarget aspects. + + + + Inter-type declarations such as declare parents also have + restrictions based on control of the code. If the code for the target of an + inter-type declaration is not available, then the inter-type declaration is + not made on that target. So, declare parents : String implements + MyInterface will not work for + java.lang.String. + + + + Other AspectJ implementations, indeed, future versions of ajc, may define + code the implementation controls more liberally. + + + + Control may mean that classes need only be available in classfile or jarfile + format. So, even if Client.java and Point.java were precompiled, their join + points could still be advised. In such a system, though, it might still be + the case that join points from code of system libraries such as java.lang + could not be advised. + + + + Or control could even include system libraries, thus allowing a call join + point from java.util.Hashmap to java.lang.Object to be advised. + + + + All AspectJ implementations are required to control the code of the + files that the compiler compiles itself. + + + + The important thing to remember is that core concepts of AspectJ, + such as the join point, are unchanged, regardless of which + implementation is used. During your development, you will have to + be aware of the limitations of the ajc compiler you're using, but + these limitations should not drive the design of your aspects. + + + + + + + + + diff --git a/docs/progGuideDB/overview.gif b/docs/progGuideDB/overview.gif new file mode 100644 index 000000000..7b1d6c8d6 Binary files /dev/null and b/docs/progGuideDB/overview.gif differ diff --git a/docs/progGuideDB/pitfalls.xml b/docs/progGuideDB/pitfalls.xml new file mode 100644 index 000000000..5379d5daa --- /dev/null +++ b/docs/progGuideDB/pitfalls.xml @@ -0,0 +1,103 @@ + + Pitfalls + + + About this Chapter + + This chapter consists of aspectj programs that may lead to surprising + behaviour and how to understand them. + + + + + + Infinite loops + + Here is a Java program with peculiar behavior + + + + This program will never reach the println call, but when it aborts + will have no stack trace. + + This silence is caused by multiple StackOverflowExceptions. First + the infinite loop in the body of the method generates one, which the + finally clause tries to handle. But this finally clause also generates an + infinite loop which the current JVMs can't handle gracefully leading to the + completely silent abort. + + The following short aspect will also generate this behavior: + + + + + Why? Because the call to println is also a call matched by the + pointcut call (* *(..)). We get no output because we + used simple after() advice. If the aspect were changed to + + + + 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. + + There's a simple idiom to use if you ever have a worry that your + advice might apply in this way. Just restrict the advice from occurring in + join points caused within the aspect. So: + + + + Other solutions might be to more closely restrict the pointcut in + other ways, for example: + + + + The moral of the story is that unrestricted generic pointcuts can + pick out more join points than intended. + + + + + diff --git a/docs/progGuideDB/preface.xml b/docs/progGuideDB/preface.xml new file mode 100644 index 000000000..4f5575fcf --- /dev/null +++ b/docs/progGuideDB/preface.xml @@ -0,0 +1,52 @@ + + Preface + + + This user's guide does three things. It + + + introduces the AspectJ language + + + + + defines each of AspectJ's constructs and their semantics, and + + + + + provides examples of their use. + + + Three appendices give a quick reference, a more formal definition of + AspectJ, and a glossary. + + + The first section, , provides a gentle + overview of writing AspectJ programs. It also shows how one can introduce + AspectJ into an existing development effort in stages, reducing the + associated risk. You should read this section if this is your first + exposure to AspectJ and you want to get a sense of what AspectJ is all + about. + + The second section, , covers the + features of the language in more detail, using code snippets as examples. + The entire language is covered, and after reading this section, you should + be able to use all the features of the language correctly. + + The next section, , comprises a set of + complete programs that not only show the features being used, but also try + to illustrate recommended practice. You should read this section after you + are familiar with the elements of AspectJ. + + The back matter contains several appendices that cover AspectJ's + semantics, a quick reference to the language, a glossary of terms and the + index. + + + + + + + + diff --git a/docs/progGuideDB/progguide.html.xsl b/docs/progGuideDB/progguide.html.xsl new file mode 100644 index 000000000..4683e404f --- /dev/null +++ b/docs/progGuideDB/progguide.html.xsl @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/docs/progGuideDB/progguide.xml b/docs/progGuideDB/progguide.xml new file mode 100644 index 000000000..0128b3490 --- /dev/null +++ b/docs/progGuideDB/progguide.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + +]> + + + + The AspectJ<superscript>TM</superscript> Programming Guide + + + + the AspectJ Team + + + + + Copyright (c) 1998-2001 Xerox Corporation, + 2002 Palo Alto Research Center, Incorporated. + 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, you should first read + for a broad overview of programming + in AspectJ. If you are already familiar with AspectJ, but want a deeper + understanding, you should read and + look at the examples in the chapter. If you want a more formal + definition of AspectJ, you should read . + + + + + &preface; + &gettingstarted; + &language; + &examples; + &idioms; + &pitfalls; + &quickreference; + &semantics; + &limitations; + &glossary; + &bibliography; + + + + + + + diff --git a/docs/progGuideDB/quickreference.xml b/docs/progGuideDB/quickreference.xml new file mode 100644 index 000000000..2b0c98f14 --- /dev/null +++ b/docs/progGuideDB/quickreference.xml @@ -0,0 +1,658 @@ + + + AspectJ Quick Reference + AspectJsemantics + quick reference + + + + Pointcut Designators + + + Pointcut Designators + + + + + + + + + + + Methods and Constructors + + + + + + call(Signature) + + + Method or constructor call join points when the signature + matches Signature + + + + + + execution(Signature) + + + Method or constructor execution join points when the + signature matches + Signature + + + + + + initialization(Signature) + + + Object initialization join point when the first + constructor called in the type matches + Signature + + + + + + Exception Handlers + + + + + + handler(TypePattern) + + + Exception handler execution join points when + try handlers for the throwable types in + TypePattern are executed. + The exception object can be accessed with an + args pointcut. + + + + + + Fields + + + + + + get(Signature) + + + Field reference join points when the field matches + Signature + + + + + + set(Signature) + + + Field assignment join points when the field matches + Signature. The new value + can be accessed with an args + pointcut. + + + + + + Static Initializers + + + + + + staticinitialization(TypePattern) + + + Static initializer execution join points for the types in + TypePattern. + + + + + + Objects + + + + + + this(TypePattern) + + + Join points when the currently executing object is an + instance of a type in TypePattern + + + + + + target(TypePattern) + + + Join points when the target object is an instance + of a type in TypePattern + + + + + + args(TypePattern, ...) + + + Join points when the argument objects are instances of + the TypePatterns + + + + + + + Lexical Extents + + + + + + within(TypePattern) + + + Join points when the code executing is defined in the + types in TypePattern + + + + + + withincode(Signature) + + + Join points when the code executing is defined in the + method or constructor with signature + Signature + + + + + + Control Flow + + + + + + cflow(Pointcut) + + + Join points in the control flow of the join points + specified by Pointcut + + + + + + cflowbelow(Pointcut) + + + Join points in the control flow below the join points + specified by Pointcut + + + + + + Conditional + + + + + + if(Expression) + + + Join points when the boolean + Expression evaluates + to true + + + + + + Combination + + + + + + ! Pointcut + + + Join points that are not picked out by + Pointcut + + + + + + Pointcut0 Pointcut1 + + + Join points that are picked out by both + Pointcut0 and + Pointcut1 + + + + + + Pointcut0 || Pointcut1 + + + Join points that are picked out by either + Pointcut0 or + Pointcut1 + + + + + + ( Pointcut ) + + + Join points that are picked out by the parenthesized + Pointcut + + + + + + +
    + +
    + + + Type Patterns + + + + + Type Name Patterns + + + + * alone + all types + + + * in an identifier + any sequence of characters, not including "." + + + .. in an identifier + any sequence of characters starting and ending + with "." + + + +
    + + + The + wildcard can be appended to a type name pattern to + indicate all subtypes. + + + + Any number of []s can be put on a type name or subtype pattern + to indicate array types. + + + + Type Patterns + + + + TypeNamePattern + all types in TypeNamePattern + + + SubtypePattern + all types in SubtypePattern, a + pattern with a +. + + + ArrayTypePattern + all types in ArrayTypePattern, + a pattern with one or more []s. + + + !TypePattern + all types not in TypePattern + + + TypePattern0 + TypePattern1 + all types in both + TypePattern0 and TypePattern1 + + + TypePattern0 || TypePattern1 + all types in either + TypePattern0 or TypePattern1 + + + ( TypePattern ) + all types in TypePattern + + + +
    + +
    + + + Advice + + + + Advice + + + + + + before(Formals) : + + + Run before the join point. + + + + + + + after(Formals) returning + [ (Formal) ] : + + + Run after the join point if it returns normally. The + optional formal gives access to the returned value. + + + + + + after(Formals) throwing [ + (Formal) ] : + + + Run after the join point if it throws an exception. The + optional formal gives access to the + Throwable exception value. + + + + + + after(Formals) : + + + Run after the join point both when it returns normally and + when it throws an exception. + + + + + + Type + around(Formals) [ throws + TypeList ] : + + + Run instead of the join point. The join point can be + executed by calling proceed. + + + + + +
    +
    + + + Static Crosscutting + + + + + Introduction + + + + + + + + Modifiers Type TypePattern.Id(Formals) { Body } + + + Defines a method on the types in TypePattern. + + + + + + abstract Modifiers Type TypePattern.Id(Formals); + + + Defines an abstract method on the types in TypePattern. + + + + + + Modifiers TypePattern.new(Formals) { Body } + + + Defines a a constructor on the types in TypePattern. + + + + + + Modifiers Type TypePattern.Id [ = Expression ]; + + + Defines a field on the types in TypePattern. + + + + +
    + + + Other declarations + + + + + + + + declare parents: TypePattern extends TypeList; + + + Declares that the types in TypePattern extend the types of TypeList. + + + + + + declare parents: TypePattern implements TypeList; + + + Declares that the types in TypePattern implement the types of TypeList. + + + + + + declare warning: Pointcut: String; + + + Declares that if any of the join points in + Pointcut possibly exist in + the program, the compiler should emit a warning of + String. + + + + + + declare error: Pointcut: String; + + + Declares that if any of the join points in + Pointcut possibly exist in + the program, the compiler should emit an error of + String. + + + + + + declare soft: + TypePattern: + Pointcut; + + + Declares that any exception of a type in + TypePattern that gets + thrown at any join point picked out by + Pointcut will be wrapped in + org.aspectj.lang.SoftException. + + + + + +
    + +
    + + + Aspect Associations + + + + + Associations + + + + modifier + Description + Accessor + + + + + + + + [ issingleton ] + + + One instance of the aspect is made. This is + the 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 + 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 + 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 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 Pointcut. + + + aspectOf() at join points in + cflowbelow(Pointcut) + + + + + +
    +
    +
    + + + + + + diff --git a/docs/progGuideDB/semantics.xml b/docs/progGuideDB/semantics.xml new file mode 100644 index 000000000..cf77a23ed --- /dev/null +++ b/docs/progGuideDB/semantics.xml @@ -0,0 +1,2361 @@ + + + Language Semantics + + + AspectJ extends Java by overlaying a concept of join points onto the + existing Java semantics and by adding adds four kinds of program elements + to Java: + + + + Join points are well-defined points in the execution of a program. These + include method and constructor calls, field accesses and others described + below. + + + + A pointcut picks out join points, and exposes some of the values in the + execution context of those join points. There are several primitive + pointcut designators, new named pointcuts can be defined by the + pointcut declaration. + + + + Advice is code that executes at each join point in a pointcut. Advice has + access to the values exposed by the pointcut. Advice is defined by + before, after, and + around declarations. + + + + Introduction and declaration form AspectJ's static crosscutting features, + that is, is code that may change the type structure of a program, by adding + to or extending interfaces and classes with new fields, constructors, or + methods. Introductions are defined through an extension of usual method, + field, and constructor declarations, and other declarations are made with a + new declare keyword. + + + + An aspect is a crosscutting type, that encapsulates pointcuts, advice, and + static crosscutting features. By type, we mean Java's notion: a modular + unit of code, with a well-defined interface, about which it is possible to + do reasoning at compile time. Aspects are defined by the + aspect declaration. + + + + Join Points + + + While aspects do define crosscutting types, the AspectJ system does not + allow completely arbitrary crosscutting. Rather, aspects define types that + cut across principled points in a program's execution. These principled + points are called join points. + + + + + A join point is a well-defined point in the execution of a program. The + join points defined by AspectJ are: + + + + + + Method call + + + When a method is called, not including super calls of non-static + methods. + + + + + + Method execution + + + When the body of code for an actual method executes. + + + + + + + Constructor call + + + When an object is built and a constructor is called, not including + this or super constructor calls. The object being constructed is + returned at a constructor call join point, so it may be accessed + with after returning advice. + + + + + + Initializer execution + + + When the non-static initializers of a class run. + + + + + + Constructor execution + + + When the body of code for an actual constructor executes, after its + this or super constructor call. The object being constructed is + the currently executing object, and so may be accessed with the + this pointcut. No value is returned from + constructor execution join points. + + + + + + Static initializer execution + + + When the static initializer for a class executes. + + + + + + Object pre-initialization + + + Before the object initialization code for a particular class runs. + This encompasses the time between the start of its first called + constructor and the start of its parent's constructor. Thus, the + execution of these join points encompass the join points from the + code found in this() and + super() constructor calls. + + + + + + Object initialization + + + When the object initialization code for a particular class runs. + This encompasses the time between the return of its parent's + constructor and the return of its first called constructor. It + includes all the dynamic initializers and constructors used to + create the object. The object being constructed is + the currently executing object, and so may be accessed with the + this pointcut. No value is returned from + constructor execution join points. + + + + + + Field reference + + + When a non-final field is referenced. + + + + + + Field assignment + + + When a field is assigned to. + + + + + + Handler execution + + + When an exception handler executes. + + + + + + + + + + + Pointcuts + + + A pointcut is a program element that picks out join points, as well as + data from the execution context of the join points. Pointcuts are used + primarily by advice. They can be composed with boolean operators to + build up other pointcuts. So a pointcut is defined by one of + + + + + call(Signature) + + Picks out a method or constructor call join point based on the + static signature at the caller side. + + + + execution(Signature) + + Picks out a method or constructor execution join point based on + the static signature at the callee side. + + + + + get(Signature) + + Picks out a field get join point based on the static + signature. Note that references to constant fields (static final + fields bound to a constant string object or primitive value) are not + get join points, since Java requires them to be inlined. + + + + set(Signature) + + Picks out a field set join point based on the static + signature. Note that the initializations of constant fields (static + final fields where the initializer is a constant string object or + primitive value) are not set join points, since Java requires their + references to be inlined. + + + + + handler(TypePattern) + + Picks out an exception handler of any of the Throwable types + of the type pattern. + + + + + initialization(Signature) + + Picks out an object initialization join point based on the + static signature of the starting constructor. + + + + + staticinitialization(TypePattern) + + Picks out a static initializer execution join point of any of the types + of the type pattern. + + + + + within(TypePattern) + + Picks out all join points where the executing code is defined + in any of the classes of the type pattern. + + + + + withincode(Signature) + + Picks out all join points where the executing code is defined + in the method or constructor of the appropriate signature. + + + + + cflow(Pointcut) + + Picks out all join points in the control flow of the join + points picked out by the pointcut, including pointcut's join points + themselves. + + + + cflowbelow(Pointcut) + + Picks out all join points in the control flow below the join + points picked out by the pointcut. + + + + + this(TypePattern or Id) + + Picks out all join points where the currently executing object + (the object bound to this) is an instance of a + type of the type pattern, or of the type of the identifier. + Will not match any join points from static methods. + + + + + + target(TypePattern or Id) + + Picks out all join points where the target object (the object + on which a call or field operation is applied to) is an instance of a + type of the type pattern, or of the type of the + identifier. Will not match any calls, gets, or sets to static + members. + + + + + args(TypePattern or Id, ...) + + Picks out all join points where the arguments are instances of + a type of the appropriate type pattern or identifier. + + + + + PointcutId(TypePattern or Id, ...) + + Picks out all join points that are picked out by the + user-defined pointcut designator named by + PointcutId. + + + + + if(BooleanExpression) + + Picks out all join points where the boolean expression + evaluates to true. The boolean expression used + can only access static members, variables exposed by teh enclosing + pointcut or advice, and thisJoinPoint forms. In + particular, it cannot call non-static methods on the aspect. + + + + + ! Pointcut + + Picks out all join points that are not picked out by the + pointcut. + + + + + Pointcut0 Pointcut1 + + Picks out all join points that are picked out by both of the + pointcuts. + + + + + Pointcut0 || Pointcut1 + + Picks out all join points that are picked out by either of the + pointcuts. + + + + + ( Pointcut ) + + Picks out all join points that are picked out by the + parenthesized pointcut. + + + + + + Pointcut naming + + + + A named pointcut is defined with the pointcut + declaration. + + + + +pointcut publicIntCall(int i): + call(public * *(int)) args(i); + + + + A named pointcut may be defined in either a class or aspect, and is + treated as a member of the class or aspect where it is found. As a + member, it may have an access modifier such as + public or private. + + + +class C { + pointcut publicCall(int i): + call(public * *(int)) args(i); +} + +class D { + pointcut myPublicCall(int i): + C.publicCall(i) within(SomeType); +} + + + + Pointcuts that are not final may be declared abstract, and defined + without a body. Abstract pointcuts may only be declared within + abstract aspects. + + + +abstract aspect A { + abstract pointcut publicCall(int i); +} + + + + In such a case, an extending aspect may override the abstract + pointcut. + + + +aspect B extends A { + pointcut publicCall(int i): call(public Foo.m(int)) args(i); +} + + + For completeness, a pointcut with a declaration may be declared + final. + + + Though named pointcut declarations appear somewhat like method + declarations, and can be overridden in subaspects, they cannot be + overloaded. It is an error for two pointcuts to be named with the same + name in the same class or aspect declaration. + + + + The scope of a named pointcut is the enclosing class declaration. This + is different than the scope of other members; the scope of other + members is the enclosing class body. This means + that the following code is legal: + + + +aspect B percflow(publicCall()) { + pointcut publicCall(): call(public Foo.m(int)); +} + + + + + + Context exposure + + + Pointcuts have an interface; they expose some parts of the execution + context of the join points they pick out. For example, the PublicIntCall + above exposes the first argument from the receptions of all public + unary integer methods. This context is exposed by providing typed + formal parameters to named pointcuts and advice, like the formal + parameters of a Java method. These formal parameters are bound by name + matching. + + + + On the right-hand side of advice or pointcut declarations, a regular + Java identifier is allowed in certain pointcut designators in place of + a type or collection of types. + There are four primitive pointcut designators where this is allowed: + this, target, and + args. In all such + cases, using an identifier rather than a type is as if the type + selected was the type of the formal parameter, so that the pointcut + + + +pointcut intArg(int i): args(i); + + + + picks out join points where an int is being passed + as an argument, but furthermore allows advice access to that argument. + + + + Values can be exposed from named pointcuts as well, so + + + +pointcut publicCall(int x): call(public *.*(int)) intArg(x); +pointcut intArg(int i): args(i); + + + + is a legal way to pick out all calls to public methods accepting an int + argument, and exposing that argument. + + + + There is one special case for this kind of exposure. Exposing an + argument of type Object will also match primitive typed arguments, and + expose a "boxed" version of the primitive. So, + + + +pointcut publicCall(): call(public *.*(..)) args(Object); + + + + will pick out all unary methods that take, as their only argument, + subtypes of Object (i.e., not primitive types like + int), but + + + +pointcut publicCall(Object o): call(public *.*(..)) args(o); + + + + will pick out all unary methods that take any argument: And if the + argument was an int, then the value passed to advice + will be of type java.lang.Integer. + + + + + Primitive pointcuts + + Method-related pointcuts + + AspectJ provides two primitive pointcut designators designed to + capture method call and execution join points. + + + call(Signature) + execution(Signature) + + + These two pointcuts also pick out constructor call end execution + join points. + + Field-related pointcuts + + + AspectJ provides two primitive pointcut designators designed to + capture field reference and assignment join points: + + + + get(Signature) + set(Signature) + + + + All set join points are treated as having one argument, the value the + field is being set to, so at a set join point, that value can be + accessed with an args pointcut. So an aspect + guarding an integer variable x declared in type T might be written as + + + MAX_CHANGE) + throw new RuntimeException(); + } +}]]> + + Object creation-related pointcuts + + + AspectJ provides three primitive pointcut designators designed to + capture the initializer execution join points of objects. + + + + call(Signature) + initialization(Signature) + execution(Signature) + + + Class initialization-related pointcuts + + + AspectJ provides one primitive pointcut designator to pick out + static initializer execution join points. + + + + staticinitialization(TypePattern) + + + Exception handler execution-related pointcuts + + + AspectJ provides one primitive pointcut designator to capture + execution of exception handlers: + + + + handler(TypePattern) + + + + All handler join points are treated as having one argument, the value + of the exception being handled, so at a handler join point, that + value can be accessed with an args pointcut. So + an aspect used to put FooException objects into some normal form + before they are handled could be written as + + + +aspect NormalizeFooException { + before(FooException e): handler(FooException) args(e) { + e.normalize(); + } +} + + + State-based pointcuts + + + Many concerns cut across the dynamic times when an object of a + particular type is executing, being operated on, or being passed + around. AspectJ provides primitive pointcuts that capture join + points at these times. These pointcuts use the dynamic types of + their objects to discriminate, or pick out, join points. They may + also be used to expose to advice the objects used for + discrimination. + + + + this(TypePattern or Id) + target(TypePattern or Id) + + + + + The this pointcut picks out all join points where the currently + executing object (the object bound to this) is an + instance of a particular type. The target pointcut picks out all + join points where the target object (the object on which a method is + called or a field is accessed) is an instance of a particular type. + + + + + args(TypePattern or Id or "..", ...) + + + + The args pointcut picks out all join points where the arguments are + instances of some types. Each element in the comma-separated list is + one of three things. If it is a type pattern, then the argument + in that position must be an instance of a type of the type name. If + it is an identifier, then the argument in that position must be an + instance of the type of the identifier (or of any type if the + identifier is typed to Object). If it is the special wildcard "..", + then any number of arguments will match, just like in signatures. So + the pointcut + + + +args(int, .., String) + + + + will pick out all join points where the first argument is an + int and the last is a String. + + + + Control flow-based pointcuts + + + 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) + + + + The cflow pointcut picks out all join points that occur between the start and the + end of each of the pointcut's join points. + + + + The cflowbelow pointcut picks out all join points that occur between + the start and the end of each of the pointcut's join points, but + not including the initial join point of the control flow itself. + + + Program text-based pointcuts + + + While many concerns cut across the runtime structure of the program, + some must deal with the actual lexical structure. AspectJ allows + aspects to pick out join points based on where their associated code + is defined. + + + + within(TypePattern) + withincode(Signature) + + + + The within pointcut picks out all join points where the code + executing 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 also + includes any join points that are associated with code within any of + the type's nested types. + + + + The withincode pointcut picks out all join points where the code + executing is defined in the declaration of a particular method or + constructor. This includes the method or constructor execution join + point as well as any join points associated with the statements and + expressions of the method or constructor. It also includes any join + points that are associated with code within any of the method or + constructor's local or anonymous types. + + + Dynamic property-based pointcuts + + + if(BooleanExpression) + + + + The if pointcut picks out join points based on a dynamic property. + It's syntax takes an expression, which must evaluate to a boolean + true or false. Within this expression, the + thisJoinPoint object is available. So one + (extremely inefficient) way of picking out all call join points would + be to use the pointcut + + + +if(thisJoinPoint.getKind().equals("call")) + + + + + + Signatures + + + One very important property of a join point is its signature, which is + used by many of AspectJ's pointcut designators to select particular + join points. + + + + At a method call join point, the signature is composed of the type used + to access the method, the name of the method, and the the types of the called + method's formal parameters and return value (if any). + + + + At a method execution join point, the signature is composed of the type + defining the method, the name of the method, and the the types of the executing + method's formal parameters and return value (if any). + + + + + At a constructor call join point, the signature is composed of the type + of the object to be constructed and the types of the + called constructor's formal parameters. + + + + At a constructor execution join point, the signature is composed of the + type defining the constructor and the types of the executing + constructor's formal parameters. + + + + At an object initialization join point, the signature is composed of + the type being initialized and the types of the formal parameters of + the first constructor entered during the initialization of this type. + + + + At an object pre-initialization join point, the signature is composed + of the type being initialized and the types of the formal parameters of + the first constructor entered during the initialization of this type. + + + + At a field reference or assignment join point, the signature is + composed of the type used to access or assign to the field, the name of + the field, and the type of the field. + + + + At a handler execution join point, the signature is composed of the + exception type that the handler handles. + + + + The withincode, call, + execution, get, and + set primitive pointcut designators all use signature + patterns to determine the join points they describe. A signature + pattern is an abstract description of one or more join-point + signatures. Signature patterns are intended to match very closely the + same kind of things one would write when defining individual methods + and constructors. + + + + Method definitions in Java include method names, method parameters, + return types, modifiers like static or private, and throws clauses, + while constructor definitions omit the return type and replace the + method name with the class name. The start of a particular method + definition, in class Test, for example, might be + + + + +class C { + public final void foo() throws ArrayOutOfBoundsException { ... } +} + + + + In AspectJ, method signature patterns have all these, but most elements + can be replaced by wildcards. So + + + + +call(public final void C.foo() throws ArrayOutOfBoundsException) + + + + picks out call join points to that method, and the pointcut + + + +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. + + + + The defining type name, if not present, defaults to *, so another way + of writing that pointcut would be + + + +call(public final void *() throws ArrayOutOfBoundsException) + + + + Formal parameter lists can use the wildcard .. to + indicate zero or more arguments, so + + + +execution(void m(..)) + + + + picks out execution join points for void methods named + m, of any number of arguments, while + + + +execution(void m(.., int)) + + + + + picks out execution join points for void methods named + m whose last parameter is of type + int. + + + + The modifiers also form part of the signature pattern. If an AspectJ + signature pattern should match methods without a particular modifier, + such as all non-public methods, the appropriate modifier should be + negated with the ! operator. So, + + + +withincode(!public void foo()) + + + + picks out all join points associated with code in null non-public + void methods named foo, while + + + +withincode(void foo()) + + + + picks out all join points associated with code in null void methods + named foo, regardless of access modifier. + + + + Method names may contain the * wildcard, indicating any number of + characters in the method name. So + + + +call(int *()) + + + + picks out all call join points to int methods + regardless of name, but + + + +call(int get*()) + + + + picks out all call join points to int methods + where the method name 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 + + + +execution(private C.new() throws ArithmeticException) + + + + + Type patterns + + + Type patterns are a way to pick out collections of types and use them + in places where you would otherwise use only one type. The rules for + using type patterns are simple. + + + Type name patterns + + + First, all type names are also type patterns. So + Object, java.util.HashMap, + Map.Entry, int are all type + patterns. + + + + There is a special type name, *, which is also a type pattern. * picks out all + types, including primitive types. So + + + +call(void foo(*)) + + + + picks out all call join points to void methods named foo, taking one + argument of any type. + + + + Type names that contain the two wildcards "*" and + ".." are also type patterns. The * wildcard matches + zero or more characters characters except for ".", so it can be used + when types have a certain naming convention. So + + + +handler(java.util.*Map) + + + + picks out the types java.util.Map and java.util.java.util.HashMap, + among others, and + + + +handler(java.util.*) + + + + picks out all types that start with "java.util." and + don't have any more "."s, that is, the types in the + java.util package, but not inner types + (such as java.util.Map.Entry). + + + + The ".." wildcard matches any sequence of + characters that start and end with a ".", so it can be used + to pick out all types in any subpackage, or all inner types. So + + + +target(com.xerox..*) + + + + picks out all join points where the target object is an instance of + defined in any type beginning with "com.xerox.". + + + Subtype patterns + + + It is possible to pick out all subtypes of a type (or a collection of + types) with the "+" wildcard. The "+" wildcard follows immediately a + type name pattern. So, while + + + +call(Foo.new()) + + + + picks out all constructor call join points where an instance of exactly + type Foo is constructed, + + + +call(Foo+.new()) + + + + picks out all constructor call join points where an instance of any + subtype of Foo (including Foo itself) is constructed, and the unlikely + + + +call(*Handler+.new()) + + + + picks out all constructor call join points where an instance of any + subtype of any type whose name ends in "Handler" is constructed. + + + Array type patterns + + + A type name pattern or subtype pattern can be followed by one or more + sets of square brackets to make array type patterns. So + Object[] is an array type pattern, and so is + com.xerox..*[][], and so is + Object+[]. + + + Type patterns + + + Type patterns are built up out of type name patterns, subtype patterns, + and array type patterns, and constructed with boolean operators + , ||, and + !. So + + + +staticinitialization(Foo || Bar) + + + + picks out the static initializer execution join points of either Foo or Bar, + and + + + +call((Foo+ ! Foo).new(..)) + + + + picks out the constructor call join points when a subtype of Foo, but + not Foo itself, is constructed. + + + + + + + Pointcuts and Join Points + + It is possible to pick out every different kind of join point with + pointcuts, but some of the less common ones require pointcut + combination. + + + Method call + + +aspect A { + after() returning: call(void foo()) { + System.err.println(thisJoinPoint.getKind()); // should be "method-call" + } +} + + + + + Method execution + + +aspect A { + after() returning: execution(void foo()) { + System.err.println(thisJoinPoint.getKind()); // should be "method-execution" + } +} + + + + + Constructor call + + +aspect A { + after() returning: call(Foo.new()) { + System.err.println(thisJoinPoint.getKind()); // should be "constructor-call" + } +} + + + + + Constructor execution<!-- [add chain up] --> + + +aspect A { + after() returning: execution(Foo.new()) { + System.err.println(thisJoinPoint.getKind()); // should be "constructor-execution" + } +} + + + + + Static initializer execution<!-- [add chain up] --> + + +aspect A { + after() returning: staticinitializer(Foo) { + System.err.println(thisJoinPoint.getKind()); // should be "static-initializar" + } +} + + + + + Object pre-initialization<!-- [add chain up] --> + + This join point will most commonly be seen as the enclosing + execution join point of a particular call, since it cannot be simply + picked out by AspectJ's primitive pointcuts. + + +aspect A { + after() returning: call(Foo) { + System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "pre-initialization" + } +} + + + + + Object initialization<!-- [add chain up] --> + + + +aspect A { + after() returning: initialization(Foo.new()) { + System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "initialization" + } +} + + + + + Field Reference <!-- [add chain up] --> + + + +aspect A { + after() returning: get(Foo.x) { + System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "field-get" + } +} + + + + + Field Assignment <!-- [add chain up] --> + + + +aspect A { + after() returning: set(Foo.x) { + System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "field-set" + } +} + + + + + + Handler Execution <!-- [add chain up] --> + + + +aspect A { + after() returning: handler(FooExn) { + System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "handler" + } +} + + + + + + + + Advice + + + before(Formals): Pointcut { Body } + after(Formals) returning [ (Formal) ]: Pointcut { Body } + after(Formals) throwing [ (Formal) ]: Pointcut { Body } + after(Formals) : Pointcut { Body } + Type around(Formals) [ throws TypeList ] : Pointcut { Body } + + + + Advice defines crosscutting behavior. It is defined in terms of + pointcuts. The code of a piece of advice runs at every join point picked + out by its pointcut. Exactly how the code runs depends on the kind of + advice. + + + + 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. + + + + 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. + + + +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"); + } +} + + + + After returning advice may not care about its returned object, in which + case it may be written + + + +after() returning: call(public Object *(..)) { + System.out.println("Returned normally"); +} + + + + It is an error to try to put after returning advice on a join point that + does not return the correct type. For example, + + + +after() returning (byte b): call(int String.length()) { + // this is an error +} + + + + is not allowed. But if no return value is exposed, or the exposed return + value is typed to Object, then it may be applied to + any join point. If the exposed value is typed to + Object, then 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. + + + + Around advice runs in place of the join point it operates over, rather + than before or after it. Because around is allowed to return a value, it + must be declared with a return type, like a method. A piece of around + advice may be declared void, in which case it is not + allowed to return a value, and instead whatever value the join point + returned will be returned by the around advice (unless the around advice + throws an exception of its own). + + + + Thus, a simple use of around advice is to make a particular method + constant: + + + +aspect A { + int around(): call(int C.foo()) { + return 3; + } +} + + + + Within the body of around advice, though, the computation of the original + join point can be executed with the special syntax + + + +proceed( ... ) + + + + 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: + + + + +aspect A { + 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 result of proceed is converted to an + object representation, even if it is originally a primitive value. And + when the advice returns an Object value, that value is converted back to + whatever representation it was originally. So another way to write the + doubling and halving advice is: + + + +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); + } +} + + + + In all kinds of advice, the parameters of the advice behave exactly like + method parameters. In particular, assigning to any parameter affects + only the value of the parameter, not the value that it came from. This + means that + + + +aspect A { + 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. + + + + Advice modifiers + + + The strictfp modifier is the only modifier allowed + on advice, and it has the effect of making all floating-point + expressions within the advice be FP-strict. + + + + + Advice and checked exceptions + + + An advice declaration must include a throws clause + listing the checked exceptions the body may throw. This list of + checked exceptions must be compatible with each target join point + of the advice, or an error is signalled by the compiler. + + + + For example, in the following declarations: + + + +import java.io.FileNotFoundException; + +class C { + int i; + + int getI() { return i; } +} + +aspect A { + before(): get(int C.i) { + throw new FileNotFoundException(); + } + before() throws FileNotFoundException: get(int C.i) { + throw new FileNotFoundException(); + } +} + + + + both pieces of advice are illegal. The first because the body throws + an undeclared checked exception, and the second because field get join + points cannot throw FileNotFoundExceptions. + + + The exceptions that each kind of join point in AspectJ may throw are: + + + + + method call and execution + + the checked exceptions declared by the target method's + throws clause. + + + + + constructor call and execution + + the checked exceptions declared by the target constructor's + throws clause. + + + + + field get and set + + no checked exceptions can be thrown from these join points. + + + + + exception handler execution + + the exceptions that can be thrown by the target exception handler. + + + + + static initializer execution + + no checked exceptions can be thrown from these join points. + + + + + initializer execution, pre-initialization, and initialization + + any exception that is in the throws clause of + all constructors of the initialized class. + + + + + + + + + + Advice precedence + + + Multiple pieces of advice may apply to the same join point. In such + cases, the resolution order of the advice is based on advice + precedence. + + + + Determining precedence + + There are a number of rules that determine whether a particular + piece of advice has precedence over another when they advise the same + join point. + + If the two pieces of advice are defined in different aspects, + then there are three cases: + + + If aspect A is declared such that it dominates + aspect B, then all advice defined in A has precedence over all advice + defined in + B. + + + Otherwise, if aspect A is a subaspect of aspect B, then all advice + defined in A has precedence over all advice defined in + B. So, unless otherwise specified with a + dominates keyword, advice in a subaspect + dominates advice in a superaspect. + + + + Otherwise, if two pieces of advice are defined in two different + aspects, it is undefined which one has precedence. + + + + + If the two pieces of advice are defined in the same aspect, then + there are two cases: + + + If either are after advice, then the one that + appears later in the aspect has precedence over the one that appears + earlier. + + Otherwise, then the one that appears earlier in the aspect + has precedence over the one that appears later. + + + + + These rules can lead to circularity, such as + + +aspect A { + before(): execution(void main(String[] args)) {} + after(): execution(void main(String[] args)) {} + before(): execution(void main(String[] args)) {} +} + + + such circularities will result in errors signalled by the compiler. + + + + + Effects of precedence + + At a particular join point, advice is ordered by precedence. + + A piece of around advice controls whether + advice of lower precedence will run by calling + proceed. The call to proceed + will run the advice with next precedence, or the computation under the + join point if there is no further advice. + + A piece of before advice can prevent advice of + lower precedence from running by throwing an exception. If it returns + normally, however, then the advice of the next precedence, or the + computation under the join pint if there is no further advice, will run. + + + Running after returning advice will run the + advice of next precedence, or the computation under the join point if + there is no further advice. Then, if that computation returned + normally, the body of the advice will run. + + Running after throwing advice will run the + advice of next precedence, or the computation under the join + point if there is no further advice. Then, if that computation threw + an exception of an appropriate type, the body of the advice will + run. + + Running after advice will run the advice of + next precedence, or the computation under the join point if + there is no further advice. Then the body of the advice will + run. + + + + + + Reflective access to the join point + + + Three special variables are visible within bodies of advice: + thisJoinPoint, + thisJoinPointStaticPart, and + thisEnclosingJoinPointStaticPart. Each is bound to + an object that encapsulates some of the context of the advice's current + or enclosing join point. These variables exist because some pointcuts + may pick out very large collections of join points. For example, the + pointcut + + + + +pointcut publicCall(): call(public * *(..)); + + + + + picks out calls to many methods. Yet the body of advice over this + pointcut may wish to have access to the method name or parameters of a + particular join point. + + + + thisJoinPoint is bound to a complete join point + object, while thisJoinPointStaticPart is bound to a + part of the join point object that includes less information, + but for which no memory allocation is required on each execution of the + advice. + + + + thisEnclosingJoinPointStaticPart is bound to the + static part of the join point enclosing the current join point. Only + the static part of this enclosing join point is available through this + mechanism. + + + + Like standard Java reflection, which uses objects from the + java.lang.reflect hierarchy, join point objects have + types in a type hierarchy. The type of objects bound to + thisJoinPoint is + org.aspectj.lang.JoinPoint, while + thisStaticJoinPoint is bound to objects of interface + type org.aspectj.lang.JoinPoint.StaticPart. + + + + + + + Static crosscutting + + + Advice declarations change the behavior of classes they crosscut, but do + not change their static type structure. For crosscutting concerns that do + operate over the static structure of type hierarchies, AspectJ provides + forms of introduction. + + + + Each introduction form is a member of the aspect defining it, but defines + a new member of another type. + + + + Member introduction + + + A method introduction looks like + + + + Modifiers + Type TypePattern + . + Id(Formals) + { Body } + + abstract Modifiers + Type TypePattern + . Id(Formals); + + + + + The effect of such an introduction is to make all the types in TypePattern + support the new method. Interfaces in TypePattern will support the new method + as well, even if the method is neither public nor abstract, so the + following is legal AspectJ code: + + + +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(); + } +} + + + + A constructor introduction looks like + + + + Modifiers TypePattern.new(Formals) + { Body } + + + + The effect of such an introduction is to make all the types in + TypePattern support the new constructor. You cannot introduce a + constructor onto an interface, so if TypePattern includes an interface + type it is an error. + + + + A field introduction looks like one of + + + + Modifiers + Type TypePattern.Id = Expression; + + Modifiers + Type TypePattern.Id; + + + + The effect of such an introduction is to make all the types in + TypePattern support the new field. Interfaces in TypePattern will + support the new field as well, even if the field is neither public, + nor static, nor final. + + + + + Any occurrence of the identifier this in the body of + the constructor or method introduction, or in the initializer of a + field introduction, refers to the target type from the + TypePattern rather than to the aspect type. + + + + + Access modifiers + + + Members may be introduced with access modifiers public or private, or + the default package-protected (protected introduction is not + supported). + + + + The access modifier applies in relation to the aspect, not in relation + to the target type. So a member that is privately introduced is visible + only from code that is defined within the aspect introducing it. One + that is package-protectedly introduced is visible only from code that + is defined within the introducing aspect's package. + + + + Note that privately introducing a method (which AspectJ supports) is + very different from introducing a private method (which AspectJ + previously supported). AspectJ does not allow the introduction of the + private method "void writeObject(ObjectOutputStream)" required to + implement the interface java.io.Serializable. + + + + + Conflicts + + + Introduction may cause conflicts among introduced members and between + introduced members and defined members. + + + + + Assuming otherPackage is not the package defining + the aspect A, the code + + + +aspect A { + private Registry otherPackage.*.r; + public void otherPackage.*.register(Registry r) { + r.register(this); + this.r = r; + } +} + + + + adds a field "r" to every type in otherPackage. This + field is only accessible from the code inside of aspect + A. The aspect also adds a + "register" method to every type in + otherPackage. This method is accessible + everywhere. + + + + If any type in otherPackage already defines a + private or package-protected field "r", there is no + conflict: The aspect cannot see such a field, and no code in + otherPackage can see the introduced + "r". + + + + If any type in otherPackage defines a public field + "r", there is a conflict: The expression + + + +this.r = r + + + + is an error, since it is ambiguous whether the introduced + "r" or the public "r" should be + used. + + + + If any type in otherPackage defines any method + "register(Registry)" there is a conflict, since it + would be ambiguous to any code that could see such a defined method + which "register(Registry)" method was applicable. + + + + Conflicts are resolved as much as possible as per Java's conflict + resolution rules: + + + + A subclass can inherit multiple fields from its superclasses, + all with the same name and type. However, it is an error to have an ambiguous + reference to a field. + + A subclass can only inherit multiple + methods with the same name and argument types from + its superclasses if only zero or one of them is concrete (i.e., all but + one is abstract, or all are abstract). + + + + + Given a potential conflict between inter-type member declarations in + different aspects, if one aspect dominates the other its declaration will + take effect without any conflict notice from compiler. This is true both + when the domination is declared explicitly in a "dominates" clause and + when sub-aspects implicitly dominate their corresponding super-aspect. + + + + + + Extension and Implementation + + + An aspect may introduce a superclass or superinterface onto a type, + with the declarations + + + + declare parents: TypePattern extends TypeList; + declare parents: TypePattern implements TypeList; + + + + For example, if an aspect wished to make a particular class runnable, + it might add an appropriate void run() method, but + it should also change the type of the class to specify that it fulfills + the Runnable interface. In order to implement the + methods in the Runnable interface, the + run() method must be publically introduced: + + + +aspect A { + declare parents: SomeClass implements Runnable; + public void SomeClass.run() { ... } +} + + + + + + Interfaces with members + + + Through the use of introduction, interfaces may now carry + (non-public-static-final) fields and (non-public-abstract) methods that + classes can inherit. Conflicts may occur from ambiguously inheriting + members from a superclass and multiple superinterfaces. + + + + Because interfaces may carry non-static initializers, the order of + super-interface instantiation is observable. We fix this order with the + following three properties: A supertype is initialized before a + subtype, that initialized code runs only once, and initializers for + supertypes run in left-to-right order. Consider the following hierarchy + where {Object, C, + D, E} are classes, + {M, N, O, + P, Q} are interfaces. + + + + Object M O + \ / \ / + C N Q + \ / / + D P + \ / + E + + + + when a new E is instantiated, the initializers run in this order: + + + + Object M C O N D Q P E + + + + + + Warnings and Errors + + An aspect may specify that a particular join point should never be + reached. + + + declare error: Pointcut: String; + declare warning: Pointcut: String; + + + If the compiler determines that a join point in + Pointcut could possibly be reached, then it + will signal either an error or warning, as declared, using the + String for its message. + + + + + Softened exceptions + + An aspect may specify that a particular kind of exception, if + thrown at a join point, should bypass Java's usual static exception + checking system and instead be thrown as a + org.aspectj.lang.SoftException, which is subtype of + RuntimeException and thus does not need to be + declared. + + + declare soft: TypePattern: Pointcut; + + + For example, the aspect + + +aspect A { + declare soft: Exception: execution(void main(String[] args)); +} + + + Would, at the execution join point, catch any + Exception and rethrow a + org.aspectj.lang.SoftException containing + original exception. + + This is similar to what the following advice would do + + +aspect A { + void around() execution(void main(String[] args)) { + try { proceed(); } + catch (Exception e) { + throw new org.aspectj.lang.SoftException(e); + } + } +} + + + except, in addition to wrapping the exception, it also affects + Java's static exception checking mechanism. + + + + + Statically determinable pointcuts + + Pointcuts that appear inside of declare forms + have certain restrictions. Like other pointcuts, these pick out join + points, but they do so in a way that is statically determinable. + + Consequently, such pointcuts may not include, directly or + indirectly (through user-defined pointcut declarations) pointcuts that + discriminate based on dynamic (runtime) context. Therefore, such + pointcuts may not be defined in terms of + + + cflow + cflowbelow + this + target + args + if + + + all of which can discriminate on runtime information. + + + + + Aspects + + + An aspect is a crosscutting type defined by the aspect declaration. The + aspect declaration is similar to the class declaration in that it defines + a type and an implementation for that type. It differs in that the type + and implementation can cut across other types (including those defined by + other aspect declarations), and that it may not be directly instantiated + with a new expression, with cloning, or with serialization. Aspects may + have one constructor definition, but if so it must be of a constructor + taking no arguments and throwing no checked exceptions. + + + + 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. + + + + Aspect Extension + + + To support abstraction and composition of crosscutting concerns, + aspects can be extended in much the same way that classes can. Aspect + extension adds some new rules, though. + + + + Aspects may extend classes and implement interfaces + + + An aspect, abstract or concrete, may extend a class and may implement + a set of interfaces. Extending a class does not provide the ability + to instantiate the aspect with a new expression: The aspect may still + only define a null constructor. + + + + + Classes may not extend aspects + + + It is an error for a class to extend or implement an aspect. + + + + + Aspects extending aspects + + + Aspects may extend other aspects, in which case not only are fields + and methods inherited but so are pointcuts. However, aspects may only + extend abstract aspects. It is an error for a concrete aspect to + extend another concrete aspect. + + + + + + Aspect instantiation + + + Unlike class expressions, aspects are not instantiated with + new expressions. Rather, aspect instances are + automatically created to cut across programs. + + + + Because advice only runs in the context of an aspect instance, aspect + instantiation indirectly controls when advice runs. + + + + The criteria used to determine how an aspect is instantiated + is inherited from its parent aspect. If the aspect has no parent + aspect, then by default the aspect is a singleton aspect. + + + + Singleton Aspects + + + aspect Id { ... } + aspect Id issingleton { ... } + + + + By default, or by using the modifier issingleton, an + aspect has exactly one instance that cuts across the entire program. + That instance is available at any time during program execution with + the static method aspectOf() defined on the aspect + -- so, in the above examples, A.aspectOf() will + return A's instance. This aspect instance is created as the aspect's + classfile is loaded. + + + + Because the an instance of the aspect exists at all join points in + the running of a program (once its class is loaded), its advice will + have a chance to run at all such join points. + + + + + Per-object aspects + + + aspect Id perthis(Pointcut) { ... } + aspect Id pertarget(Pointcut) { ... } + + + + If an aspect A is defined + perthis(Pointcut), then + one object of type A is created for every object that is the + executing object (i.e., "this") at any of the join points picked out + by Pointcut. + The advice defined in A may then run at any join point where the + currently executing object has been associated with an instance of + A. + + + Similarly, if an aspect A is defined + pertarget(Pointcut), + then one object of type A is created for every object that is the + target object of the join points picked out by + Pointcut. + The advice defined in A may then run at any join point where the + target object has been 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 Pointcut where + there is no associated aspect of type A. + + + Both perthis and pertarget + aspects may be affected by code the AspectJ compiler controls, as + discussed in the appendix. + + + + + Per-control-flow aspects + + + aspect Id percflow(Pointcut) { ... } + aspect Id percflowbelow(Pointcut) { ... } + + + + If an aspect A is defined + percflow(Pointcut) or + percflowbelow(Pointcut), + then one object of type A is created for each flow of control of the + join points picked out by Pointcut, either + as the flow of control is entered, or below the flow of control, + respectively. The advice defined in A may run at any join point in + or under that control flow. During each such flow of control, the + static method A.aspectOf() will return an object + of type + A. An instance of the aspect is created upon entry into each such + control flow. + + + + + + Aspect privilege + + + privileged aspect Id { ... } + + + + Code written in aspects is subject to the same access control rules as + Java code when referring to members of classes or aspects. So, for + example, code written in an aspect may not refer to members with + default (package-protected) visibility unless the aspect is defined in + the same package. + + + + While these restrictions are suitable for many aspects, there may be + some aspects in which advice or introductions needs to access private + or protected resources of other types. To allow this, aspects may be + declared privileged. Code in priviliged aspects has + access to all members, even private ones. + + + + +class C { + private int i = 0; + void incI(int x) { i = i+x; } +} +privileged aspect A { + static final int MAX = 1000; + before(int x, C c): call(void C.incI(int)) 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 signalled 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 + precedence. For example, in the code + + + +class C { + private int i = 0; + void foo() { } +} +privileged aspect A { + private int C.i = 999; + before(C c): call(void C.foo()) target(c) { + System.out.println(c.i); + } +} + + + + A's introduced private field C.i, initially bound to 999, will be + referenced in the body of the advice in preference to C's privately + declared field, since the A would have access to fields it introduces + even if it were not privileged. + + + + + + + Aspect domination + + + aspect Id dominates TypePattern { ... } + + + + An aspect may declare that the advice in it dominates the advice in + some other aspect. Such declarations are like the + strictfp keyword in Java; it applies to the advice + declarations inside of the respective aspects, and states that the + advice declared in the current aspect has more precedence than the + advice in the aspects from TypePattern. + + + + For example, the CountEntry aspect might want to count the entry to + methods in the current package accepting a Type object as its first + argument. However, it should count all entries, even those that the + aspect DisallowNulls causes to throw exceptions. This can be + accomplished by stating that CountEntry dominates DisallowNulls. + + + + +aspect DisallowNulls { + pointcut allTypeMethods(Type obj): call(* *(..)) args(obj, ..); + before(Type obj): allTypeMethods(obj) { + if (obj == null) throw new RuntimeException(); + } +} +aspect CountEntry dominates DisallowNulls { + pointcut allTypeMethods(Type obj): call(* *(..)) args(obj, ..); + static int count = 0; + before(): allTypeMethods(Type) { + count++; + } +} + + + + + + + + diff --git a/docs/progGuideDB/telecom.gif b/docs/progGuideDB/telecom.gif new file mode 100644 index 000000000..89a7207f3 Binary files /dev/null and b/docs/progGuideDB/telecom.gif differ diff --git a/docs/readme-docs-module.html b/docs/readme-docs-module.html new file mode 100644 index 000000000..0bd11ae2b --- /dev/null +++ b/docs/readme-docs-module.html @@ -0,0 +1,32 @@ + +AspectJ docs + +

    AspectJ docs

    + +The AspectJ docs include native sources (html and word files) +and XML DocBook files used to produce the FAQ and guides. +The dist directory contains the native files +as they are delivered with the distribution, and the +docbook directories + faq, + progGuideDB, and + devGuideDB +contain sources for the FAQ and the Programming and Development Guides, +generated using the Ant build.xml script. + +

    +Build: The script uses a taskdefs defined in ../lib/build/build.jar +to generate the installers, and others to do misc. text-conversion. +Dependencies outside this directory: +

      +
    • .xml files refer to their docbook dtds using relative + path, for the moment ../../lib/docbook/... +
    • +
    • When building docbook, uses ../lib/saxon libraries. +
    • +
    • When building installer, using ../lib/build/build.jar + and the ../build/installer-resources. +
    • +
    + + -- cgit v1.2.3