diff options
author | wisberg <wisberg> | 2002-12-16 17:58:19 +0000 |
---|---|---|
committer | wisberg <wisberg> | 2002-12-16 17:58:19 +0000 |
commit | d842c4f1139629c1f062b74ba818d233b2c31043 (patch) | |
tree | 842d3871620bc0eb60edcd95e55804d67e0f61fa /docs/dist | |
parent | 3ce247199704eae6b2c92c6e38c69584e3250c52 (diff) | |
download | aspectj-d842c4f1139629c1f062b74ba818d233b2c31043.tar.gz aspectj-d842c4f1139629c1f062b74ba818d233b2c31043.zip |
initial version
Diffstat (limited to 'docs/dist')
80 files changed, 10725 insertions, 0 deletions
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 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <meta http-equiv="Content-Language" content="en-us"> + <title>AjcTask Ant Support for AspectJ 1.1</title> +</head> +<body> + +<h2> +<a NAME="ajc"></a>AjcTask Ant Support for AspectJ 1.1</h2> + +<h3> +Description</h3> + +This task uses the AspectJ<small><sup>tm</sup></small> 1.1 compiler +<code>ajc</code>. + +The AspectJ compiler can be used like + <a href="http://jakarta.apache.org/ant/manual/CoreTasks/javac.html">Javac</a> +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 <tt>ajc</tt>, see the links from +the <a href="index.html">AspectJ docs home</a>. The main things to remember: +<ul> + <li>In incremental mode, sources may only be specified using source root directories. + </li> + <li>A .class file may only be woven once. That means + binaries in injars or aspectjpath must have been compiled with jikes or javac + or, if using ajc, with noweave. + </li> +</ul> +This task is named <tt>iajc</tt> now to avoid conflict with the +1.0 task <tt>ajc</tt>, but the name may change to <tt>ajc</tt> in +the future. +<p> +See <a href="#compilerMessages">below</a> for +an introduction to handling compiler messages programmatically. + +<p> +<h3> +Parameters</h3> + +<h4>Parameters supported by <code>ajc</code></h4> + +<table BORDER CELLSPACING=0 CELLPADDING=2 > +<tr> +<td VALIGN=TOP><b>Attribute</b></td> + +<td VALIGN=TOP><b>Description</b></td> + +<td ALIGN=CENTER VALIGN=TOP><b>Required</b></td> +</tr> + +<tr> +<th colspan="3">Specifying source and destination files</th> +</tr> + +<td VALIGN=TOP>sourceroots</td> + +<td VALIGN=TOP>a 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 <a href="nestedElements">nested element</a>. +</td> + +<td ALIGN=CENTER VALIGN=TOP>Yes, in incremental mode.</td> +</tr> + +<tr> +<td VALIGN=TOP>outjar</td> +<td VALIGN=TOP>Path to an output jar to generate with all output classes.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>destdir</td> +<td VALIGN=TOP>Specify where to place the generated class files.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>classpath</td> +<td VALIGN=TOP>the classpath required by the source files to compile. + May also be specified as a <a href="nestedElements">nested element</a>. +</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>srcdir</td> +<td VALIGN=TOP>the nested source base directory to compile, + specified as a <a href="nestedElements">nested element</a>. +</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>aspectpath</td> +<td VALIGN=TOP>the 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 <a href="nestedElements">nested element</a>. +</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>bootclasspath</td> +<td VALIGN=TOP>location of bootstrap class files.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>classpathref</td> +<td VALIGN=TOP>the classpath to use, given as a<a href="http://jakarta.apache.org/ant/manual/using.html#references"> +reference</a> to a PATH defined elsewhere.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>bootclasspathref</td> +<td VALIGN=TOP>location of bootstrap class files, given as a <a href="http://jakarta.apache.org/ant/manual/using.html#references">reference</a> +to a PATH defined elsewhere.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<th colspan="3">Specifying compiler behavior</th> +</tr> + +<tr> +<td VALIGN=TOP>noweave</td> +<td VALIGN=TOP>If true, produce binaries for the -injars option (only) -- +defaults to <tt>false</tt>.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> + <td VALIGN=TOP>incremental</td> + <td VALIGN=TOP>build once, then recompile on demand only required files; + defaults to <tt>false</tt>. + By default, files are recompiled based on input passed to stdin + (see tagfile)</td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>tagfile</td> + <td VALIGN=TOP>File that controls when incremental builds are done + and when the task completes.</td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>X</td> + <td VALIGN=TOP>Set 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.</td> <!-- XXX list --> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + + +<tr> +<th colspan="3">Specifying compiler side-effects and messages</th> +</tr> + +<tr> +<td VALIGN=TOP>verbose</td> +<td VALIGN=TOP>whether to emit compiler status messages during the compile; +defaults to <tt>false</tt>.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>version</td> +<td VALIGN=TOP>if true, do not compile - just print AspectJ version; +defaults to <tt>false</tt>.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>help</td> +<td VALIGN=TOP>if true, just print help for the command-line compiler; +defaults to <tt>false</tt>.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>Xlintenabled</td> +<td VALIGN=TOP>same as <tt>xlint:all</tt>, +whether to emit language usage messages during the compile; +defaults to <tt>false</tt>.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>Xlintfile</td> +<td VALIGN=TOP>specify property file containing name:level associations +for any overrides to the default associations for language usage +messaged emitted during the compile.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<!-- +<tr> +<td VALIGN=TOP>Xlint</td> +<td VALIGN=TOP>Specify which language usage messages to emit +during compile, using comma-separated list of entries. +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> +--> + +<tr> + <td VALIGN=TOP>failonerror</td> + <td VALIGN=TOP>whether the build continues notwithstanding compile errors; + defaults to <tt>true</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> +<td VALIGN=TOP>messageholderclass</td> +<td VALIGN=TOP>Specify 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 <tt>org.aspectj.bridge.IMessageHolder</tt> +interface and having a public no-argument constructor.</td> +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + + +<tr> +<th colspan="3">Eclipse compiler options</th> +</tr> + +<tr> + <td VALIGN=TOP>nowarn</td> + <td VALIGN=TOP>same as <tt>warn:none</tt>; + defaults to <tt>false</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>deprecation</td> + <td VALIGN=TOP>same as <tt>warn:deprecation</tt>; + defaults to <tt>false</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>warn</td> + <td VALIGN=TOP>one or more comma-separated warning specifications: +constructorName, +packageDefaultMethod, +deprecation, +maskedCatchBlocks, +unusedLocals, +unusedArguments, +unusedImports, +syntheticAccess, or +assertIdentifier.</td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>debug</td> + <td VALIGN=TOP>same as <tt>debug:lines,vars,source</tt></td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>debuglevel</td> + <td VALIGN=TOP>comma-separated list lines, vars, or source, + indicating to add debugging information for lines, + variables, or source</tt></td> <!-- XXX weak --> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>PreserveAllLocals</td> + <td VALIGN=TOP>code gen preserve all local variables (for debug purposes); + defaults to <tt>false</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>noimporterror</td> + <td VALIGN=TOP>no errors for unresolved imports; + defaults to <tt>false</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>referenceinfo</td> + <td VALIGN=TOP>compute reference info; + defaults to <tt>false</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>log</td> + <td VALIGN=TOP>File to log compiler messages to.</td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>encoding</td> + <td VALIGN=TOP>default source encoding format</td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>proceedonerror</td> + <td VALIGN=TOP>keep compiling when error, dumping class files with problem methods; + defaults to <tt>false</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>progress</td> + <td VALIGN=TOP>show progress (requires log); + defaults to <tt>false</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>time</td> + <td VALIGN=TOP>display speed information; + defaults to <tt>false</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>noexit</td> + <td VALIGN=TOP>disable System.exit (kills Ant -- use failonerror); + defaults to <tt>true</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>target</td> + <td VALIGN=TOP>Specify target class file format (must be "1.1" or "1.2"); + defaults to 1.1 class file. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>compliance</td> + <td VALIGN=TOP>Set "1.3" or "1.4" source compliance level + (e.g., no import from default package in 1.4); + defaults to 1.3 compliance level. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>source</td> + <td VALIGN=TOP>source assertion mode ("1.3" or "1.4"); + default depends on compliance mode. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +</table> + +<a name="nestedElements"></a> +<h3>Nested Elements</h3> +This taskdef should support nested elements as the old one did; +see <a href="taskdef-ajc10.html#nestedElements">taskdef-ajc10.html#nestedElements</a>. + +<a name="compilerMessages"></> +<h3>Programmatically handling compiler messages</h3> + +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). + + +<hr> +<center> +</center> + +</body> +</html> 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 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <meta http-equiv="Content-Language" content="en-us"> + <title>Ajc10 Ant Task</title> +</head> +<body> + +<h2> +<a NAME="ajc10"></a>Ajc10 Ant Task</h2> + +<h3> +Description</h3> +This task is provided for backwards compatibility with build scripts +created for the AspectJ 1.0 <tt>ajc</tt> 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. +<p> +This task compiles using the AspectJ<small><sup>tm</sup></small> compiler <code>ajc</code>; +you can use it in place of the + <a href="http://jakarta.apache.org/ant/manual/CoreTasks/javac.html">Javac</a> task. + +The interface is like the <tt>Javac</tt> task interface, except it also accepts +<a href="#ajc-parameters">parameters unique to <code>ajc</code></a>. +Of these, most no longer have any effect (nocomments, preprocess, workingdir, +maxmemory, jvmarg), but argfiles are still supported. (For more information +on argfiles, see <a href="#argfiles">below</a>.) +<p> + +<h3> +Parameters</h3> + +<h4>Parameters supported by <code>ajc</code></h4> + +<table BORDER CELLSPACING=0 CELLPADDING=2 > +<tr> +<td VALIGN=TOP><b>Attribute</b></td> + +<td VALIGN=TOP><b>Description</b></td> + +<td ALIGN=CENTER VALIGN=TOP><b>Required</b></td> +</tr> + +<tr> +<td VALIGN=TOP>srcdir</td> + +<td VALIGN=TOP>the base directory of the java files. (See <a href="#nestedElements">note</a>)</td> + +<td ALIGN=CENTER VALIGN=TOP>Yes, unless you use <tt>argfile</tt> +or nested <tt><src></tt> elements. +</tr> + +<tr> +<td VALIGN=TOP>destdir</td> + +<td VALIGN=TOP>Specify where to place the generated class files.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>includes</td> + +<td VALIGN=TOP>comma-separated list of patterns of files that must be included; +<b>no</b> +files are included when omitted.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>includesfile</td> + +<td VALIGN=TOP>the name of a file that contains include patterns.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>excludes</td> + +<td VALIGN=TOP>comma-separated list of patterns of files that must be excluded; +no files (except default excludes) are excluded when omitted.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>excludesfile</td> + +<td VALIGN=TOP>the name of a file that contains exclude patterns.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>defaultexcludes</td> + +<td VALIGN=TOP>whether default excludes should be used (<tt>yes</tt> +| <tt>no</tt>); default excludes are used when omitted.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>classpath</td> + +<td VALIGN=TOP>the classpath to use.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>bootclasspath</td> + +<td VALIGN=TOP>location of bootstrap class files.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>classpathref</td> + +<td VALIGN=TOP>the classpath to use, given as a<a href="http://jakarta.apache.org/ant/manual/using.html#references"> +reference</a> to a PATH defined elsewhere.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>bootclasspathref</td> + +<td VALIGN=TOP>location of bootstrap class files, given as a <a href="http://jakarta.apache.org/ant/manual/using.html#references">reference</a> +to a PATH defined elsewhere.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>extdirs</td> + +<td VALIGN=TOP>location of installed extensions </td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>debug</td> + +<td VALIGN=TOP>whether debug information should be included in classes output; +defaults to <tt>false</tt>.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>deprecation</td> + +<td VALIGN=TOP>whether compiler should emit messages about +usage of deprecated API; defaults to <tt>false</tt>.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>verbose</td> + +<td VALIGN=TOP>whether to emit compiler status messages during the compiler; +defaults to <tt>false</tt>.</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> + <td VALIGN=TOP>version</td> + <td VALIGN=TOP>print ajc version and exit</td> + <td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> + <td VALIGN=TOP>failonerror</td> + + <td VALIGN=TOP>whether the build continues notwithstanding compile errors; + defaults to <tt>true</tt>. </td> + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + + +<tr> + <td VALIGN=TOP>source</td> + + <td VALIGN=TOP>Value of -source option - ignored unless "1.4"</td> + + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +</table> + +<h4> +<a NAME="ajc-parameters-ignored"></a>Parameters that used to be ignored by +the <code>ajc</code> taskdef, but now are supported or cause failures</h4> + +<table BORDER CELLSPACING=0 CELLPADDING=2 > +<tr> +<td VALIGN=TOP><b>Attribute</b></td> + +<td VALIGN=TOP><b>Description</b></td> + +<td ALIGN=CENTER VALIGN=TOP><b>Support</b></td> +</tr> + +<tr> +<td VALIGN=TOP>encoding</td> + +<td VALIGN=TOP>encoding of source files.</td> + +<td ALIGN=CENTER VALIGN=TOP>Yes?</td> +</tr> + +<tr> +<td VALIGN=TOP>optimize</td> + +<td VALIGN=TOP>whether source should be compiled with optimization</td> + +<td ALIGN=CENTER VALIGN=TOP>Yes?</td> +</tr> + +<tr> +<td VALIGN=TOP>target</td> + +<td VALIGN=TOP>generate class files for specific VM version (e.g., <tt>1.1</tt> +or <tt>1.2</tt>).</td> + +<td ALIGN=CENTER VALIGN=TOP>Yes</td> +</tr> + +<tr> +<td VALIGN=TOP>depend</td> + +<td VALIGN=TOP>enables dependency-tracking </td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>includeAntRuntime</td> + +<td VALIGN=TOP>whether to include the Ant run-time libraries</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> +<td VALIGN=TOP>includeJavaRuntime</td> + +<td VALIGN=TOP>whether to include the run-time libraries from the +executing VM</td> + +<td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> +<tr> + <td VALIGN=TOP>threads</td> + <td VALIGN=TOP>Multi-threaded compilation</td> + <td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +</table> + + +<h4> +<a NAME="ajc-parameters"></a>Parameters unique to <code>ajc</code></h4> +<u>Note</u>: Many of the unique parameters in AspectJ 1.0 are no longer supported, +and fork is not supported yet. + +<table BORDER CELLSPACING=0 CELLPADDING=2 > +<tr> <td VALIGN=TOP><b>Attribute</b></td> + <td VALIGN=TOP><b>Description</b></td> + <td ALIGN=CENTER VALIGN=TOP><b>Required</b></td> +</tr> + +<tr> + <td VALIGN=TOP>X</td> + + <td VALIGN=TOP>comma-delimited list of extended (-X...) options, + entered without -X + (e.g., <code>X="lint"</code> for + <code>-Xlint</code>). </td> + + <td ALIGN=CENTER VALIGN=TOP>No</td> + </tr> + +<tr> + <td VALIGN=TOP>emacssym</td> + <td VALIGN=TOP>Generate symbols for Emacs IDE support + (defaults to off)</td> + <td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +<tr> + <td VALIGN=TOP>argfiles</td> + + <td VALIGN=TOP>a comma-delimited list of argfiles that + contain a line-delimited list of source file paths + (absolute or relative to the argfile) </td> + + <td ALIGN=CENTER VALIGN=TOP>No</td> +</tr> + +</table> + +<a name="argfiles"></a> +<h3>argfiles - Argument list files</h3> +An argument file is a file (usually <tt><file>.lst</tt>) 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 <code>ajc</code> requires +to avoid searching every possible source file in the source path when building aspects. +If you specify an argfile to the <tt>ajc</tt> 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. + +<br> +<a name="nestedElements"></a> +<h3> +Parameters specified as nested elements</h3> +This task forms an implicit <a href="http://jakarta.apache.org/ant/manual/CoreTypes/fileset.html">FileSet</a> +and supports all attributes of <tt><fileset></tt> (<tt>dir</tt> becomes +<tt>srcdir</tt>) +as well as the nested +<tt><include></tt>, <tt><exclude></tt>, +<tt><patternset>, +and <argfile></tt> elements. +<h4> +<tt>src</tt>, <tt>classpath</tt>, <tt>bootclasspath</tt> and <tt>extdirs</tt></h4> +<tt>ajc</tt>'s <i>srcdir</i>, <i>classpath</i>, +<i>bootclasspath, extdirs</i> +and <i>jvmarg</i> attributes are <a href="http://jakarta.apache.org/ant/manual/using.html#path">path-like +structures</a> and can also be set via nested +<tt><src></tt>, +<tt><classpath></tt>, +<tt><bootclasspath>, +<extdirs> </tt>and <tt><jvmarg> </tt>elements, respectively. +<p> +<h3> +Examples</h3> + +See <a href="../examples/builds.xml">../examples/builds.xml</a> +for an example build script. +<p> +This build script snippet + +<pre> <ajc srcdir="${src}" + destdir="${build}" + argfiles="demo.lst" + /></pre> +compiles all <tt>.java</tt> files specified in the <tt>demo.lst</tt> and +stores the <tt>.class</tt> files in the <tt>${build}</tt> directory. +Unlike the Javac task, the +<i>includes</i> attribute is empty by default, so only those +files specified in <tt>demo.lst</tt> are included. +<p>This next example +<pre> <ajc srcdir="${src}" + destdir="${build}" + includes="spacewar/*,coordination/*" + excludes="spacewar/Debug.java" + /></pre> +compiles <tt>.java</tt> files under the <tt>${src}</tt> directory in the +<tt>spacewar +</tt>and<tt> +coordination </tt>packages, and stores the +<tt>.class</tt> files in the +<tt>${build}</tt> directory. All source files under +<tt>spacewar/</tt> and +<tt>coordination/</tt> are used, except <tt>Debug.java</tt>. + + +<hr> +</body> +</html> 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 @@ +<html> + +<head> +<title>AspectJ Ant Tasks</title> +</head> + +<BODY> + +<h2 align="center">AspectJ Ant Tasks</h2> + +<p align="center"><i>Version @build.version.long@ released on @build.date@.</i></p> + +<h3>About the AspectJ Ant tasks</h3> + +AspectJ contains a compiler, <tt>ajc</tt>, that can be run from Ant. + +Included in the <tt>aspectjtools.jar</tt> are Ant binaries to support +three ways of running the compiler: +<ol> +<li><tt>Ajc10</tt> (<a href="ant-ajc10-task.html">options</a>), + a task to run build scripts compatible with the AspectJ 1.0 tasks,</li> +<li><tt>AjcTask</tt> (<a href="ant-ajc-task.html">options</a>), + a task to run the new AspectJ 1.1 compiler, which supports + all the eclipse and ajc options, including incremental mode; +<li><tt>Ajc11CompilerAdapter</tt>, + an adapter class to run the new compiler using Javac tasks + by setting the build.compiler property.</li> +</ol> + +This describes how to install and use the tasks and the adapter. +For an example Ant script, +see <a href="../examples/build.xml">../examples/build.xml</a>. + +<h3>Installation</h3> +<p>Install Jakarta Ant 1.5.1: + Please see the official + <a href="http://jakarta.apache.org/ant/index.html">Jakarta + Ant website</a> for more information and + the 1.5.1 <a href="http://jakarta.apache.org/builds/jakarta-ant/release/v1.5.1/bin/"> + distribution</a>. +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 <a href="@aspectj.home.url@">@aspectj.home.url@</a>. + +<p>In Ant, third-party tasks can be declared using a <tt>taskdef</tt> entry +in the build script, to identify the name and classes. + +When declaring a task, include the <tt>aspectjtools.jar</tt> +either in the taskdef classpath +or in <tt>${ANT_HOME}/lib</tt> +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: +<pre> + <taskdef + resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"> +</pre> +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. <!-- XXX --> +</p> +<p>For more information on using Ant, please refer to +Jakarta's <a href="http://jakarta.apache.org/ant/manual/develop.html">documentation</a> +on integrating user-defined Ant tasks into builds.</p></li> +<p> + +<h3><a name="#ajc10">Ajc10 (script name: ajc)</a></h3> +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.) +<p> +Following is a declaration for the ajc task and a sample invocation +that uses the ajc compiler to compile the files listed in +<tt>default.lst</tt> into the <tt>dest</tt> dir. +<pre> +<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> +</pre> + +<h3><a name="#ajctask">AjcTask (script name: iajc)</a></h3> +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. + +<p>Below is an example of incrementally compiling <tt>src</tt> + and <tt>testsrc</tt> root source directories, using <tt>tagfile.txt</tt> + 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. +<pre> +<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> +</pre> + + +<h3><a name="#adapter">Ajc11CompilerAdapter</a></h3> +This CompilerAdapter can be used in <tt>javac</tt> tasks calls +by setting the <code>build.compiler</code> +property to the class name. This enables users to +to easily switch between Javac and the AspectJ compiler. + +To build this way, install <tt>aspectjtools.jar</tt> in <tt>${ANT_HOME}/lib</tt> +and define the <tt>build.compiler</tt> +property as the fully-qualified name of the class: + +<pre> + cp aspectj1.1/lib/aspectjtools.jar ant/lib + ant/bin/ant -Dbuild.compiler=org.aspectj.tools.ant.taskdefs.Ajc11CompilerAdapter ... +</pre> + +The AspectJ compiler should run for any compile using the <tt>Javac</tt> task +(for options, see the Ant documentation for the Javac task). + +<p> +To pass <tt>ajc</tt>-specific arguments, use a <code>compilerarg</code> entry. +For example, + +<pre> + +-- 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 > +</pre> + +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. + +<hr> + +<h3>4. What to do if you encounter problems</h3> +<p>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. +<p> + +<li>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.) </li> + + +<li>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.</li> + +<li>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).</li> + +<p><b>Known Problems</b> +<br>For the most up-to-date information on known problems, see the + <a href="@aspectj.home.url@/bugs">bug database</a> for + <a href="@aspectj.home.url@/bugs/compiler">compiler bugs</a> + or <a href="@aspectj.home.url@/ant-support">task bugs</a>. + +<li><u>Memory and forking</u>: +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. +<u>Forking is not supported in this release</u>, 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). +</li> +<li><u>Messages suppressed</u>: In the incremental task, +messages from the compiler are printed but not segregated. +</li> + +<p> +You can send email to <a href="mailto:users@aspectj.org">users@aspectj.org</a>. +(Do join the list to participate!) We also welcome any bug reports; you can +submit them to <a href="@aspectj.home.url@/bugs">@aspectj.home.url@/bugs</a>. +</body> + +</html> 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 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<HTML> + +<head> +<LINK rel="STYLESHEET" href="../style.css" type="text/css"> +<title>AspectJ 1.0.6 Reference -- Recent Changes</title> +</head> + +<body> + +<DIV ALIGN=right CLASS=copyrightNotice> +© Copyright 1998-2002 Palo Alto Research Center Incorporated. All rights reserved. +</DIV> + +<h1>Recent Changes in AspectJ 1.0</h1> + +<ul> + <li><a href="#1.0.6">1.0.6</a> (released 2002-07-24) + <ul> + <li><a href="#1.0.6compiler">Compiler</a></li> + <li><a href="#1.0.6ajde">AJDE</a></li> + <li><a href="#1.0.6ajdoc">Ajdoc</a></li> + </ul> + </li> + + <li><a href="#1.0.5">1.0.5</a> (released 2002-06-27) + </li> + + <li><a href="#1.0.4">1.0.4</a> (released 2002-04-17) + </li> + + <li><a href="#1.0.3">1.0.3</a> (released 2002-02-08) + </li> + <li><a href="#1.0.2">1.0.2</a> (released 2002-02-06) + </li> + <li><a href="#1.0.1">1.0.1</a> (released 2001-12-18) + </li> + <li><a href="#1.0.0">1.0.0</a> (released 2001-11-30) + </li> + <li><a href="#1.0rc3">1.0rc3</a> (released 2001-11-14) + </li> + <li><a href="#1.0rc2">1.0rc2</a> (released 2001-10-12) + </li> + <li><a href="#1.0rc1">1.0rc1</a> (released 2001-10-5) + </li> + <li><a href="#1.0beta1">1.0beta1</a> (released 2001-08-29) + </li> + <li><a href="#1.0alpha1">1.0alpha1</a> (released 2001-08-09) + </li> + <li><a href="#oldversions">Previous Versions</a></li> + <li><a href="porting.html">Porting and Transition</a></li> +</ul> + +<hr /> + +<h2><a name="1.0.6">1.0.6</a></h2> + +<p> This release contains mainly bug fixes for ajde and ajdoc. + +<h3><a name="1.0.6compiler">Compiler</a></h3> + +<p>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. +</p> + +<h3><a name="1.0.6ajde">AJDE</a></h3> + +<p><b>AJDE Framework, AJBrowser, and AJDE for Forte/NetBeans</b></p> + +<p>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.</p> + +<h4>AJDE for JBuilder</h4> + +<p>JBuilder 7 is now supported. All known bugs have been fixed including:</p> + +<ul> + <li><a href="http://aspectj.org/bugs/resolved?id=787">787</a> + AJDE for JBuilder throws exception given non-existent file</li> + <li><a href="http://aspectj.org/bugs/resolved?id=788">788</a> + Label too small in error message </li> + <li><a href="http://aspectj.org/bugs/resolved?id=789">789</a> + Index-out-of-bounds exception in JBuilder AJDE </li> + <li><a href="http://aspectj.org/bugs/resolved?id=792">792</a> + Required libraries disappear from JBuilder 6 </li> + <li><a href="http://aspectj.org/bugs/resolved?id=795">795</a> + Unable to compile open tools </li> + <li><a href="http://aspectj.org/bugs/resolved?id=802">802</a> + AJDE loses current (cursor) position in file when switching files </li> +</ul> + +<p>In addition, thanks to user feedback that indicated trouble building JBuilder +OpenTools with AJDE/JBuilder, the OpenTool is now being built with itself. </p> + +<h3><a name="1.0.6ajdoc">Ajdoc</a></h3> + <ul> + <li>Fixed <a href="http://aspectj.org/bugs/resolved?id=790">790</a> + aspect code comments suppressed by fix to bug 710 + </li> + <li>Known problems: <a href="http://aspectj.org/bugs/ajdoc"> + http://aspectj.org/bugs/ajdoc + </a></li> + </ul> + +<hr /> + +<h2><a name="1.0.5">1.0.5</a></h2> + + +<p>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. </p> + +<ul> + <li><a href="#1.0.5compiler">Compiler</a></li> + <li><a href="#1.0.5ajde">AJDE</a></li> + <li><a href="#1.0.5ajdoc">Ajdoc</a></li> + <li><a href="#1.0.5anttasks">Ant tasks</a></li> +</ul> + +<h3><a name="1.0.5compiler">Compiler</a></h3> + +<p> 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. </p> + +<h3><a name="1.0.5ajde">AJDE</a></h3> + +<h4><span style="font-weight: 400">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. </span></h4> + + +<ul> + <li><span style="font-weight: 400">The entire user interface has been revised + and streamlined.</span></li> + <li>The structure view and browser have a new UI, and offer both a file-based + and global structure views. All views expose node ordering, node + filtering, and association filtering functionality. The global views + expose a package tree as well as the global inheritance and crosscutting + structure. </li> + <li>Structure view navigation now has a history exposed by back/forward.</li> + <li>The is a new build configuration management UI.</li> + <li>The compiler preferences UI now includes access to all build options.</li> + <li>Error messages have been improved, and the structure views include + annotations of nodes with errors and warnings.</li> +</ul> + +<h4>AJDE for JBuilder</h4> + + +<p>Integration into the JBuilder IDE is more streamlined. In addition:</p> + + +<ul> + <li>The AspectJ Browser is included as a tool that replaces JBuilder's + "Project View" and can be used to navigate the global structure of your system + (including the crosscutting and inheritance structure).</li> + <li>Inline structure annotations in the editor's gutter can now expose all of + the structure presented in the structure view, and can be used to navigate in + a similar way. Note that there are preferences for toggling which of + these appear.</li> + <li>Building is better integrated and the JBuilder build toolbar is removed + when AJDE is enabled.</li> + <li>Build configurations can be selected from the build button's menu.</li> + <li>Execution is better integrated: instead of a separate "run" button + JBuilder's run and debug can be used. Note that for new projects you + will need to use the "AspectJ Runtime" library, which will be added to your + preferences automatically.</li> + <li>A new graphical build configuration editor can be used by double-clicking + ".lst" files that have been added to the project. </li> + <li>Error messages now match JBuilder's look-and-feel and behavior. + Seeking to column numbers now works in addition to line numbers.</li> +</ul> + + +<h4>AJDE for Forte/NetBeans</h4> + + +<p>Integration into the NetBeans IDE is more streamlined. In addition:</p> + + +<ul> + <li>NetBeans 3.3.2 and SunONE Studio 4 are supported.</li> + <li>Multiple filesystems are supported.</li> + <li>Default project build configurations (all project files) are now + supported.</li> + <li>Build configurations can be selected in the tool bar.</li> + <li>Regular NetBeans execution and debugging is supported. Note that you + have to add netbeans/lib/ext/aspectjrt.jar file to your project configuration.</li> + <li>Class files are generated beside source files (NetBeans/javac default). + There is currently no way to specify a target directory.</li> +</ul> + + +<h4>AJBrowser</h4> + + +<ul> + <li>The browser now supports main class execution. Set the main class in + the options dialog, and make sure that both the Java executable is on your + path, and the class that you expect to execute on your classpath.</li> + <li>The error messages UI has been improved.</li> +</ul> + + +<h3><a name="1.0.5ajdoc">Ajdoc</a></h3> +<p>Bug fixes: +</p> + <ul> + <li><a href="http://aspectj.org/bugs/resolved?id=710">710 - + compiler-generated constructor shown with class comment + </a></li> + <li><a href="http://aspectj.org/bugs/resolved?id=712">712 - + comments lost in aspect docs for methods + or constructors declared on other types. + </a></li> + <li><a href="http://aspectj.org/bugs/resolved?id=719">719 - + poor support for @link, @see tags + </a></li> + <li><a href="http://aspectj.org/bugs/resolved?id=742">742 - + crash with @see tag + </a></li> + <li><a href="http://aspectj.org/bugs/resolved?id=751">751 - + error loading doclet resource + </a></li> + </ul> + +<h3><a name="1.0.5anttasks">Ant tasks</a></h3> +<p>Bug fixes: +</p> + <ul> + <li><a href="http://aspectj.org/bugs/resolved?id=730">730 - + document all supported ajc flags <a></li> + </ul> + +<hr /> + +<h2><a name="1.0.4">1.0.4</a></h2> + +<ul> + <li><a href="#1.0.4compiler">Compiler</a></li> + <li><a href="#1.0.4ajde">AJDE</a></li> + <li><a href="#1.0.4ajdoc">Ajdoc</a></li> + <li><a href="#1.0.4taskdefs">Ant taskdefs</a></li> + <li><a href="#1.0.4doc">Documentation</a></li> +</ul> + +<h3><a name="1.0.4compiler">Compiler</a></h3> +<ul> + <li>Over a dozen people independently reported a bug in error + handling for the wrong number number of arguments to + <code>proceed</code>. This has been turned into a nice error + message. A number of other bug reports related to around advice and + proceed have also been fixed, including the ability to change the + bindings for <code>this</code> and <code>target</code> using proceed + in around advice. + </li> + <li>David Walend gets the <em>black thumb</em> award for the most + bug reports submitted by a new user. His bug report on the + behavior of after returning advice led to some valuable clarifications + of this part of the language spec. + </li> + <li>A number of places where ajc didn't fully comply with the Java + Language Spec have been fixed in this release. Thanks to Neal + Gafter for reporting many of these. + </li> +</ul> + +<h4>Incompatible changes</h4> + +<p>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.</p> + +<ul> + <li>The obsolete class + <code>org.aspectj.lang.MultipleAspectsBoundException</code> has been + removed from aspectjrt.jar. This class had not been used since + AspectJ-0.8 and should have been removed prior to the 1.0 release. + It is not documented as part of the 1.0 language spec. This change + will cause a compile-time type not found error in any code that + refers to this exception.</code> + + <li>The compiler was not correctly implementing the AspectJ-1.0 + language design for some uses of after returning advice. This + compiler behavior was fixed, and advice whose behavior might be + changed by this bug fix will be highlighted with a compiler + warning. More information about some of these changes can be found + in the <a href="porting.html#pre-1.0.4">porting notes</a>.</li> +</ul> + +<h3><a name="1.0.4ajde">AJDE</a></h3> + + +<p>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.</p> + + +<h4>AJDE for JBuilder</h4> + +<ul> + <li>Updates<ul> + <li>This is a bug fix release only. </li> + </ul> + </li> +</ul> + +<h4>AJDE for Forte/NetBeans</h4> + +<ul> + <li>Updates<ul> + <li>NetBeans 3.3.1 is now supported in addition to NetBeans 3.2 and Forte CE + 3.</li> + <li>Native NetBeans main class execution can now be used. After doing + a "Compile with AJC" browse to the main class in the "Filesystems" Explorer, + right-click the class and select "Execute". </li> + <li>The debugger can now be used if the project main class is set ("Project" + menu -> "Set Project Main Class...").</li> + <li>Numerous bugs have been fixed.</li> + </ul> + </li> + <li>Known limitations<ul> + <li>Breakpoint setting does not work in the debugger.</li> + <li>In the "Filesystems" Explorer red Xs appear on files with AspectJ source + code. The "AspectJ" Explorer understands the structure of AspectJ + projects and should be used for navigating structure instead.</li> + </ul> + </li> +</ul> + +<h4>AJDE for Emacs</h4> + + +<ul> + <li>This is a bug fix release only.</li> +</ul> + + +<h3><a name="1.0.4ajdoc">Ajdoc</a></h3> +<p>Ajdoc now runs under J2SE 1.4, but still requires the tools.jar + from J2SE 1.3 be on the classpath. +</p> + +<h3><a name="1.0.4taskdefs">Ant tasks</a></h3> +<ul> + <li>Repackaged to fit into the AspectJ product directory - e.g., + <code>aspectj-ant.jar</code> moved to <code>lib</code> + as expected by <code>examples/build.xml</code>. + </li> + <li>Fixed bugs, esp. <a href="http://aspectj.org/bugs/resolved?id=682">682</a>: + Throw BuildException if failonerror and ajdoc detects misconfiguration. + </li> +</ul> +<h3><a name="1.0.4doc">Documentation</a></h3> +<p>Added a 1-page quick reference guide. Improved javadoc documentation for + the org.aspectj.lang package. +</p> + + +<hr/> + +<h2><a name="1.0.3">1.0.3</a></h2> + +<ul> + <li><a href="#1.0.3compiler">Compiler</a></li> + <li><a href="#1.0.3taskdefs">Ant taskdefs</a></li> +</ul> + +<h3><a name="1.0.3compiler">Compiler</a></h3> +<p> This release fixes a single significant bug in 1.0.2 where ajc +could generate unreachable code in <code>-usejavac</code> or +<code>-preprocess</code> mode. This would happen when around advice +was placed on void methods whose body consisted solely of a +<code>while (true) {}</code> 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. +</p> + +<h3><a name="1.0.3taskdefs">Ant taskdefs</a></h3> +<p>Added support to the Ajc taskdef for the -source 1.4 and -X options generally. +</p> + +<hr /> + +<h2><a name="1.0.2">1.0.2</a></h2> + +<p> 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. +</p> + +<ul> + <li><a href="#1.0.2compiler">Compiler</a></li> + <li><a href="#1.0.2ajde">AJDE</a></li> + <li><a href="#1.0.2ajdb">AJDB</a></li> +</ul> + +<h3><a name="1.0.2compiler">Compiler</a></h3> + +<ul> + <li>Official support for <code>-source 1.4</code> option to compile new + <a href="http://java.sun.com/j2se/1.4/docs/guide/lang/assert.html">1.4 assertions</a>. + This makes ajc completely compatible with j2se-1.4. + </li> + <li>Implementation of <a href="http://jcp.org/jsr/detail/45.jsp"> + JSR-45 Debugging Support for Other Languages</a> so that debuggers which + correctly implement this specification will be able to accurately debug + any AspectJ program at a source code level. We are not currently + aware of any debuggers that implement this so far, but expect that + as j2se-1.4 becomes widely available this will change. + </li> + <li>As proposed by Arno Schmidmeier and seconded by Nick Lesiecki, we now have an + experimental <code>-Xlint</code> option that will provide warnings when + type patterns used in pcds have no bindings. We are very interested in + feedback on the usefulness and suggested improvements for this feature. + </li> + <li>Several significant bugs in the implementation of around advice have been fixed. + These include issues with <a href="http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=632"> + dynamic tests</a>, with + <a href="http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=620"> + complicated local types in an around body</a>, and with + <a href="http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=636"> + capturing proceed in a closure</a>. + </li> + <li>All but two (<a href="http://aspectj.org/jitterbug/aspectj-bugs/compiler?id=626">1</a>, + <a href="http://aspectj.org/jitterbug/aspectj-bugs/compiler?id=645">2</a>) + verified bugs in 1.0.1 have been fixed. The two outstanding bugs + have relatively easy work-arounds. Thanks as usual to everyone who + submitted a bug report. + </li> + <li>We no longer use the <code>SYNTHETIC</code> attribute to label declarations + added by the aspectj compiler. We were using this attribute in compliance + with <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#80128"> + the JVM Specification</a>; however, we've found that many tools expect + this attribute to only be used for the narrow purpose of implementing + Java's inner classes and that using it for other synthetic members can confuse + them. This led to problems both + <a href="http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=649">with javap</a> and + <a href="http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=646">with javac</a>. + </li> + <li>Changes required adding runtime classes, so please compile and run using the latest + <code>aspectjrt.jar</code> + </li> + +</ul> + +<h3><a name="1.0.2ajde">AJDE</a></h3> + +<p align="left">This is a bug fix release only. </p> + +<ul> + <li> + +<p align="left">Thanks to Dave Yost and Matt Drance for submitting the AJDE +patches for Mac OSX (context popup menus and keyboard shortcuts did not work). </p> + + </li> + <li> + +<p align="left">Bugs in history navigation (back-forward buttons in the +structure view) have been fixed.</p> + + </li> + <li> + +<p align="left">"Declares" are now handled properly in the structure view.</p> + + </li> + <li> + +<p align="left">Other GUI and usability improvements have been made the AspectJ +Browser and core framework.</p> + + </li> +</ul> + +<h4>AJDE for JBuilder</h4> + + +<ul> + <li>Support has been extended to JBuilder 6, and support for Enterprise + version features has been improved.</li> + <li>Fixed bug causing inline source code annotations in the editor pane to not + be updated after a recompile.</li> + <li>Keyboard shortcuts were fixed to work with Mac OSX.</li> +</ul> + + +<h4>AJDE for Forte</h4> + + +<ul> + <li>Keyboard shortcuts were fixed to work with Mac OSX.</li> +</ul> + +<h4><a name="1.0.2ajdb">AJDB</a></h4> + +<p> 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. +</p> + +<hr /> + +<h2><a name="1.0.1">1.0.1</a></h2> + +<ul> + <li><a href="#1.0.1compiler">Compiler</a></li> + <li><a href="#1.0.1ajde">AJDE</a></li> + <li><a href="#1.0.1ajdb">AJDB</a></li> +</ul> + +<h3><a name="1.0.1compiler">Compiler</a></h3> + +<p> 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 <a +href=http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=610>this +bug report</a> for an example. +</p> + +<p> A new experimental flag has been added, +<code>-XaddSafePrefix</code>, that will cause the prefix +<code>aspectj$</code> 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. +</p> + + +<h3><a name="1.0.1ajde">AJDE</a></h3> + +<p align="left">Minor bug fixes, including: AJDE for JBuilder failed to preserve +application parameters from project settings when executing the application.</p> + +<p align="left">Source builds were cleaned up for JBuilder and Forte sources.</p> + +<h3><a name="1.0.1ajdb">AJDB</a></h3> + +<p>Two bugs were reported and have been fixed in this release. + (Note that ajdb is still considered early-access software.)</p> + +<ul> + <li>bug 611: NullPointerException dumping non-primitive values</li> + <li>bug 617: -X and -D options not passed to debug VM correctly</li> +</ul> + +<h2><a name="1.0.0">1.0.0</a></h2> + +<ul> + <li><a href="#1.0.0language">Language</a></li> + <li><a href="#1.0.0compiler">Compiler</a></li> + <li><a href="#1.0.0ajde">AJDE</a></li> + <li><a href="#1.0.0ajdoc">AJDoc</a></li> + <li><a href="#1.0.0taskdefs">Ant taskdefs</a></li> +</ul> + +<h2><a name="1.0.0language">Language</a></h2> + +<p>There were no language changes for this release.</p> + +<h2><a name="1.0.0compiler">Compiler</a></h2> + +<p>Several minor bugs primarily in error handling were reported and +have been fixed in this release. The two most serious bugs are +described below:</p> + +<ul> + <li>Niall Smart and Stephan Schmidt reported related bugs (variants + of which are also produced by other compilers) that caused verify + errors when dealing with nested try-finally and synchronized + statements. These are now fixed. More details are available + <a href="http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=601"> + here</a> and + <a href="http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=595"> + here</a> + </li> + + <li>Jan Hannemann submitted a <a + href="http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=600"> + succint and clear bug report</a> for a difficult intermittant bug. + The bug led to the compiler sometimes generating illegal code when + introduced methods on a class overrode introduced methods on an + interface implemented by that class. This is now fixed.</li> </ul> + +<h2><a name="1.0.0ajde">AJDE</a></h2> + +<p align="left">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.</p> + +<h4>AJDE for JBuilder</h4> + + +<ul> + <li>The AspectJ Browser now uses JBuilder's icons and distinguishes nodes by + visibility.</li> + <li>Project-setting VM parameters are now supported by the "AJDE Run" button.</li> +</ul> + + +<h4>AJDE for Forte</h4> + + +<ul> + <li>The AspectJ Browser now uses Forte's icons and distinguishes nodes by + visibility</li> +</ul> + + +<h4>AJBrowser</h4> + + +<ul> + <li>Documentation for the browser is now available at + <a href="http://aspectj.org/docs">http://aspectj.org/docs</a> </li> +</ul> + + +<h4>Emacs Support: aspectj-mode and AJDEE</h4> + +<ul> + <li>Improved updating of annotations during editing.</li> + <li>Pop-up jump menu now placed (with mouse pointer) near cursor.</li> + <li>[AJDEE only] Improved filtering of legal code completions.</li> +</ul> + +<h4><a name="1.0.0ajdoc">AJDoc</a></h4> + +<ul> + <li>Runs only in J2SE 1.3 - not 1.2 or 1.4. + You can document 1.x-reliant programs by using the options + to compile using 1.x libraries.</li> + <li>Disabled some non-functioning options, documented as + <code>unsupported</code> in the syntax message.</li> +</ul> + +<h4><a name="1.0.0taskdefs">Ant taskdefs</a></h4> +<ul> + <li>Fork is not supported in the AJDoc taskdef</li> +</ul> + +<h2><a name="1.0rc3">1.0rc3</a></h2> + +<h2><a name="1.0rc3language">Language</a></h2> + +<p>There have been several minor clarifications/changes to the +language.</p> + +<ul> + <li>Thanks to Robin Green for suggesting that we could relax the + rules for inheriting multiple concrete members in order to allow + those unambiguous cases where one member has already overridden the + other. <a href=http://aspectj.org/pipermail/users/2001/001289.html> + More details...</a></li> + + <li>Ron Bodkin encouraged us to examine the details of privileged + aspects more closely. This led to several small improvements and + clarifications to this language feature. + <a href=http://aspectj.org/pipermail/users/2001/001258.html> More + details...</a></li> +</ul> + +<h2><a name="1.0rc3compiler">Compiler</a></h2> + +<p>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.</p> + +<ul> + <li>Hanson Char reported a bug where ajc's correctly generated + bytecodes for some references to interface fields result in verify + errors on certain JVMs. While this is a known bug in those JVMs, + we've modified ajc to be bug compatible with all the other Java + compilers out there to work-around this JVM bug. + <a href=http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=551> + More details...</a></li> + + <li>Frank Hunleth discovered a similar bug where ajc's correct + bytecodes could lead to essentially random method dispath due to a + bad bug in the 1.3.0 JVM from Sun. Even though this bug was fixed + in the 1.3.1 and 1.2.2 JVMs, we have introduced the appropriate + work-around in ajc's code generation. <a + href=http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=580>More + details...</a></li> + + <li>Thomas Haug (as well as several other members of his group) + reported a problem with name binding where ajc was behaving + differently than javac. This problem was resolved to come from a + class created by an obfuscator that conflicted with his package + names. The JLS doesn't clearly specify which of these two behaviors + is correct. Nevertheless, ajc has been changed to treat packages + more like javac does in order to minimize this sort of problem in + the future. <a + href=http://aspectj.org/jitterbug/aspectj-bugs/resolved?id=574> More + details...</a></li> + + <li>Several "real" bugs in ajc were also reported and fixed. Toby + Allsopp gets credit for reporting two of them. The most interesting + of these bugs to me was his report that we just didn't support + qualified anonymous inner constructors. This is a part of the Java + language that ajc has never supported over its almost 3 year + history. We'd just noticed this ourselves when running the jacks + compiler test suite from the jikes group, and had added the feature + days before getting our first bug report for it not being + there.</li> +</ul> + +<h2><a name="1.0rc3ajde">AJDE</a></h2> + +<ul> + <li>The structure view has been improved. </li> + <li>Multiple user-configurable views are supported.</li> + <li>Structure tree filtering and ordering has been added. </li> + <li>A split tree mode has been added to permit the navigation of multiple + views on the same structure. </li> + <li>The view can also be toggled between a file-based and a system-based mode + which determines whether the root of the structure tree is the current file or + the project root. </li> + <li>The signatures of tree nodes have been improved and several new node + associations are now navigable. </li> + <li>A depth slider for controlling tree-expansion has been added.</li> +</ul> + +<h4>AJDE for JBuilder</h4> + + +<ul> + <li>Changes:</li> + <li>Inline annotations support have been improved and made consistent with the + structure tree (annotations only show up for intra-declaration structure).</li> + <li>The current structure view persists across IDE launches.</li> + <li>An enabled AJDE no longer slows down JBuilder shutdown.</li> +</ul> + + +<h4>AJDE for Forte</h4> + + +<ul> + <li>Execution remembers main class.</li> + <li>The bug causing an error during a "Mode" and "Explorer" switch has been + fixed.</li> +</ul> + + +<h4>AJBrowser</h4> + + +<ul> + <li>AJBrowser is currently an undocumented demonstration application. To use + it type: ajbrowser <lst file1> <lst file2> ...</li> + <li>Multiple source locations can be shown by selecting multiple nodes and + right-clicking to select the "Display Sources" command.</li> +</ul> + + +<h4>Emacs Support: aspectj-mode and AJDEE</h4> + +<ul> + <li>Numerous jump-menu improvements, including operation of pop-ups.</li> + <li>For AJDEE, compatibility with JDEE 2.2.9beta4. Also, fixes in completion, + ajdoc launch, and speedbar.</li> +</ul> + +<h3><a name="1.0rc3ajdoc">AJDoc</a></h3> + +<p>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:</p> +<ul> + <li>Split indexes do not work correctly</li> + <li>Inner classes are not listed in indexes </li> + <li>Synthetic methods are documented</li> + <li>There is no package frame even when packages are specified on the command line</li> + <li>-group option is not implemented</li> + <li>-use targets are not all calculated correctly</li> + <li>Exception information may not be printed for the @throws tag</li> + <li>Verbose output should go to stderr, not stdout</li> + <li>Extra links are generated (should be unlinked text) </li> +</ul> +<p>Further, Ajdoc has not been testing on variants of the J2SE (it uses javadoc classes). + +<h3><a name="1.0rc3taskdefs">Ant taskdefs</a></h3> +<p>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. +<p> +<hr /> +<h2><a name="1.0rc2">1.0rc2</a></h2> + + <ul> + <li><a href="#1.0rc2language">Language</a></li> + <li><a href="#1.0rc2compiler">Compiler</a></li> + <li><a href="#1.0rc2ajde">AJDE</a></li> + </ul> + +<h2><a name="1.0rc2language">Language</a></h2> + +<p>There are no language changes in this release. This is a bug fix release +only.</p> + +<h2><a name="1.0rc2compiler">Compiler</a></h2> + +<p>A bug in handling inner type names that conflict with enclosing +type names was fixed. Many error messages were improved.</p> + +<h2><a name="1.0rc2ajde">AJDE</a></h2> + +<ul> + <li>This is a bug fix release only.</li> +</ul> + +<h4>AJDE for JBuilder</h4> + +<ul> + <li>Changes:<ul> + <li>Fixed bug causing the output path to be ignored and .class files to be + generated into the JBuilder install's "bin" directory.</li> + <li>Fixed bugs in Browser listener causing NullPointerExceptions to be thrown + if no node editor was present.</li> + <li>Fixed bug permitting "-bcg" option to be passed to the compiler.</li> + <li>Fixed bug preventing ajc from compiling all of the project source files + when automatic package discovery was on (JBuilder Proffessional and Enterprise + editions).</li> + <li>If the "-preprocess" flag is used resulting source files will be placed in + the project's "Working directory".</li> +</ul> + + </li> + <li>Limitations:<ul> + <li>"Automatic package discovery" mode is not supported in this release.</li> + <li>The debugger has not seen much use and it's stability and performance is + limited.</li> + </ul> + </li> +</ul> + +<h4>AJDE for Forte</h4> + +<ul> + <li>Changes:<ul> + <li>Moved the "AspectJ" menu into the "Tools" menu in order to make it less + intrusive.</li> + <li>Added a "ctrl-alt-shift-F9" keyboard compile shortcut.</li> +</ul> + + </li> + <li>Limitations:<ul> + <li>Known bug: "Mode" switching is not supported in this version--you must + do all of your AspectJ work in the "Editing" mode. If you switch modes the + IDE has to be restarted for the AspectJ window to show again. Switching to a + different tab in the ProjectExplorer has the same effect.</li> + <li>The debugger has not seen much use and it's stability and performance is + limited.</li> + </ul> + </li> +</ul> + +<h4>AJBrowser</h4> + +<ul> + <li>Changes:<ul> + <li>...</li> +</ul> + + </li> + <li>Limitations:<ul> + <li>AJBrowser is currently an undocumented demonstration application. To use + it type:<br> + > ajbrowser <lst file1> <lst file2> ...</li> +</ul> + + </li> +</ul> + +<h4>Emacs Support: aspectj-mode and AJDEE</h4> + +<p align="left"> 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.</p> + +<hr /> + +<h2><a name="1.0rc1">1.0rc1</a></h2> + + <ul> + <li><a href="#1.0rc1language">Language</a></li> + <li><a href="#1.0rc1compiler">Compiler</a></li> + <li><a href="#1.0rc1ajde">AJDE</a></li> + </ul> + +<h2><a name="1.0rc1language">Language</a></h2> + +<p>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 +<a href="progguide/apb.html">the semantics section of the programming +guide</a>. +</p> + +<p>In a related change, aspects are not allowed to implement either +the <code>java.io.Serializable</code> or the +<code>java.lang.Cloneable</code> 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.</p> + +<h2><a name="1.0rc1compiler">Compiler</a></h2> + +<p>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.</p> + +<p>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. +</p> + +<p>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.</p> + +<h2><a name="1.0rc1ajde">AJDE</a></h2> + +<ul> + <li>The structure view can now be configured (using the "Options" dialog) to + display different kinds of associations between program elements that appear + in the tree.</li> + <li>Structure view history navigation has been added. </li> + <li>When navigating links the structure view will stay synchronized with the + editor.</li> +</ul> + +<h4>AJDE for JBuilder</h4> + +<ul> + <li>Changes:<ul> + <li>Inline structural navigation annotations appear in the gutter of the + editor and can be used to navigate associations such as advice and + introduction.</li> +</ul> + + </li> + <li>Limitations:<ul> + <li>"Automatic package discovery" mode is not supported in this release.</li> + <li>The debugger has not seen much use and it's stability and performance is + limited.</li> + </ul> + </li> +</ul> + +<h4>AJDE for Forte</h4> + +<ul> + <li>Changes:<ul> + <li>Support for Forte 3 and Netbeans 3.2 has been added.</li> + <li>The module is now installed by default on the first use without having to + go to the IDE options to enable it.</li> +</ul> + + </li> + <li>Limitations:<ul> + <li>Known bug: "Mode" switching is not supported in this version--you must + do all of your AspectJ work in the "Editing" mode. If you switch modes the + IDE has to be restarted for the AspectJ window to show again. Switching to a + different tab in the ProjectExplorer has the same effect.</li> + <li>The debugger has not seen much use and it's stability and performance is + limited.</li> + </ul> + </li> +</ul> + +<h4>AJBrowser</h4> + +<ul> + <li>Changes:<ul> + <li>Build configuration file editor added.</li> +</ul> + + </li> + <li>Limitations:<ul> + <li>AJBrowser is currently an undocumented demonstration application. To use + it type:<br> + > ajbrowser <lst file1> <lst file2> ...</li> +</ul> + + </li> +</ul> + +<h4>Aspectj-mode and AJDEE: AspectJ support in Emacs</h4> + +<p align="left">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. </p> + +<hr /> + +<h2><a name="1.0beta1">1.0beta1</a></h2> + +<ul> + <li><a href="#1.0beta1language">Language</a></li> + <li><a href="#1.0beta1compiler">Compiler</a></li> + <li><a href="#1.0beta1ajbrowser">AJBrowser</a></li> + <li><a href="#1.0beta1ajde">AJDE</a></li> +</ul> + +<h2><a name="1.0beta1language">Language</a></h2> + +<p>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.</p> + +<p>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.</p> + +<h2><a name="1.0beta1compiler">Compiler</a></h2> + +<p>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.</p> + +<p>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.</p> + +<h2><a name="1.0beta1ajbrowser">AJBrowser</a></h2> + +<ul> + <li>Support for executing classes has been added.</li> + <li>.lst can now be passed as arguments on the command line.</li> + <li>Compiler options can be set.</li> + <li>Know limitations:<ul> + <li>In order to execute classes they must be available on the classpath that + the browser is launched with.</li> + </ul> + </li> +</ul> + +<h2><a name="1.0beta1ajde">AJDE</a></h2> + +<ul> + <li>The performance and UI of the structure tree has been improved.</li> + <li>Compilation now runs in a separate thread and a progress monitor is + updated during the compile.</li> + <li>The structure view now persists across IDE launches.</li> + <li>Limitations:<ul> + <li>If an error occurs in the javac pass it will not display properly in the + error messages pane. To view the error you have check the output of the + console that the IDE was launched from. No more errors should be passed + to javac, so please report this behavior and the corresponding error message + as a bug.</li> +</ul> + + </li> +</ul> + +<h4>AJDE for JBuilder</h4> + +<ul> + <li>Known bugs have been fixed.</li> + <li>Classpath separator character is no longer hardcoded.</li> + <li>Keyboard shortcuts for compilation (ctrl-F11) and execution (ctrl-F12) + have been added.</li> + <li>Limitations:<ul> + <li>The debugger has not seen much use and it's stability and performance is + limited.</li> + </ul> + </li> +</ul> + +<h4>AJDE for Forte</h4> + +<ul> + <li>Known bugs have been fixed.</li> + <li>Limitations:<ul> + <li>"Mode" switching is not supported in this version--you must do all of your + AspectJ work in the "Editing" mode. If you switch modes the IDE has to + be restarted for the AspectJ window to show again.</li> + <li>There are no keyboard compile/execute shortcuts.</li> + <li>The debugger has not seen much use and it's stability and performance is + limited.</li> + </ul> + </li> +</ul> + +<h4>Aspectj-mode and AJDEE: AspectJ support in Emacs</h4> + +<p> 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. +</p> + +<hr /> + +<h2><a name="1.0alpha1">1.0alpha1</a></h2> + +<p> 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. </p> + + <ul> + <li><a href="#1.0alpha1language">Language</a></li> + <li><a href="#1.0alpha1compiler">Compiler</a></li> + <li><a href="#1.0alpha1documentation">Documentation</a></li> + <li><a href="#1.0alpha1ajdoc">AJDoc</a></li> + <li><a href="#1.0alpha1ant">Ant</a></li> + <li><a href="#1.0alpha1ajbrowser">AJBrowser</a></li> + <li><a href="#1.0alpha1ajde">AJDE</a></li> + </ul> + +<h3><a name="1.0alpha1language">Language</a></h3> + +<p> 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. + +<p>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 <code>declare error</code>), Stefan +Hanenberg (who should appreciate the '+' wildcard in type patterns), +and Rich Price (who suggested final pointcuts, more flexible +dominates, and many other improvements).<p> + +<p> Note that entries into the <a href="porting.html">porting +notes</a> for this release are linked from the various language +changes. </p> + +<h4>Pointcuts</h4> + +<p> 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) </p> + +<blockquote>calls executions gets sets handlers initializations +staticinitializations</blockquote> + +<p> have been +<a href="porting.html#1.0a1-plural-to-singular">changed</a> to be +singular rather than plural nouns </p> + +<blockquote>call execution get set handler initialization +staticinitialization</blockquote> + +<p> Although a side benefit is that the names are one character +shorter, the real benefit is that their combination with the +<CODE>&&</CODE> and <code>||</code> operators now reads much +more naturally. No longer does "and" mean "or" and "or" mean "and". +</p> + +<p> You'll notice that <code>receptions</code> doesn't appear on the +table as being shortened to <code>reception</code>. That's because +call and reception join points have been merged, and the +<code>receptions</code> pointcut declaration has been +<a href="porting.html#1.0a1-remove-receptions">eliminated</a>. Now, +<code>call</code> 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.</p> + +<p> We have <a href="porting.html#1.0a1-fixing-state-access">changed +the mechanism for accessing state</a> at join points, which has the +benefit of making our treatment of signatures +<a href="porting.html#1.0a1-no-subs-in-sigs">cleaner</a> and easier to +read. As a part of this, the <code>instanceof</code> pointcut +designator has now been +<a href="porting.html#1.0a1-fixing-instanceof">split into two +different pointcut designators</a>, <code>this</code> and +<code>target</code>, corresponding to a join point's currently +executing object and target object, respectively. </p> + +<p> The new <code>args</code> 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 <code>HashSet.removeAll</code> method takes a +<code>Collection</code> as an argument, you can write advice that only +runs when it is actually passed a <code>HashSet</code> object. </p> + +<p> AspectJ's notion of object construction and initialization, a +complicated process in Java, has been clarified. This affects some +uses of the +<a href="porting.html#1.0a1-initializations">initializations +pointcut</a> and +<a href="porting.html#1.0a1-constructor-calls">constructor calls</a> +pointcut. </p> + +<p> The little-used pointcuts +<a href="porting.html#1.0a1-hasaspect"><code>hasaspect</code></a> and +<a href="porting.html#1.0a1-withinall"><code>withinall</code></a> have +been removed. </p> + +<p> The <code>returns</code> keyword is +<a href="porting.html#1.0a1-user-defined-returns">no longer +necessary</a> for user-defined pointcuts. </p> + +<p> Pointcuts may now be declared <code>static</code>, and +<a href="porting.html#1.0a1-static-pointcuts">only static +pointcuts</a> may be declared in classes and referred to with +qualified references (such as <code>MyAspect.move()</code>). </p> + +<p> Non-abstract pointcuts may now be declared <code>final</code>. +</p> + +<p> We have finally added an extremely general pointcut, +<code>if(<var>BooleanExpression</var>)</code>, that picks out +join points programatically. </p> + + +<h4>Type patterns</h4> + +<p> Our treatment of +<a href="porting.html#1.0a1-new-wildcards">* and ..</a> in type +patterns is cleaner. </p> + +<p> 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 <a href="porting.html#1.0a1-subtypes-to-plus">spelled +differently</a>. </p> + +<h4>Advice</h4> + +<p> Around advice is treated much more like a method, with a +<a href="porting.html#1.0a1-around-returns">return value</a> and an +optional <a href="porting.html#1.0a1-around-throws">throws clause</a>. +</p> + +<p> The advice precedence rules have been +<a href="porting.html#1.0a1-advice-precedence">changed</a>. 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. </p> + +<p> After returning advice has lost a +<a href="porting.html#1.0a1-after-returning">useless set of +parentheses</a> when not using the return value. </p> + +<p> The <code>thisStaticJoinPoint</code> reflective object has been +<a href="porting.html#1.0a1-this-static-join-point">renamed</a>, and +the <code>thisJoinPoint</code> object hierarchy has been +<a href="porting.html#1.0a1-this-join-point">simplified</a>. </p> + +<h4>Introduction and static crosscutting</h4> + +<p> On the static side of the language, introduction hasn't changed, +but there is now a new keyword, <code>declare</code>, that is used to +declare various statically-crosscutting properties. One of these +properties is subtyping, so we've +<a href="porting.html#1.0a1-plus-implements-extends">gotten rid of</a> +the ugly keywords <code>+implements</code> and +<code>+extends</code>. </p> + +<p> We have provided two new forms, <code>declare error</code> and +<code>declare warning</code>, for the often-asked-for property of +compile-time error detection based on crosscutting properties. </p> + +<p> 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, <code>declare soft</code>, can be used to +"soften" checked exceptions into an unchecked form. This may affect +some uses of <a href="porting.html#1.0a1-now-use-soft">around +advice</a> that previously mucked with the exception checking +system.</p> + +<h4>Aspects</h4> + +<p> The "of each" modifiers have been +<a href="porting.html#1.0a1-aspects">renamed</a>. Apart from the +spelling, the main interesting difference is the splitting up of +<code>of eachobject</code> into two different modifiers, parallel with +the split of <code>instanceof</code> into <code>this</code> and +<code>target</code>. </p> + +<p> The <code>dominates</code> 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: <code>aspect A +dominates B+</code>. +</p> + +<h3><a name="1.0alpha1compiler">Compiler</a></h3> + +<p> 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.</p> + +<p>The compiler also gets a new <code>-encoding</code> 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. + +<h4>Known Limitations</h4> + +<p> 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. </p> + +<p> 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. </p> + + +<h3><a name="1.0alpha1documentation">Documentation</a></h3> + +<p> 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 <cite>Primer</cite> has been +split into a <cite>Programming Guide</cite>, covering the language, and a +<cite>Development Environment Guide</cite>, covering the develompent tools. In +addition, printable versions of both guides (in PDF) are finally +included in the documentation package. </p> + +<h3><a NAME="1.0alpha1ajdoc">Ajdoc</a></h3> + +<p> 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). +</p> + +<h3><a NAME="1.0alpha1ant">Ant</a></h3> + +<p> An Ajdoc task is now available. The Ajc ant task was improved to +be completely back-compatible with the Javac task.</p> + +<h3><a NAME="1.0alpha1ajbrowser">AJBrowser</a></h3> + +<p> 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.</p> + +<h3><a name="1.0alpha1ajde">AJDE</a></h3> + +<h4>AJDE for JBuilder</h4> + +<h5>Installation</h5> +<ul> + <li>Use the installer to place the "ajdeForJBuilder.jar" and "aspectjrt.jar" + in to JBuilder's lib/ext directory.</li> +</ul> + +<h5>Key Improvements</h5> + +<ul> + <li>The "AspectJ Structure View" replaces JBuilder's structure view instead of + being launched in a separate window.</li> + <li>AJDE can be toggled on/off with the "AJ" button--when it is turned off all + of the menus, resources, and event listeners that it uses will be removed.</li> + <li>Projects no longer require the manual adding of the "aspectjrt.jar" + libarary.</li> +</ul> + +<h5>Known Bugs & Limitations</h5> + +<ul> + <li>There is no compiler progress dialog--the way to tell if the compile is + finished is to watch the "status" area of the main window.</li> + <li>There are no keyboard compile/execute shortcuts.</li> + <li>The structure view is not persistent between IDE launches--you must + compile to view the structure for a program.</li> + <li>The debugger has not seen much use and it's stability and performance is + limited.</li> + <li>There is no ajdoc tool support.</li> + <li>Linux testing has been very limited.</li> +</ul> + + +<h4>AJDE for Forte</h4> + + +<h5>Installation</h5> + +<ul> + <li>Use the installer to place the "ajdeForForte.jar" in Forte's + modules directory and "aspectjrt.jar" + in to Forte's lib/ext directory.</li> + <li> + In the "Tools" menu select "Global Options"</li> + <li> + Right-click the "Modules" item and select "New Module from + File..."</li> + <li> + Find the ajdeForForte.jar in the directory that you installed into (e.g. + c:\forte4j\modules) and + select it.</li> +</ul> + +<h5>Key Improvements</h5> + +<ul> + <li>AJDE can be toggled on/off with the "AJ" button--when it is turned off all + of the menus, resources, and event listeners that it uses will be removed.</li> + <li>The AJDE functionality is now contained within it's own toolbar and menu.</li> +</ul> + +<h5>Known Bugs & Limitations</h5> + +<ul> + <li>"Mode" switching is not supported in this version--you must do all of your + AspectJ work in the "Editing" mode. If you switch modes the IDE has to + be restarted for the AspectJ window to show again.</li> + <li>There is no compiler progress dialog--the way to tell if the compile is + finished is to watch the "status" area of the main window.</li> + <li>There are no keyboard compile/execute shortcuts.</li> + <li>The structure view is not persistent between IDE launches--you must + compile to view the structure for a program.</li> + <li>The debugger has not seen much use and it's stability and performance is + limited.</li> + <li>There is no ajdoc tool support.</li> + <li>Linux testing has been very limited.</li> +</ul> + +<h4>AJDE for Emacs</h4> + +<p> 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. </p> + +<p> 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. +</p> + + +<hr /> + +<h2><a name="oldversions">Previous Versions</a></h2> + +<p> Changefiles for previous versions can be found in +<code>doc/oldversions</code> in the documentation distribution. +</p> + + +</body> +</html> 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 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<html> <head> +<LINK rel="STYLESHEET" href="../style.css"> +<!-- type="text/css": Error: no attribute "TYPE" for this element (in 3.2) --> +<title>AspectJ Documentation and Resources</title> +</head> +<body> +<a name="top"></a> +<h1>AspectJ Documentation and Resources</h1> +<p> + AspectJ <sup><small>tm</small></sup> + is a seamless aspect-oriented extension to + Java<sup><small>tm</small></sup>. + 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 + <a href="@aspectj.home.url@">@aspectj.home.url@</a>, + especially the <a href="@aspectj.home.url@/faq">FAQ</a>. +<p> + +<table> + <tr><td><u>Section</u></td><td><u>Contents</u></td></tr> + <tr><td><a href="#documentation">docs</a></td><td> + <a href="faq.html">FAQ</a>, + <a href="quick.pdf">Quick Reference</a>, + <a href="progguide/index.html">programming</a> and + <a href="devguide/index.html">development</a> guides, + <a href="api/overview-summary.html">API</a> and + <!-- start strip --> + (<a href="../examples/">local</a>) + <!-- end strip --> + examples + <tr><td><a href="#distributions">distributions</a></td><td> + compiler, AJDE, docs, and Ant taskdefs + (<a href="@aspectj.home.url@/dl">binary</a> + - <a href="@aspectj.home.url@/sources">source</a>) + <tr><td><a href="#resources">resources</a></td><td> + <a href="http://aosd.net">aosd.net</a>; + <a href="@aspectj.home.url@">aspectj.org</a> + bug <a href="@aspectj.home.url@/bugs">db</a> and + <a href="mailto:jitterbug@aspectj.org">email</a>, + mail <a href="@aspectj.home.url@/lists">lists</a> for + <a href="mailto:users@aspectj.org">users</a> and + <a href="mailto:support@aspectj.org">support</a> + <tr><td><a href="#paths">paths</a> </td><td>for those new to AspectJ +</table> +<p> + +<a name="documentation"></a> +<h3>AspectJ documentation</h3> +<table border="1"> +<tr> <th>Documentation</th><th>Description</th> + </tr> + +<tr> <td><a href="quick.pdf"> AspectJ Quick Reference</a> + <!-- start strip --> + (<a href="@aspectj.home.url@/doc/dist/quick.pdf">web</a>) + <!-- end strip --> + </td> + <td>This is a two-page quick reference for the AspectJ language. + </td> </tr> + + +<tr> <td><a href="progguide/index.html">Programming Guide</a> + (printable <a href="progguide.pdf">pdf</a> or <a href="progguide/printable.html">html</a> + <!-- start strip --> + - <a href="@aspectj.home.url@/doc/dist/progguide/index.html">web</a> + <!-- end strip --> + ) + </td> + <td>This introduces AOP and the AspectJ language. + <a href="progguide/ch01.html">Getting Started</a> + describes basic semantics, and shows development- and production-time applications. + <a href="progguide/ch02.html">The AspectJ Language</a> + describes join points, pointcuts, advice, and introduction, all features new to AOP. + <a href="progguide/ch03.html">Examples</a> walks you through the + examples included with the documentation, and there are two short + chapters on useful <a href="progguide/ch04.html">Idioms</a> and a + few <a href="progguide/ch05.html">Pitfalls</a> + The appendices have reference information: + the <a href="progguide/apa.html">Quick Reference</a> + summarizes AspectJ syntax, + the <a href="progguide/apb.html">Language Semantics</a> + best describes AspectJ usage, and + <a href="progguide/apc.html">Implementation Limitations</a> notes that + the current version is limited to code the compiler controls.</td> + </tr> + +<tr> <td><a href="devguide/index.html">Development Environment Guide</a><br> + + (printable <a href="devguide/printable.html">html</a> + <!-- start strip --> + - <a href="@aspectj.home.url@/doc/dist/devguide/index.html">web</a> + <!-- end strip --> + ) + </td> + <td>Find here a guide to the command-line compiler <u><tt>ajc</tt></u> + and API doc tool <u><tt>ajdoc</tt></u>, as well as + the <u>AspectJ Development Environment (AJDE)</u> for managing crosscutting + structure in JBuilder, Forte, Emacs, and the stand-alone <tt>ajbrowser</tt>. + (For using <tt>ajc</tt> and <tt>ajdoc</tt> in + <a href="http://jakarta.apache.org/ant">Ant</a> builds, + see the <code>taskdefs</code> distribution.) + </td> + </tr> + +<tr> <td><a href="api/overview-summary.html">AspectJ API</a> + <!-- start strip --> + (<a href="@aspectj.home.url@/doc/dist/api/overview-summary.html">web</a>) + <!-- end strip --> + </td> + <td>API documentation for AspectJ runtime classes. <tt>JoinPoint</tt> + shows the state automatically available at each join point. + </td> </tr> + +<tr> <td><a href="faq.html"> FAQ</a> + <!-- start strip --> + (<a href="@aspectj.home.url@/doc/dist/faq.html">web</a>) + <!-- end strip --> + </td> + <td>Frequently-asked questions about the AspectJ language, tools, and project. + </td> </tr> + +<tr> <td><a href="porting.html"> Porting guide</a> + <!-- start strip --> + (<a href="@aspectj.home.url@/doc/dist/porting.html">web</a>) + <!-- end strip --> + </td> + <td>How users can convert code from pre-1.0 versions + of AspectJ to 1.0. + </td> </tr> + +<tr> <td><a href="changes.html"> Changes </a> + <!-- start strip --> + (<a href="@aspectj.home.url@/doc/dist/changes.html">web</a>) + <!-- end strip --> + </td> + <td>Changes between the latest releases. + </td> </tr> + +<tr> <td>Examples + <!-- start strip --> + (<a href="../examples/">local</a>) + <!-- end strip --> + </td> + <td>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. + </td> </tr> + +</table> + +<a name="distributions"></a> +<h3>AspectJ distributions</h3> +<table border="1"> +<tr> <th>Distributions</th><th>Description</th> +<tr> <td><a href="@aspectj.home.url@/dl">AspectJ</a> + </td> + <td>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.) + </td> + </tr> + +<tr> <td><a href="http://eclipse.org/ajdt">AspectJ for Eclipse</a> + </td> + <td>AspectJ Development Environment support for + Eclipse is available under the Common Public License 1.0 + from the eclipse.org project site + <a href="http://eclipse.org/ajdt"> + http://eclipse.org/ajdt</a> + </td> + </tr> + +<tr> <td><a href="http://aspectj4emacs.sourceforge.net"> + AspectJ for Emacs</a> + </td> + <td>AspectJ Development Environment support for + Emacs is available under the GPL + from the sourceforge project site + <a href="http://aspectj4emacs.sourceforge.net/"> + http://aspectj4emacs.sourceforge.net</a> + </td> + </tr> + +<tr> <td><a href="http://aspectj4jbuildr.sourceforge.net"> + AspectJ for JBuilder</a> + </td> + <td>AspectJ Development Environment support for + JBuilder is available under the Mozilla Public License 1.1 + from the sourceforge project site + <a href="http://aspectj4jbuildr.sourceforge.net/"> + http://aspectj4jbuildr.sourceforge.net</a> + </td> + </tr> + +<tr> <td><a href="http://aspectj4netbean.sourceforge.net"> + AspectJ for Netbeans</a> + </td> + <td>AspectJ Development Environment support for + Netbeans is available under the Mozilla Public License 1.1 + from the sourceforge project site + <a href="http://aspectj4netbean.sourceforge.net/"> + http://aspectj4netbean.sourceforge.net</a> + </td> + </tr> + +</table> + +<a name="resources"></a> +<h3>Other AspectJ resources</h3> +<table border="1"> +<tr> <th>Resources</th><th>Description</th> + </tr> +<tr> <td> + user + <a href="mailto:users@aspectj.org">email</a> + <a href="@aspectj.home.url@/lists">list</a> + </td> + <td>Developers use the + <a href="mailto:users@aspectj.org">users@aspectj.org</a> + mail list to discuss tips and + best practices for developing with AspectJ. + </td> </tr> + +<tr> <td> + announce + <a href="mailto:announce@aspectj.org">email</a> + <a href="@aspectj.home.url@/lists">list</a> + </td> + <td> + <a href="mailto:announce@aspectj.org">announce@aspectj.org</a> + has notices about releases and AspectJ team events. + </td> </tr> + +<tr> <td> + <a href="mailto:support@aspectj.org">email</a> us + </td> + <td> + Email <a href="mailto:support@aspectj.org">support@aspectj.org</a> + to contact the AspectJ team directly. + (As a small team, we cannot reply as fast as + <a href="mailto:users@aspectj.org">users</a> + can for usage questions.) + </td> </tr> + +<tr> <td>Bug + <a href="@aspectj.home.url@/bugs">DB</a> + and <a href="mailto:jitterbug@aspectj.org">email</a> + </td> + <td>Please send AspectJ bugs! (as a small program + that reproduces the problem) + </td> </tr> + +<tr> <td> <a href="http://aosd.net">http://aosd.net</a> - the AOSD web site + </td> + <td>This site has discussion and announcements related to + aspect-oriented software development (AOSD) in general. + Use <a href="mailto:announce@aosd.net">announce@aosd.net</a> + to get and publish notices about AOSD + workshops, conferences, and technology releases. + Use <a href="mailto:announce@aosd.net">discuss@aosd.net</a> + for general AOSD discussions. + </td> </tr> +</table> + +<p> +<a name="paths"></a> +<h3>Suggested paths for those new to AspectJ</h3> +<p> + To learn the AspectJ language, read the + <a href="progguide/index.html">Programming Guide</a>, + keeping the <a href="progguide/apb.html">Semantics appendix</a> + 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 + <!-- start strip --> + <a href="../examples/">local</a> + <!-- end strip --> + examples as described in the + <a href="progguide/ch03.html">Examples </a> section of the + <a href="progguide/index.html">Programming Guide</a>. + View and navigate the crosscutting structure using + the <code>ajbrowser</code> structure viewer, as described in + the <a href="devguide/rn02re04.html">ajbrowser</a> section of + the <a href="devguide/index.html">Development Environment Guide</a>. +<p> + To start using AspectJ with your own code, + modify the example aspects to apply to your classes. + The <a href="devguide/index.html">Development Environment Guide</a> + shows how to build using the command-line tools. + As you learn, + use the compiler's <code>-Xlint</code> flag to catch some common + mistakes. (Understand that the + <a href="progguide/apc.html">current implementation</a> + is limited to code the compiler controls.) +<p> + To plan how to adopt AspectJ into a project, read the + <a href="progguide/index.html">Programming Guide</a> + on development- and production-time aspects + and the <a href="faq.html">FAQ</a> entries for + <a href="faq.html#q:startUsingAJ">How should I start using AspectJ?</a>, + <a href="faq.html#adoption">Deciding to adopt AspectJ</a>, + the Development tools sections + (<a href="faq.html#q:integrateWithDevTools">one</a>, + <a href="faq.html#devtools">two</a>), + <a href="faq.html#q:opensource">AspectJ as open-source</a> and + <a href="faq.html#q:consulting">available support and consulting</a>. +</p> +<p> + Otherwise, see + the <a href="faq.html">FAQ</a>, + <a href="@aspectj.home.url@/lists">view</a> or + <a href="mailto:users@aspectj.org">email</a> the + AspectJ users list, and enjoy the language! +</p> +<p> +The AspectJ Team +</p> + +<hr> +<small> +<a href="#top">Top</a> +</small> +</body> </html> 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 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + +<head> +<LINK rel="STYLESHEET" href="../style.css" type="text/css"> +<title>AspectJ 1.0.6 Reference - Porting Notes</title> +</head> + +<body> + +<DIV ALIGN=right CLASS=copyrightNotice> +© Copyright 1998-2002 Palo Alto Research Center Incorporated. All rights reserved. +</DIV> + +<h1>Porting Notes</h1> + +<ul> + <li><a href="#pre-1.0.4">Pre-1.0.4 code</a></li> + <li><a href="#pre-1.0rc1">Pre-1.0rc1 code</a></li> + <li><a href="#pre-1.0beta1">Pre-1.0beta1 code</a></li> + <li><a href="#pre-1.0alpha1">Pre-1.0alpha1 code</a> + </li> + <li><a href="#pre08b3">Pre-0.8beta3 code</a></li> + + <li><a href="#pre08b1">Pre-0.8beta1 code</a></li> + + <li><a href="#pre07b11">Pre-0.7beta11 code</a></li> + + <li><a href="#pre07b10">Pre-0.7beta10 code</a></li> +</ul> + +<h2><a name="pre-1.0.4">Porting pre-1.0.4 code</a></h2> + +<p>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. +</p> + +<p> The main change that was made was of after returning advice for +constructor execution join points. Previously, this advice was legal: +</p> + +<PRE> +after() returning (Foo f): execution(Foo.new(..)) { ... } +</PRE> + +<p> 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, +<code>this</code> 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. </p> + +<PRE> +after(Foo f) returning: this(f) && execution(Foo.new(..)) { ... } +</PRE> + +<p> In compilers prior to 1.0.4, the following advice could pick out +join points +</p> + +<PRE> +after() returning (String s): call(void foo()) { ... } +</PRE> + +<p> This is no longer picked out. This pattern was most commonly used +in highly polymorphic contexts, such as +</p> + +<PRE> +after() returning (String s): call(* foo()) { ... } +</PRE> + +<p> If you want to capture all calls, binding null objects for those +that would otherwise have no value, you must use the +<code>Object</code> type. +</p> + +<PRE> +after() returning (Object o): call(* foo()) { ... } +</PRE> + +<p> Uses of both of these forms are highleted with compiler warnings +in the 1.0.4 compiler. +</p> + + +<hr /> + +<h2><a name="pre-1.0rc1">Porting pre-1.0rc1 code</a></h2> + +<p> Aspects can no longer be declared to implement the +<code>Serializable</code> or <code>Cloneable</code> 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. +</p> + +<hr /> + +<h2><a name="pre-1.0beta1">Porting pre-1.0beta1 code</a></h2> + +<p> The <code>static</code> modifier is no longer allowed on pointcut +declarations anywhere. Porting is simple; just remove the static +declarations when you find them. +</p> + +<p> Also, though the <code>returns</code> 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 <code>returns</code> modifier when the compiler +complains about it. +</p> + +<hr /> + +<h2><a name="pre-1.0alpha1">Porting pre-1.0alpha1 code </a></h2> + + +<p> The release of AspectJ 1.0alpha1 involved sweeping cleanups of the +language to bring it to 1.0 status. </p> + + <ul> + <li><a href="#1.0a1-pointcuts">Pointcuts</a></li> + <li><a href="#1.0a1-type-patterns">Type patterns</a></li> + <li><a href="#1.0a1-advice">Advice</a></li> + <li><a href="#1.0a1-introduction-and-static">Introduction and + static crosscutting</a></li> + <li><a href="#1.0a1-aspects">Aspects</a></li> + </ul> + +<h3><a name="1.0a1-pointcuts">Pointcuts</a></h3> + +<h4><a name="1.0a1-plural-to-singular">Removing the "s" from pointcuts</a></h4> + +<p> 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 +</p> + +<blockquote>calls executions gets sets handlers initializations +staticinitializations</blockquote> + +<p> Just take off the final "s", to make one of +</p> + +<blockquote>call execution get set handler initialization +staticinitialization</blockquote> + +<p> Often, there will be other changes you should make for each of +these pointcuts, but as for the name, just take off the "s". </p> + +<p> 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. </p> + +<PRE> +pointcut sort(Collection set): calls(void addAll(set)); +==> +pointcut sort(Collection mySet): call(void addAll(mySet)); +</PRE> + +<p> While converting to use singular nouns for the primitive +pointcuts, you may also want to remove the "s" from your user-defined +pointcuts. </p> + +<PRE> +pointcut publicCalls(): calls(public * *(..)); +==> +pointcut publicCall(): call(public * *(..)); +</PRE> + +<p> Of course, your naming conventions are your own, but throughout +these porting notes we will be making these changes in our example +ports. </p> + + +<h4><a name="1.0a1-remove-receptions">Removing the receptions pointcut</a></h4> + +<p> 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. </p> + +<p> Changing code that used the <code>receptions</code> pointcut should be +fairly straightforward, depending on whether the pointcut exposed state or +not. </p> + +<h5>Not exposing state</h5> + +<p> Receptions pointcuts that did not expose state can simply be +replaced by the new <code>call</code> and <code>target</code> pointcuts:</p> + +<PRE> +receptions(void Foo.m()) +==> +target(Foo) && call(void m()) +</PRE> + +<h5>Exposing state</h5> + +<p> 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 <code>target</code> pointcut to expose +the receiving object. </p> + +<PRE> +pointcut fooCallees(Foo f): receptions(void f.m()); +==> +pointcut fooCallee(Foo f): target(f) && call(void m()); +</PRE> + +<p> Like <a href="#1.0a1-fixing-state-access">other pointcuts</a>, +receptions pointcuts that exposed one or more arguments should be +rewritten to use the <code>args</code> pointcut: </p> + +<PRE> +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)); +</PRE> + +<h5>Constructor receptions</h5> + +<p> There are two issues with constructor receptions in +particular. </p> + +<p>Like <a href="#1.0a1-constructor-calls">constructor calls</a>, +constructor receptions pointcuts had a dynamic character, in that +<code>receptions(C.new())</code> would capture constructions of not +only C classes, but also of classes that extended C. </p> + +<p> If you want this behaviour, then you need to use the new subtypes +operator, +, on the type name in question. So, +</p> + +<PRE> +receptions(C.new()) +==> +call(C+.new()) +</PRE> + +<p>Also like <a href="#1.0a1-constructor-calls">constructor calls</a>, +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 <code>after returning</code> +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 </p> + +<PRE> +aspect Singleton { + private C theC = null; + + C around(): call(C.new(..)) { + if (c == null) theC = proceed(); + return theC; + } +} +</PRE> + +<p> but it does require some rewriting. The new object can be +accessed as the return value in after returning advice. So, </p> + +<PRE> +after(Point p) returning (): receptions(p.new(int, int)) { ... } +==> +after() returning (Point p): call(Point+.new(int, int)) { ... } +</PRE> + +<h4><a name="1.0a1-fixing-state-access">Fixing state access</a></h4> + +<p> 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 </p> + +<blockquote>args this target</blockquote> + +<p> which pick out argument values, the currently executing object, +and the target object of a method call or field operation, +respectively. </p> + +<h5>Using args</h5> + +<p> 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 <code>args</code> pointcut. +</p> + +<PRE> +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)); +</PRE> + +<PRE> +pointcut stringPassers(String s): receptions(void Foo.m(s, ..)); +==> +pointcut stringPasser(String s): args(s, ..) && call(void Foo.m(String, ..)); +</PRE> + +<h5>Rewriting calls</h5> + +<p> If a calls pointcut exposed the the receiving object, such as </p> + +<PRE> +pointcut fooCallees(Foo f): calls(void f.m()); +</PRE> + +<p> then the new version should use the <code>target</code> pointcut +to get at that object +</p> + +<PRE> +pointcut fooCallee(Foo f): target(f) && call(void Foo.m()); +</PRE> + +<p> 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 <code>target</code> +pointcut to expose the value, you should use the normal <code>after +returning</code> mechanism: +</p> + +<PRE> +after(Point p) returning (): calls(p.new(int, int)) { ... } +==> +after() returning (Point p): call(Point+.new(int, int)) { ... } +</PRE> + + +<h5>Rewriting gets and sets</h5> + +<p> Exposing the target object of a <code>gets</code> or +<code>sets</code> pointcut should be done the same way it was for +<code>calls</code> pointcuts, with the new <code>target</code> +pointcut. </p> + +<PRE> +before(Frame f): gets(Color f.color) { ... } +==> +before(Frame f): target(f) && get(Color Frame.color) { ... } +</PRE> + +<PRE> +before(Frame f): sets(Color f.color) { ... } +==> +before(Frame f): target(f) && set(Color Frame.color) { ... } +</PRE> + +<p> 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. </p> + +<PRE> +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; + ... + } +} +</PRE> + +<p> The same can be done for <code>around</code> advice. However, the +only way to port after advice that needs the old value is to convert +it to around advice. +</p> + +<PRE> +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); + ... + } +} +</PRE> + +<p> When porting <code>sets</code> 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 <code>args</code> pointcut. +All set join points are assumed to have exactly one argument, which +holds the new value. So, </p> + +<PRE> +after(Color newColor): sets(Color Frame.color)[][newColor] { ... } +==> +after(Color newColor): args(newColor) && set(Color Frame.color) { ... } +</PRE> + +<p> Also, if the field was declared private, in order to get at its +old value the aspect must be declared <code>privileged</code>. +</p> + +<h5>Rewriting handlers</h5> + +<p> The value of the exception at an exception handler join point is +now accessed through the <code>args</code> pointcut; all exception +handler join points are treated as having exactly one argument, the +exception value. So, +</p> + +<PRE> +before(NotFoundException e): handlers(e) { ... } +==> +before(NotFoundException e): args(e) && handler(NotFoundException) { ... } +</PRE> + +<h5>Rewriting within</h5> + +<p> The <code>within</code> 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 +<code>this</code> pointcut will capture what previous implementations +did: </p> + +<PRE> +pointcut usesFoo(Foo f): within(f); +==> +pointcut usesFoo(Foo f): this(f) && within(Foo); +</PRE> + +<h4><a name="1.0a1-no-subs-in-sigs">Understanding signatures</a></h4> + +<p> Now that we have <code>this</code>, <code>target</code>, and +<code>args</code> pointcuts, all of our signatures are composed of +just types, names, and wildcards; there are no more parameters. +</p> + +<p> Also, now that we have the <code>+</code> wildcard to pick out +<a href="#1.0a1-subtypes-to-plus">subtypes</a>, we can make signature +matching much more uniform.</p> + +<p> Previously, some signatures matched based on subtypes, some based +on instanceof, and some exactly. Now, we have made all signatures +match exactly. +</p> + +<p> What does this mean for your program? Well, it means that you +may have to add <code>+</code> to some of your signatures, depending +on what you meant them to match. +</p> + +<p> For example, the pointcut +</p> + +<pre> +calls(void m(Object)) +</pre> + +<p> 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 </p> + +<pre> +call(void m(Object+)) +</pre> + +<h4><a name="1.0a1-fixing-instanceof">Removing the instanceof pointcut</a></h4> + +<p> The intanceof pointcut has been split into two different +pointcuts, <code>this</code> and <code>target</code>. </p> + +<p> Typically, the instanceof pointcut would only exist in a compound +pointcut, composed (with <CODE>&&</CODE>) with another +pointcut. If the other pointcut was a <code>receptions</code> +pointcut, then <code>instanceof</code> should be converted to +<code>target</code> (and <code>receptions</code> converted to +<code>call</code>). So, </p> + +<PRE> +pointcut stateChanges(Subject s): + instanceof(s) && receptions(void Button.click()); +==> +pointcut stateChange(Subject s): + target(s) && call(void Button.click()); +</PRE> + +<p> In all other cases, <code>instanceof</code> referred to the +currently executing object, and so should be converted into +<code>this</code></p> + +<PRE> +before(Point p): instanceof(p) && executions(* makePolar(..)) { ... } +==> +before(Point p): this(p) && execution(* makePolar(..)) { ... } +</PRE> + +<PRE> +pointcut setup(Client c): instanceof(c) && calls(Remote Naming.lookup(String)); +==> +pointcut setup(Client c): this(c) && calls(Remote Naming.lookup(String)); +</PRE> + +<h4><a name="1.0a1-initializations">Rewriting the initializations pointcut</a></h4> + +<p> 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. </p> + +<p> The old behaviour can be recovered with a simple rewrite. +</p> + +<PRE> +initializations(A) +==> +initialization(A.new(..)) && !execution(A.new(..)) +</PRE> + +<h4><a name="1.0a1-constructor-calls">Understanding constructor calls</a></h4> + +<p> Previously, constructor call join points were matched by subtypes, +so <code>calls(Foo.new())</code> would match both calls to create new +<code>Foo</code> objects, and new <code>SubFoo</code> objects. The +new <code>call</code> pointcut designator matches types exactly, so if +you want the old behaviour, you should write +<code>call(Foo+.new())</code>. </p> + +<p> Similarly, constructor execution join points were matched by +subtypes. So the old <code>executions(Foo.new())</code> is now +represented by <code>execution(Foo+.new())</code>. +</p> + +<p> In both of these cases, think before using the + operator; it may +be that you didn't intend subtype matching in the first place. </p> + +<h4><a name="1.0a1-hasaspect">Removing the hasaspect pointcut</a></h4> + +<p> The <code>hasaspect</code> pointcut is no longer defined, but you +can get the same behaviour using the new <code>if</code> pointcut. +</p> + +<p> If the aspect whose presense you are checking for was defined +<code>of eachcflow</code>, <code>of eachcflowbelow</code>, or, more +unlikely, <code>of eachJVM()</code>, then the conversion is simple: +</p> + +<PRE> +hasaspect(A) +==> +if(A.hasAspect()) +</PRE> + +<p> If the aspect was defined <code>of eachobject</code>, then you +will have to expose the current object in your pointcut or advice +parameters: </p> + +<PRE> +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)) ... ; +</PRE> + +<p> If you were using the <code>hasaspect</code> pointcut to expose +the state of the aspect, then you can get the same state by using +<code>A.aspectOf()</code> in the body of the advice. For example, if +the aspect A were defined <code>of eachcflow</code>, then +</p> + +<PRE> +before(A myA): hasaspect(myA) { + myA.checkStatus(); +} +==> +before(): if(A.hasAspect()) { + A myA = A.aspectOf(); + myA.checkStatus(); +} +</PRE> + +<h4><a name="1.0a1-withinall">Removing the withinall pointcut</a></h4> + +<p> The withinall poinctut is no longer defined. You can use a +combination of within and the <a href="#1.0a1-subtypes-to-plus">new +subtypes operator</a>, +, instead. You'll save two characters and be +using a simpler and more orthogonal language. </p> + +<PRE> +withinall(Foo) +==> +within(Foo+) +</PRE> + +<h4><a name="1.0a1-user-defined-returns">Removing returns modifier from pointcuts</a></h4> + +<p>The returns keyword is no longer necessary for user-defined +pointcuts. Simply remove it when you find it. </p> + +<PRE> +pointcut publicIntCalls() returns int: calls(public int *(..)); +==> +pointcut publicIntCall(): call(public int *(..)); +</PRE> + +<h4><a name="1.0a1-static-pointcuts">Making some pointcuts static</a></h4> + +<p> In Java, only static members may be accessed by their declaring +type name, like the static method <code>Math.max()</code> can be +accessed. </p> + +<p> Pointcuts now have that property too. Pointcuts may be declared +to be static, in which case they can be accessed like +<code>MyAspect.move()</code>, or they can be left non-static, in which +case they can be overridden by a subaspect. </p> + +<p> In addition, while pointcuts can still be defined in classes, only +<code>static</code> pointcuts can be defined in classes. </p> + +<p> Porting should be straightforward; just make all your pointcuts in +classes <code>static</code>, and make any pointcut with a qualified +reference static. +</p> + +<h3><a name="1.0a1-type-patterns">Type patterns</a></h3> + +<h4><a name="1.0a1-new-wildcards">Understanding * and .. in type patterns</a></h4> + +<p> 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. </p> + +<p> In AspectJ 1.0, both of these wildcards are defined simply, and +textually: +</p> + +<ul> + <li> The * wildcard alone matches all types. </li> + + <li> The * wildcard in a pattern matches zero or more characters, + but will not match "." </li> + + <li> The .. wildcard matches any sequence of characters that begins + and ends with "." </li> +</ul> + +<p> That's it. +</p> + +<p> 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 +<code>*..*</code>, which used to match all types, you can replace it with the +much simpler *. </p> + +<PRE> +pointcut unaryVoidMethods(): call(void *(*..*)); +==> +pointcut unaryVoidMethod(): call(void *(*)); +</PRE> + +<h4><a name="1.0a1-subtypes-to-plus">Fixing subtypes in introduction</a></h4> + +<p> The new + operator is used to normalize the many places you want +to use subtypes of some types. +</p> + +<p> In introduction forms, you will need to replace +<code>subtypes(<var>TypePattern</var>)</code> type patterns with the +new subtype operator, +. In the case where you wrote +<code>subtypes(Foo)</code>, i.e., the subtypes of a single type, +simply replace this with <code>Foo+</code>. Otherwise, use the ++ operator as appropriate in <var>TypePattern</var>. </p> + +<PRE> +public void (subtypes(Target0 || Target1)).accept(Visitor v) { + v.visit(this); +} +==> +public void (Target0+ || Target1+).accept(Visitor v) { + v.visit(this); +} +</PRE> + +<h3><a name="1.0a1-advice">Advice</a></h3> + +<h4><a name="1.0a1-around-returns">Moving the return type of around</a></h4> + +<p> The returns keyword is no longer used for around advice. Instead, +the return type is declared as it is for methods. So, </p> + +<PRE> +around(Point p) returns void: setters(p) { ... } +==> +void around(Point p): setter(p) { ... } +</PRE> + +<h4><a name="1.0a1-around-throws">Adding a throws clause to around</a></h4> + +<p> Around advice must now declare the checked exceptions it throws +with a <code>throws</code> clause, much like a method. +</p> + +<PRE> +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; +} +</PRE> + +<h4><a name="1.0a1-advice-precedence">Understanding advice precedence</a></h4> + +<p> 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 +<code>before</code> and <code>around</code> advice, but was the cause +of confusion (even among the AspectJ designers, more than once) for +<code>after</code> advice, as it seemed backward. </p> + +<p> In addition, advice was ordered by kind, in that around advice +always surrounded before and after advice. +</p> + +<p> AspectJ 1.0 has changed this; precedence for <code>after</code> +advice is inverted, and advice is no longer ordered by kind. +</p> + +<p>This won't matter to you unless you write pieces of advice in the +same aspect that apply to the same join point. </p> + +<p>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 +<code>after</code> advice, then the second one has precedence. +Otherwise, the first does. </p> + +<p> This allows interesting advice interaction. In the following +advice, for example, the <code>after throwing</code> advice will catch +the exception thrown by the <code>before</code> advice </p> + +<PRE> +aspect A { + before(): call(void main(..)) { + throw new RuntimeException(); + } + after() throwing(RuntimeException e): call(void main(..)) { + System.err.println("caught you!"); + } +} +</PRE> + +<p> But reversing the order will give the <code>before</code> advice +more precedence, making its exception uncatchable by the <code>after +throwing</code> advice +</p> + +<PRE> +aspect A { + after() throwing(RuntimeException e): call(void main(..)) { + System.err.println("missed you!"); + } + before(): call(void main(..)) { + throw new RuntimeException(); + } +} +</PRE> + +<p> Advice in <em>different</em> aspects is ordered by the normal aspect +precedence rules of subtyping and the <code>dominates</code> modifier. +</p> + +<h4><a name="1.0a1-after-returning">Fixing after returning</a></h4> + +<p> 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, </p> + +<pre> +after(<var>Formals</var>) returning (): <var>Pointcut</var> { ... } +==> +after(<var>Formals</var>) returning: <var>Pointcut</var> { ... } +</pre> + +<p> The same syntax is now available for after throwing advice, in +case you do not care what <code>Throwable</code> is thrown. +</p> + +<pre> +after(<var>Formals</var>) throwing: <var>Pointcut</var> { ... } +</pre> + +<h4><a name="1.0a1-this-static-join-point">Renaming thisStaticJoinPoint</a></h4> + +<p> <code>thisStaticJoinPoint</code> has been renamed +<code>thisJoinPointStaticPart</code>, to reflect that it is now +exactly the static part of <code>thisJoinPoint</code>: It will return +the same object as <code>thisJoinPoint.getStaticPart()</code>. </p> + +<h4><a name="1.0a1-this-join-point">Converting access to thisJoinPoint</a></h4> + +<p> The <code>JoinPoint</code> object hierarchy has been folded into a +single class, <code>org.aspectj.lang.JoinPoint</code>. A common +pattern in logging, for example, was </p> + +<pre> +before() executions(* myMethod()) { + ExecutionJoinPoint jp = (ExecutionJoinPoint)thisJoinPoint; + CodeSignature jp = (CodeSignature)jp.getSignature(); + System.err.println(jp.getParameters()); + System.err.println(jp.getParameterNames()); +} +</pre> + +<p> While there is still a rich hierarchy for signatures, there is +only one <code>JoinPoint</code> type, so this can be rewritten as: +</p> + +<pre> +before() executions(* myMethod()) { + JoinPoint jp = thisJoinPoint; + CodeSignature jp = (CodeSignature)jp.getSignature(); + System.err.println(jp.getArgs()); + System.err.println(jp.getParameterNames()); +} +</pre> + +<p> Some of the method names of <code>JoinPoint</code> have been +reorganized, as well. </p> + +<h3><a name="1.0a1-introduction-and-static">Introduction and static crosscutting</a></h3> + +<h4><a name="1.0a1-plus-implements-extends">Removing +implements and +extends</a></h4> + +<p> The keywords <code>+implements</code> and <code>+extends</code> no +longer exist. Instead, AspectJ uses the <code>declare</code> +form for exactly the same functionality. </p> + +<PRE> +Point +implements Serializable; +=> +declare parents: Point implements Serializable; +</PRE> + +<PRE> +MyButton +extends ButtonAdaptor; +=> +declare parents: MyButton extends ButtonAdaptor; +</PRE> + +<h4><a name="1.0a1-now-use-soft">Using declare soft</a></h4> + +<p> Around advice advice no longer effects the static exception +checking of Java. This means that the following code previously +compiled: </p> + +<PRE> +class C { + void noExceptionDeclared() { + exceptionDeclared(); + } + void exceptionDeclared() throws IOException {} +} +aspect A { + around(): call(void C.exceptionDeclared()) { + try { proceed(); } + catch (IOException e) {} + } +} +</PRE> + +<p> even though the class C is not compilable on its own (because +noExceptionDeclared actually throws an Exception). +</p> + +<p> 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. </p> + +<pre> +declare soft: <var>ExceptionType</var>: <var>Pointcut</var>; +</pre> + +<p> 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: +</p> + +<PRE> +declare soft: IOException: + call(void C.exceptionDeclared()) && + withincode(void noExceptionDeclared()); +</PRE> + +<h3><a name="1.0a1-aspects">Aspects</a></h3> + +<p> The syntax of "of each" modifiers has changed. For <code>of +eachcflow</code> and <code>of eachcflowbelow</code>, you can simply +replace "of each" with "per". So, </p> + +<PRE> +aspect A of eachcflow(...) { ... } +==> +aspect A percflow(...) { ... } +</PRE> + +<p> If you have any aspects defined <code>of eachJVM()</code>, then +you should either remove that declaration entirely (because this is +the default behaviour), or replace the <code>of eachJVM()</code> +declaration with an <code>issingleton</code> declaration. +</p> + +<PRE> +aspect of eachJVM() { ... } +==> +aspect A { ... } +or +aspect A issingleton { ... } +</PRE> + +<p> The <code>of eachobject(<var>Pointcut</var>)</code> modifier has +been split into two different forms, <code>of +perthis(<var>Pointcut</var>)</code> and <code>of +pertarget(<var>Pointcut</var>)</code>. Which one you replace with +depends on the <var>Pointcut</var> you use. +</p> + +<p> If you use a pointcut that picked out reception join points, then +use <code>pertarget</code>, and rewrite the pointcut to pick out call +join points. So +</p> + +<PRE> +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))) { + ... +} +</PRE> + +<p> Otherwise, in most cases, use <code>perthis</code>. When you +convert, remember the meaning of each of these modifiers. +<code>perthis(<var>Pointcut</var>)</code> indicates that an instance +of the aspect should be associated with every object that is +<code>this</code> at each of the join points picked out by +<var>Pointcut</var>, while <code>pertarget(<var>Pointcut</var>)</code> +associates with every object that is the target object at such join +points. </p> + +<!-- ==================================== --> +<!-- ==================================== --> +<!-- ==================================== --> + +<hr /> + +<h2><a name="pre08b3">Porting pre-0.8beta3 code</a></h2> + +<ul> + <li><a href="#cflowTerminology">Changing cflow terminology</a></li> + <li><a href="#abstractPointcuts">Overriding abstract pointcuts</a></li> + <li><a href="#recursiveAdvice">Limiting recursive advice</a></li> +</ul> + + +<p>The following changes are only required when porting code written +prior to the 0.8beta3 release of AspectJ.</p> + +<h3><a name="cflowTerminology">Changing cflow terminology</a></h3> + +<p> Changing pre-0.8beta3 code that uses AspectJ's control-flow-based +features only requires rewriting occurrences of +<code>eachcflowroot</code>, <code>cflow</code>, and +<code>cflowtop</code>. No editing of other aspect code is +necessary.</p> + +<h4>eachcflowroot</h4> + +<p> The aspect modifier "<code>of +eachcflowroot(<var>Pointcut</var>)</code>" should now be written more +as "<code>percflow(<var>Pointcut</var>)</code>". </p> + +<h4>cflow</h4> + +<p> In previous versions of AspectJ, the pointcut +<code>cflow(<var>Pointcut</var>)</code> picked out all join points in +the cflow below the join points of <var>Pointcut</var>. That is, it +did not include the join points of <var>Pointcut</var>, only the join +points in their control flow. +</p> + +<p> As of version 0.8beta3, +<code>cflowbelow(<var>Pointcut</var>)</code> has that behavior. +<code>cflow(<var>Pointcut</var>)</code> includes the join points of +<var>Pointcut</var>. </p> + +<p> In many cases, you may not care whether the points of +<var>Pointcut</var> are included or not, and so can safely leave +<code>cflow(<var>Pointcut</var>)</code> pointcut designators alone. +However, if you use the idiom +</p> + +<pre class="codeindent"> +<var>Pointcut</var> && ! cflow(<var>Pointcut</var>) +</pre> + +<p> to capture the non-recursive entries to a particular pointcut, you +will definitely want to rewrite that as +</p> + +<pre class="codeindent"> +<var>Pointcut</var> && ! cflowbelow(<var>Pointcut</var>) +</pre> + +<h4>cflowtop</h4> + +<p> The primitive pointcut designator +<code>cflowtop(<var>Pointcut</var>)</code> has been removed from the +language, as it is expressible with <code>cflow</code> or +<code>cflowbelow</code>. All uses of +<code>cflowtop(<var>Pointcut</var>)</code> can be rewritten as: +</p> + +<pre class="codeindent"> +cflowbelow(<var>Pointcut</var> && ! cflowbelow(<var>Pointcut</var>)) +</pre> + +<p> Though in most cases the following is sufficient +</p> + +<pre class="codeindent"> +cflow(<var>Pointcut</var> && ! cflowbelow(<var>Pointcut</var>)) +</pre> + +<h3><a name="abstractPointcuts">Overriding abstract pointcuts</a></h3> + +<p> 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:</p> + +<pre class="codeindent"> +abstract aspect A { + abstract pointcut pc(); +} + +aspect B {} +</pre> + +<p> will no longer compile. +</p> + +<p> Adding the new empty pointcut designator +</p> + +<pre class="codeindent"> +pointcut <var>Id</var>(); +</pre> + +<p> in the declaration of the concrete aspect fixes this problem. +</p> + +<pre class="codeindent"> +abstract aspect A { + abstract pointcut pc(); +} + +aspect B { + pointcut pc(); +} +</pre> + +<h3><a name="recursiveAdvice">Limiting recursive advice</a></h3> + +<p> Previously, the compiler silently refrained from applying a piece +of advice to join points within its own advice body. So, for example, +in </p> + +<pre class="codeindent"> +class C { + static int i; +} + +aspect A { + before(): gets(int C.i) { + System.err.println("C.i was " + C.i) + } +} +</pre> + +<p> The advice would trace all references of the static field +<code>C.i</code> except those in the body of the before. </p> + +<p> The compiler has now removed this special case, and so running the +above example will now cause a <code>StackOverflowException</code> to +be thrown. </p> + +<p> 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 <em>all</em> references of <code>C.i</code>, just those +outside the aspect. +</p> + +<pre class="codeindent"> +class C { + static int i; +} + +aspect A { + before(): get(int C.i) && ! within(A) { + System.err.println("C.i was " + C.i) + } +} +</pre> + +<p> 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): +</p> + +<pre class="codeindent"> +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 + } +} +</pre> + + +<!-- ============================== --> + +<hr /> +<h2><a name="pre08b1">Porting pre-0.8beta1 code</a></h2> + +<ul> + <li><a href="#introSyntax">Rewriting introductions</a></li> + <li><a href="#staticAdvice">Removing static advice</a></li> + <li><a href="#aspect-aspect">Fixing aspect-aspect inheritance</a></li> + <li><a href="#usingPrivateIntroduction">Using private introduction</a></li> +</ul> + +<p>The following changes are only required when porting code written +prior to the 0.8beta1 release of AspectJ.</p> + +<h3><a name="introSyntax">Rewriting introductions</a></h3> + +<h4>Syntax</h4> + +<p> The syntax of introduction has changed. Porting most programs +should require some simple editing. Anywhere you have an introduction +block</p> + +<pre class="codeindent"> +introduction <var>GTN</var> { + ... +} +</pre> + +<p> simply move the <var>GTN</var> down into the introduction +declarations and remove the block.</p> + +<p>For method introduction, place the <var>GTN</var> in front of the +method name, For field introduction, place the <var>GTN</var> in front +of the field name, and for constructor introduction, place the +<var>GTN</var> in front of the <code>new</code> identifier. </p> + +<pre class="codeindent"> +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; } +</pre> + +<p> For implements and extends introduction, move the <var>GTN</var> +in front of the new identifiers <code>implements</code> or +<code>extends</code>, and place that in a <code>declare parents</code> +form. +</p> + +<pre class="codeindent"> +introduction Foo { + implements Comparable; + extends Goo; +} + +==> + +declare parents: Foo implements Comparable; +declare parents: Foo extends Goo; +</pre> + +<p> In all cases, if the <var>GTN</var> is just a type name, it can be +moved down on its own. However, if the <var>GTN</var> uses any of +<CODE>&&</CODE>, <code>||</code>, and <code>!</code>, it must +be parenthesized. </p> + +<pre class="codeindent"> +introduction subtypes(Foo) && !Goo { + int x; +} + +==> + +int (Foo+ && !Goo).x; +</pre> + + +<h4>Access</h4> + +<p>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 <code>privileged</code> modifier on +the aspect that contains the introduction.</p> + +<pre class="codeindent"> +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; } +} +</pre> + + +<p> 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.</p> + +<pre class="codeindent"> +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; } +} +</pre> + +<p> 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 <code>private +void writeObject(..)</code> or a <code>private void +readObject(..)</code> method to interact with Java's serialization +API, you will need to come up with an alternative design. Using some +combination of <code>Externalizable</code>, +<code>writeReplace(..)</code> and/or <code>readResolve(..)</code> +methods should allow you to port your code. If you find this isn't +the case, we'd like to hear about it. + + +<p> 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. <p> + + +<h3><a name="staticAdvice">Removing static advice</a></h3> + +<p> 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. +</p> + +<p> 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. </p> + +<pre class="codeindent"> +aspect Tracing { + static before(): executions(* *(..)) { + System.out.println("Got Here! " + thisJoinPoint); + } +} + +==> + +aspect Tracing { + before(): execution(* *(..)) { + System.out.println("Got Here! " + thisJoinPoint); + } +} +</pre> + +<p> 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. </p> + +<pre class="codeindent"> +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 +} +</pre> + +<h3><a name="aspect-aspect">Fixing aspect-aspect inheritance</a></h3> + +<p> 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 <code>abstract</code> modifier to a +super-aspect that was already implicitly abstract.</p> + +<pre class="codeindent"> +aspect BaseTracing { + abstract pointcut traced(); + before(): traced() { + System.out.println("Got Here! " + thisJoinPoint); + } +} + +==> + +// make this abstract aspect explicitly abstract +abstract aspect BaseTracing { + ... +} +</pre> + + +<p> This change has also affected the <code>getAspect</code> static +method. Now, <code>getAspect</code> is only defined on non-abstract +aspects. Previously, you could call <code>getAspect</code> on an +abstract superaspect and (sometimes) get an instance of a subaspect +back. </p> + +<p>This pattern was used in the Spacewar example in the AspectJ +distribution. We had the class hierarchy </p> + +<pre> + SpaceObject (abstract) + |- Ship + |- Bullet + |- EnergyPellet +</pre> + +<p> And the aspect hierarchy +</p> + +<pre> + SpaceObjectDA (abstract) + |- ShipDA of eachobject(instanceof(Ship)) + |- BulletDA of eachobject(instanceof(Ship)) + |- EnergyPacketDA of eachobject(instanceof(Ship)) +</pre> + +<p> And we would call <code>SpaceObjectDA.getAspect(SpaceObject)</code> to access +the aspect associated with a ship, bullet, or energy pellet. This +pattern depended on the <code>SpaceObjectDA</code> aspect hierarchy +exactly mirroring the <code>SpaceObject</code> hierarchy, and being +maintained that way. </p> + +<p> A better way to implement this kind of design aspect is to use +private introduction, a new feature of AspectJ. +</p> + +<h3><a name="usingPrivateIntroduction">Using private introduction</a></h3> + +<p> 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 <code>of eachobject(instanceof(...))</code>. A prime +example of this was the <code>BoundPoint</code> aspect of the bean +example: which needed to associate each point with a +<code>PropertyChangeSupport</code> object. </p> + +<pre class="codeindent"> +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 + } +} +</pre> + +<p> 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 <code>Point</code> +object, store the <code>PropertyChagneSupport</code> object in the +<code>Point</code> objects themselves. +</p> + +<pre class="codeindent"> +aspect BoundPoint { + private PropertyChangeSupport Point.support = new PropertyChangeSupport(this); + + void around(Point p): setters(p) { + // code that uses p.support + } +} +</pre> + +<p> Just as in the past, the PropertyChangeSupport object is not +accessable to anyone but the aspect, but now less mechanism is needed. +</p> + +<p> There are times when changing aspects that are defined <code>of +eachobject(instanceof(...))</code> may not be reasonable. If the +aspect instance is stored or passed to other methods, then having a +real <code>of eachobject(instanceof(...))</code>, now written +<code>perthis(this(...))</code>, association may capture the +crosscutting concern best. </p> + +<!-- ============================== --> + +<hr /> +<h2><a name="pre07b11">Porting pre-0.7beta11 code</a></h2> + +<ul> + <li><a href="#twoArgumentCalls">Removing two-argument calls</a></li> + <li><a href="#adviceInClasses">Removing advice from Class declarations</a></li> +</ul> + +<p>The following changes are only required when porting code written +prior to the 0.7beta11 release of AspectJ.</p> + +<h3><a name="twoArgumentCalls">Removing two-argument calls</a></h3> + +<p> In AspectJ 0.7beta11, the two-argument <code>calls</code> +primitive pointcut designator was deprecated. Removing these +designators will require different cases depending on what the +original pointcut did. </p> + +<h4>Calls to static methods</h4> + +<p> For pointcuts denoting calls to particular static methods, such as +</p> + +<blockquote><pre> +calls(String, static String valueOf(int)) // deprecated +</pre></blockquote> + +<p> 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 <code>String valueOf(int)</code>, catch +calls to that exact method defined in the String class. </p> + +<blockquote><pre> +call(static String String.valueOf(int)) +</pre></blockquote> + +<p> Pointcuts denoting calls to classes of static methods can also be +rewritten with these rules. For example, </p> + +<blockquote><pre> +calls(my.package.*, static * get*(..)) // deprecated +</pre></blockquote> + +<p> should now be written </p> + +<blockquote><pre> +call(static * my.package.*.get*(..)) +</pre></blockquote> + +<h4>Calls to non-static methods</h4> + +<p> 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, +</p> + +<blockquote><pre> +calls(Thread, int getPriority()) // deprecated +</pre></blockquote> + +<p> which denotes all calls to nullary int methods named <code>getPriority</code> +when the called object is an instance of the <code>Thread</code> type, +can almost always be rewritten </p> + +<blockquote><pre> +call(int Thread.getPriority()) +</pre></blockquote> + +<p> which denotes all calls to the nullary int <code>Thread.getPriority()</code> +method. +</p> + +<p> 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 <code>Thread</code> +when its <code>int getPriority()</code> method is called. If you want +to capture calls to the <code>int Thread.getPriority()</code> method, +regardless of how the called object is statically typed, you shoud use +the different translation: </p> + +<blockquote><PRE> +call(int getPriority()) && target(Thread) +</PRE></blockquote> + +<p> This will capture all call join points of methods with signature +<code>int Thread.getPriority()</code>. </p> + +<p> It will also denote any join points if the Thread type does not +define (possibly abstractly) some <code>int getPriority()</code> +method, though. </p> + + +<h3><a name="adviceInClasses">Removing advice from Class declarations</a></h3> + +<p> 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 </p> + +<blockquote><pre> +class C { + static before(): executions(C.new()) { ... } // deprecated +} +</pre></blockquote> + +<p> write </p> + +<blockquote><pre> +class C { + static aspect ConstructionProtocol { + static before(): executions(C.new()) { ... } + } +} +</pre></blockquote> + +<p> 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. </p> + +<blockquote><pre> +class C { ... } + +aspect ConstructionProtocol { + static before(): execution(C.new()) { ... } +} +</pre></blockquote> + +<p> 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. </p> + +<!-- ============================== --> +<hr /> +<h2><a name="pre07b10">Porting pre-0.7beta10 code</a></h2> + +<ul> + <li><a href="#joinPoints">Changing access to thisJoinPoint</a></li> +</ul> + +<p>The following changes are only required when porting code written +prior to the 0.7beta10 release of AspectJ.</p> + + +<h3><a name="joinPoints">Changing access to thisJoinPoint</a></h3> + +<p> In AspectJ 0.7beta10, access to the reflective object +<code>thisJoinPoint</code> substantially changed. The two parts of +this change were the elimination of the <code>runNext()</code> static +method, and the use of an interface hierarchy represent the join point +object. </p> + +<h4><a name="proceed"><code>thisJoinPoint.runNext()</code> to +<code>proceed()</code></a></h4> + +<p> The elimination of the <code>runNext()</code> static method +requires almost no porting work. An automatic replacement of the +string +</p> + +<blockquote><code>thisJoinPoint.runNext</code></blockquote> + +<p> with the string +</p> + +<blockquote><code>proceed</code></blockquote> + +<p> will do the job. However, if any around advice used the +identifier "<code>proceed</code>" 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 "<code>this</code>", +depending on whether the field is static or not). </p> + +<h4><a name="thisJoinPoint">Using <code>thisJoinPoint</code></a></h4> + +<p> While access to reflective information through +<code>thisJoinPoint</code> 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. </p> + +<!-- --> + +<p> Many existing uses of the fields on join points can be re-written +to use one of: +</p> + +<ul> + <li><code>thisJoinPoint.toString()</code></li> + <li><code>thisJoinPoint.toShortString()</code></li> + <li><code>thisJoinPoint.toLongString()</code></li> + <li><code>thisJoinPoint.getSignature().toString()</code></li> + <li><code>thisJoinPoint.getSignature().toShortString()</code></li> + <li><code>thisJoinPoint.getSignature().toLongString()</code></li> +</ul> + +<p>For example: +</p> + +<blockquote><pre> +System.out.println(thisJoinPoint.className + "." + + thisJoinPoint.methodName) +</pre></blockquote> + +<p> can be replaced with +</p> + +<blockquote><code>System.out.println(thisJoinPoint)</code></blockquote> + +<p> or +</p> + +<blockquote><code>System.out.println(thisJoinPoint.getSignature().toShortString())</code></blockquote> + +<p> with comparable behavior. +</p> + +<!-- --> + +<p> Accesses to the parameters field of join points should be changed +as follows. A field access like: +</p> + + +<blockquote><code>thisJoinPoint.parameters</code></blockquote> + +<p> must be changed to: +</p> +<ul> + <li><code>thisJoinPoint.getArgs()</code></li> +</ul> + +<!-- --> + +<p> 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: +</p> + +<ul> + <li><code>thisJoinPoint.className</code></li> + <li><code>thisJoinPoint.methodName</code></li> +</ul> + +<p> must be changed to: +</p> + +<ul> + <li><code>thisJoinPoint.getSignature().getDeclaringType().getName()</code></li> + <li><code>thisJoinPoint.getSignature().getName()</code></li> +</ul> + +<!-- --> + +<p> 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: +</p> + +<ul> + <li><code>thisJoinPoint.parameterNames</code></li> + <li><code>thisJoinPoint.parameterTypes</code></li> +</ul> + +<p> must be changed to: +</p> + +<ul> + <li><code>((CodeSignature)thisJoinPoint.getSignature()).getParameterNames()</code></li> + <li><code>((CodeSignature)thisJoinPoint.getSignature()).getParameterTypes()</code></li> +</ul> + +</body> +</html> diff --git a/docs/dist/doc/quick.doc b/docs/dist/doc/quick.doc Binary files differnew file mode 100644 index 000000000..89857a0b8 --- /dev/null +++ b/docs/dist/doc/quick.doc 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<property> 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 @@ + +<!-- ========================================================================= --> +<!-- Copyright (c) 1999-2001 Xerox Corporation, --> +<!-- 2002 Palo Alto Research Center, Incorporated (PARC). --> +<!-- All rights reserved. --> +<!-- This program and the accompanying materials are made available --> +<!-- under the terms of the Common Public License v1.0 --> +<!-- which accompanies this distribution and is available at --> +<!-- http://www.eclipse.org/legal/cpl-v10.html --> +<!-- --> +<!-- Contributors: --> +<!-- Xerox/PARC initial implementation --> +<!-- ========================================================================= --> + +<project name="aspectj-examples" default="spacewar" basedir="."> + + <target name="info" > + <echo> + 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 + + </echo> + </target> + + <!-- ============================================================= --> + <!-- setup and cleanup targets --> + <!-- ============================================================= --> + + <target name="clean" depends="init" + description="clean and create classes dir"> + <delete quiet="on" dir="${classes.dir}"/> + <delete quiet="on"> + <fileset dir="${example.dir}" includes="**/*.ajesym"/> + </delete> + <mkdir dir="${classes.dir}"/> + </target> + + <target name="init" depends="init.variables,init.taskdefs"/> + + <target name="init.variables" + description="init variables"> + + <!-- required directories - run from examples or predefine --> + <property name="example.dir" + location="${basedir}"/> + <property name="aspectj.lib.dir" + location="${basedir}/../lib"/> + + <!-- required libraries - install or predefine --> + <property name="aspectj-ant.jar" + location="${aspectj.lib.dir}/aspectj-ant.jar"/> + <property name="aspectjrt.jar" + location="${aspectj.lib.dir}/aspectjrt.jar"/> + <property name="aspectjtools.jar" + location="${aspectj.lib.dir}/aspectjtools.jar"/> + + <!-- created directories (fyi workingdir unused) --> + <property name="classes.dir" + location="${example.dir}/classes"/> + <property name="working.dir" + location="${example.dir}/ajworkingdir"/> + + <!-- checking required libraries --> + <available file="${aspectjtools.jar}" + property="aspectjtools.jar.available"/> + <available file="${aspectjrt.jar}" + property="aspectjrt.jar.available"/> + <available file="${aspectj-ant.jar}" + property="aspectj-ant.jar.available"/> + + <property name="example.packages" + value="bean, coordination, evolution, figures, figures.gui, + helloworld, icount, icount.lib, introduction, + observer, shadow, shadow.version1, shadow.version2, + spacewar, telecom, telecom.version1, timeserver, tjp, + tracing, tracing.lib tracing.version1, tracing.version2, + tracing.version3"/> + </target> + + <target name="init.taskdefs" depends="init.variables, + aspectjtools.jar.available, + aspectjrt.jar.available, + aspectj-ant.jar.available"> + + <taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"> + <classpath> + <pathelement path="${aspectjtools.jar}"/> + <pathelement path="${aspectj-ant.jar}"/> + </classpath> + </taskdef> + </target> + + <!-- targets to fail unless required libraries available --> + + <target name="aspectjrt.jar.available" depends="init.variables" + unless="aspectjrt.jar.available" > + <fail message="expecting aspectjrt.jar at ${aspectjrt.jar}"/> + </target> + + <target name="aspectjtools.jar.available" depends="init.variables" + unless="aspectjtools.jar.available" > + <fail message="expecting aspectjtools.jar at ${aspectjtools.jar}"/> + </target> + + <target name="aspectj-ant.jar.available" depends="init.variables" + unless="aspectj-ant.jar.available" > + <fail message="expecting aspectj-ant.jar at ${aspectj-ant.jar}"/> + </target> + + <!-- ============================================================= --> + <!-- these targets compile and run any example --> + <!-- ============================================================= --> + <target name="Ajx" depends="init" + description="compile {list} and run {class} of example"> + <echo message="##### Ajx list=${list} class=${class}" /> + <antcall target="clean" /> + + <ajc destdir="${classes.dir}" emacssym="on" argfile="${list}" + classpath="${aspectjrt.jar}"/> + + <antcall target="Ajx-run" > + <param name="class" value="${class}"/> + </antcall> + + </target> + + <target name="Ajx-run" + description="run {class} unless {norun} is set" + unless="norun" > + <echo message="##### Ajx-run list=${list} class=${class}" /> + <java classname="${class}" fork="yes"> + <classpath> + <pathelement path="${classes.dir}"/> + <pathelement path="${aspectjrt.jar}"/> + </classpath> + </java> + </target> + + <!-- ============================================================= --> + <!-- example targets --> + <!-- ============================================================= --> + <target name="all" + description="build and run all examples" + depends="bean,intro,intro-clone,intro-compare,intro-hash, + observer,spacewar,spacewar-demo,telecom, + telecom-timing,tracing-none,tracing-1, + tracing-2,tracing-3,tjp"/> + + <target name="nonGui" + description="build and run non-GUI examples" + depends="bean,intro,intro-clone,intro-compare,intro-hash, + telecom,telecom-timing,tracing-none,tracing-1, + tracing-2,tracing-3,tjp"/> + + <target name="bean"> + <antcall target="Ajx"> + <param name="list" value="bean/files.lst"/> + <param name="class" value="bean.Demo"/> + </antcall> + </target> + + <target name="intro"> + <antcall target="Ajx"> + <param name="list" value="introduction/files.lst"/> + <param name="class" value="introduction.Point"/> + </antcall> + </target> + + <target name="intro-clone"> + <antcall target="Ajx"> + <param name="list" value="introduction/files.lst"/> + <param name="class" value="introduction.CloneablePoint"/> + </antcall> + </target> + + <target name="intro-compare"> + <antcall target="Ajx"> + <param name="list" value="introduction/files.lst"/> + <param name="class" value="introduction.ComparablePoint"/> + </antcall> + </target> + + <target name="intro-hash"> + <antcall target="Ajx"> + <param name="list" value="introduction/files.lst"/> + <param name="class" value="introduction.HashablePoint"/> + </antcall> + </target> + + <target name="observer"> + <antcall target="Ajx"> + <param name="list" value="observer/files.lst"/> + <param name="class" value="observer.Demo"/> + </antcall> + </target> + + <target name="spacewar"> + <antcall target="Ajx"> + <param name="list" value="spacewar/debug.lst"/> + <param name="class" value="spacewar.Game"/> + </antcall> + </target> + + <target name="spacewar-demo"> + <antcall target="Ajx"> + <param name="list" value="spacewar/demo.lst"/> + <param name="class" value="spaceware.Game"/> + </antcall> + </target> + + <target name="telecom"> + <antcall target="Ajx"> + <param name="list" value="telecom/basic.lst"/> + <param name="class" value="telecom.BasicSimulation"/> + </antcall> + </target> + + <target name="telecom-billing"> + <antcall target="Ajx"> + <param name="list" value="telecom/billing.lst"/> + <param name="class" value="telecom.BillingSimulation"/> + </antcall> + </target> + + <target name="telecom-timing"> + <antcall target="Ajx"> + <param name="list" value="telecom/timing.lst"/> + <param name="class" value="telecom.TimingSimulation"/> + </antcall> + </target> + + <target name="tjp"> + <antcall target="Ajx"> + <param name="list" value="tjp/files.lst"/> + <param name="class" value="tjp.Demo"/> + </antcall> + </target> + + <target name="tracing-none"> + <antcall target="Ajx"> + <param name="list" value="tracing/notrace.lst"/> + <param name="class" value="tracing.ExampleMain"/> + </antcall> + </target> + + <target name="tracing-1"> + <antcall target="Ajx"> + <param name="list" value="tracing/tracev1.lst"/> + <param name="class" value="tracing.ExampleMain"/> + </antcall> + </target> + + <target name="tracing-2"> + <antcall target="Ajx"> + <param name="list" value="tracing/tracev2.lst"/> + <param name="class" value="tracing.ExampleMain"/> + </antcall> + </target> + + <target name="tracing-3"> + <antcall target="Ajx"> + <param name="list" value="tracing/tracev3.lst"/> + <param name="class" value="tracing.ExampleMain"/> + </antcall> + </target> + +</project> 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. + * <P> + * 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. + * <P> + * 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. + * <P> + * 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. + * <P> + * 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 @@ +<html> + +<head> +<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> +<meta name="GENERATOR" content="Microsoft FrontPage 4.0"> +<meta name="ProgId" content="FrontPage.Editor.Document"> +<title>Space War</title> +</head> + +<body BGCOLOR="white"> + +<P>© Copyright 1997-2001 Xerox Corporation. All rights +reserved.</P> + +<P><B>Last updated</B>: January 10, 2001</P> + +<p> </p> + + + +<h2><a name="5">Exploring the Spacewar Example</a></h2> + +<P>The code in this directory is an implementation of the +classic video game Spacewar.</P> + +<P>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.</P> + +<P>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 <a href="../doc/primer/default.html">Primer</a> +section Getting Started.</P> + +<h3><a name="5.1">Compiling Spacewar</a></h3> + +<ul> +<li> Change to the <code>examples</code> directory. </li> + +<li> Type <code><strong>ajc -argfile spacewar/demo.lst</strong></code> to compile the + system.</li> +</ul> + +<h3><a name="5.2">Running Spacewar</a></h3> + +<ul> +<li> In the examples directory, type <code><strong>java spacewar.Game</strong></code></li> +</ul> + +<p>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.</p> + +<p>You can quit the game with ctl-Q.</p> + +<h3><a name="5.3">Exploring the Code</a></h3> + +<p>There is one other built-in configurations for the Spacewar game. +Try it by typing <code><strong>ajc @spacewar\debug.lst</strong></code>. This +compiles in an elaborate debugging aspect for the game. + +</p> + +<p> 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. +</p> + + +</body> + +</html> 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: + * <ul> + * <li>MAX_ENERGY</li> + * <li>BULLET_ENERGY</li> + * <li>ACCELERATION_ENERGY_FACTOR</li> + * <li>energy</li> + * </ul> + * The damage related values are: + * <ul> + * <li>MAX_DAMAGE</li> + * <li>BULLET_DAMAGE</li> + * <li>COLLISION_DAMAGE_FACTOR</li> + * <li>damage</li> + * </ul> + * 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<N>--
+
+ ajc @.../examples/tracing/tracev<N>.lst
+
+ java tracing.version<N>.TraceMyClasses
+
+where <N> 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.<P> + * The class is thread-safe. Different threads may use different output streams + * by simply calling the method initStream(myStream).<P> + * This class should be extended. + * It defines 3 abstract crosscuts for injecting the tracing functionality + * into any constructors and methods of any application classes.<P> + * + * One example of using this class might be + * <PRE> + * 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 * *(..)) + * } + * </PRE> + * (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); + } +} + |