<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html> <head>
-<title>AspectJ Tutorial Exercises</title>
+<title>AspectJ Exercises</title>
</head>
<body bgcolor="white">
-<h1>AspectJ Tutorial Exercises</h1>
+<h1>AspectJ Exercises</h1>
<h3>Organization</h3>
-<p> The exercises work with a figure editor together with JUnit test
-cases. They progress, as most users do in their adoption of AspectJ,
-from non-functional, development-only aspects to aspects which augment
-a deployed program with crosscutting features. </p>
-
-<p> Before the tutorial we will make available a package that includes
-the tests, the base code, JUnit, and a distribution of AspectJ. All
-it needs is information about where Java lives (so set your JAVA_HOME
-environment variable). It assumes that you unzip it in c:\ (on
-Windows) or in your home directory (on Linux): If you put it somewhere
-else, edit setpaths or setpaths.bat, as appropriate. Once all this is
-done, run <code>setpaths.bat</code> or <code>source setpaths</code> to
-export some other needed environment variables. </p>
+<p> This tutorial consists of the attendees solving AspectJ
+programming tasks (with unit tests) in pairs or triples and discussing
+the answers with the group and with the tutorial presenters. The
+exercises work with a figure editor together with JUnit test cases.
+They progress, as most users do in their adoption of AspectJ, from
+non-functional, development-only aspects to aspects which augment a
+deployed program with crosscutting features. </p>
+
+<p> These notes consist of four sections of exercises, a quick
+reference to AspectJ syntax, and a UML diagram of a figure editor
+program. While you should feel free to have a quick look through
+these notes before the tutorial, please do not try to seriously read
+or do the exercises; you'll learn a lot more by working through it in
+groups. </p>
+
+<h3>Command-line usage</h3>
+
+<p> At the beginning of the tutorial we will make available a binary
+package that includes the tests, the base code, JUnit, and a
+distribution of AspectJ. All it needs is information about where Java
+lives (so set your JAVA_HOME environment variable). It assumes that
+you unzip it in c:\ (on Windows) or in your home directory (on Linux):
+If you put it somewhere else, edit setpaths or setpaths.bat, as
+appropriate. Once all this is done, run <code>setpaths.bat</code> or
+<code>source setpaths</code> to export some other needed environment
+variables. </p>
<p> All the files in the program are listed in base.lst, including
test cases and an empty answer aspect,
IDE or with </p>
<blockquote><PRE>
-$ ajc -Xlint -argfile base.lst
+$ ajc -argfile base.lst
</PRE></blockquote>
<p> Before you move onto another exercise, though, make sure to copy
<blockquote><PRE>
> copy answers/Answer.java answers/2a.java (Windows)
-$ cp answers/Answer.java answers/2a.java (Linux)
+$ cp answers/Answer.java answers/2a.java (Unix)
</PRE></blockquote>
-<p> If you want to put your answer in a different file, say,
-<code>answers/Answer2a.java</code>, you can compile with </p>
-
-<blockquote><PRE>
-$ ajc -Xlint -argfile base.lst answers/Answer2a.java
-</PRE> </blockquote>
-
-<p> In any case, after building the system, you should invoke Java on
-the compiled test class. On the command-line, this this would be </p>
+<p> After building the system, you should invoke Java on the compiled
+test class. On the command-line, this this would be </p>
<blockquote><PRE>
$ java tests.Test2a
periodically. Looking at the JUnit tests for each exercise may also
be helpful. </p>
-<p> Again, ae will be looking at some solutions and having discussion,
+<p> Again, we will be looking at some solutions and having discussion,
which is much more difficult without incremental solutions. So when
you go from one exercise to the next, make sure to save your work in a
file and go on to work in a different file, even if you plan to
set up the run button to run a test through the Options menu, but
we've found this is fairly cumbersome. </p>
-
-<hr>
<!-- ============================== -->
<br style="page-break-after: always" />
<h2>1. Static Invariants</h2>
+<p> The easiest way to get started with AspectJ is to use it to
+enforce static invariants.
+</p>
+
<h3>a. Catch old tracing</h3>
<p> <strong>Sample Exercise</strong>: The main point of this exercise
to use <code>System.out.println()</code>, so that is what we typically
use for one-off debugging traces. It's a common mistake to leave
these in your system longer than is necessary. Type in the aspect
-below to forces an error at compile time if this mistake is made.
+below to force an error at compile time if this mistake is made.
</p>
<p> When you use this on the given system, you'll find one incorrect
of the <code>out</code> field is illegal. This will also catch those
users who bind System.out to a static field to save typing. </p>
+<br style="page-break-after: always" />
<h3>b. Mandate setters</h3>
the assignment is outside the <em>text</em> of the setter.
<p> Make sure your program still passes the JUnit test
-<code>tests.Test</code> before continuing, and that you see all of the
-following warning messages. Make sure you get 11 warnings from this.
-Wait to fix them until the next exercise. </p>
+<code>tests.Test</code> before continuing. Make sure you get 11
+warnings from this. Wait to fix them until the next exercise. </p>
<h3>c. Refine setters mandate</h3>
<p> Look at some of the warnings from the previous exercise. Notice
that a lot of them are from within constructors. Actually, the common
coding convention is that no private field should be set outside of
-setter methods <em>or constructors</em>. Modify your answer (in a new
-file) to signal an actual error at compile time (rather than just a
-warning) when such an illegal assignment expression exists. </p>
+setter methods <em>or constructors</em>. Modify your answer to signal
+an actual error at compile time (rather than just a warning) when such
+an illegal assignment expression exists. </p>
<p>You'll want to add another <code>withincode</code> primitive
pointcut to deal with the constructors.
the convention is violated twice in the figures package. You should see
the following two errors:</p>
-<pre>
-.\figures\Point.java:28:9: bad field set
- _x += dx;
- ^
-.\figures\Point.java:29:9: bad field set
- _y += dy;
- ^
+<PRE>
+.\figures\Point.java:37 bad field set
+.\figures\Point.java:38 bad field set
+
2 errors
-</pre>
+</PRE>
<p>Rewrite these two occurrences so as not to violate
the convention. Make sure your program still passes the JUnit test
<code>tests.Test</code> before continuing. </p>
-<h3>d. Congratulatoins</h3>
+<h3>d. Congratulations</h3>
<p> You've taken your first steps. At this point, check the people to
your left and right. If they're stuck somewhere, see if you can help
them. </p>
-<hr />
-
<!-- ============================== -->
<br style="page-break-after: always" />
<h2>2. Dynamic invariants</h2>
+<p> The next step in AspectJ adoption is often to augment a test suite
+by including additional dynamic tests.
+</p>
+
+<p> Tutorial attendees typically progress at different speeds through
+these questions. Throughout this tutorial, if you finish early, see
+what the people around you are doing and if they need help. Feel free
+to help them out of naked self-interest; we promise you'll learn a lot
+about AspectJ by explaining it. </p>
+
<h3>a. Check a simple precondition</h3>
<p> <strong>Sample Exercise</strong>: We've provided the answer to
</p>
<blockquote><PRE>
-$ ajc -Xlint -argfile base.lst answers/Answer.java
+$ ajc -argfile base.lst answers/Answer.java
$ java tests.Test2a
.......
<p> <strong>Task:</strong> Pass <code>tests.Test2b</code>. </p>
+<p> <strong>Tools: </strong> <code>call</code>.
+</p>
+
<p> <code>Group</code> is a <code>FigureElement</code> class that
encapsulates groups of other figure elements. As such, only actual
figure element objects should be added to <code>Group</code> objects.
<h3>d. Assure input</h3>
-<p> <strong>Task: </strong> Pass <code>tests.Test2g</code>.
+<p> <strong>Task: </strong> Pass <code>tests.Test2d</code>.
</p>
<p> <strong>Tools: </strong> around advice
</p>
<p> Instead of throwing an exception when one of <code>Point</code>'s
-<code>int</code> fields are set to an out-of-bounds value, write an
-aspect to trim the value into an in-bounds one. You'll want to use
-<code>around</code> advice that exposes the new value of the field
-assignment with an <code>args</code> pointcut, and
-<code>proceed</code> with the trimmed value. </p>
+<code>int</code> fields are set to a negative value, write an aspect
+to trim the value to zero. You'll want to use <code>around</code>
+advice that exposes the new value of the field assignment with an
+<code>args</code> pointcut, and <code>proceed</code> with the trimmed
+value. </p>
+
+<p> This is going to look something like
+</p>
+
+<pre>
+aspect A {
+ void around(int val): <var><Pointcut></var> {
+ <var><Do something with val></var>
+ proceed(val);
+ }
+}
+</pre>
+<br style="page-break-after: always" />
<h3>e. Check a postcondition</h3>
<p> <strong>Task: </strong> Pass <code>tests.Test2e</code>
<p> A postcondition of a <code>Point</code>'s <code>move</code>
operation is that the <code>Point</code>'s coordinates should change.
-If a call to move move didn't actually move a point by the desired
+If a call to move didn't actually move a point by the desired
offset, then the point is in an illegal state and so an
<code>IllegalStateException</code> should be thrown.
</p>
figure itself. Write an aspect to check for this postcondition --
throw an <code>IllegalStateException</code> if it is violated. </p>
-<h3>Help Yourself by Helping Others</h3>
-
-<p> At this point, check the people to your left and right. If
-they're stuck somewhere, see if you can help them. </p>
-
-<hr />
-
<!-- ============================== -->
<br style="page-break-after: always" />
<h2>3. Tracing</h2>
-<p> The crosscutting feature you will be adding in part (4) will be
-support for caching the bound objects of <code>Group</code> figure
-elements, which may be costly to compute. On the way to that, though,
-it's useful to explore the system with some tracing aspects. </p>
+<p> Tracing is one of the classic AspectJ applications, and is often
+the first where AspectJ is used on deployed code.
+</p>
<h3>a. Simple logging</h3>
<code>Log</code> (with an import from <code>support.Log</code>)
and call <code>Log.log(String)</code></p>
-<h3>b. Simple logging</h3>
+<h3>b. Exposing a value</h3>
<p> <strong>Task:</strong> Pass <code>tests.Test3b</code>.</p>
<p> <strong>Task:</strong> Pass <code>tests.Test3c</code>.</p>
-<p> <strong>Tools:</strong>
+<p> <strong>Tools:</strong> <code>args</code>.
</p>
-<p> Write an aspect to log whenever a <code>Point</code> is added to
-a group (including initially). To do this, use the utility class
-<code>Log</code> (with an import from <code>support.Log</code>) and
-call </p>
-
-<blockquote><PRE>
-Log.log("adding Point")
-</PRE></blockquote>
-
-<p> This will write the string "adding Point", followed by a semicolon
-terminator, to the Log. For example, with your aspect enabled, </p>
-
-<blockquote><PRE>
-Point p1 = new Point(10, 100);
-Point p2 = new Point(10, 100);
-Group g = new Group(p1);
-g.add(p2);
-System.out.println(Log.getString());
-</PRE></blockquote>
+<p> Write an aspect to log whenever a <code>Point</code> is added to a
+group. The <code>args</code> pointcut allows you to select join points
+based on the type of a parameter to a method call. </p>
-<p> should print out "adding Point;adding Point;".
+<p> Look at the test case for details about the tested log message.
</p>
-<p> <em>Hint: The <code>args</code> pointcut allows you to select join points
-based on the type of a parameter to a method call. </em> </p>
-
<h3>d. Logging extended to checking an invariant</h3>
<p> <strong>Task:</strong> Pass <code>tests.Test3d</code>.</p>
<p> <strong>Tools:</strong> <code>inter-type field declaration</code>
</p>
-<p>Make sure that a Point is never added to more than one Group.</p>
+<p> Make sure that a Point is never added to more than one Group.
+To do so, associate a boolean flag with each Point using an inter-type
+declaration, such as </p>
+
+<blockquote><pre>
+boolean Point.hasBeenAdded = false;
+</pre></blockquote>
+<p> Check and set this flag with the same kind of advice from your
+answer to problem (c). Throw an <code>IllegalStateException</code> if
+the point has already been added.
+</p>
<h3>e. Better error messages for 3d</h3>
<p> <strong>Tools:</strong>
</p>
-<p>Make sure that a Point is never added to more than one Group.
-Include the Group that the Point was previously a part of in the
-thrown exception.</p>
-
-<h3>c. Keeping track of state</h3>
-
-<p> In this exercise, perform the tracing from part (a), but also log
-the enclosing group, if any, of the moving point. You can use an
-inter-type declaration inside your aspect to associate a
-<code>Group</code> field with <code>Point</code> objects, and then
-work with that field, setting it appropriately when the
-<code>Point</code> is added to a <code>Group</code> (at the same join
-points you were tracing in part b). So </p>
-
-<blockquote><PRE>
-Point p1 = new Point(10, 100);
-p1.move(0, 0);
-System.out.println(Log.getString());
-</PRE></blockquote>
-
-<p> should print out "moving as a part of null;", but
-</p>
-
-<blockquote><PRE>
-Point p1 = new Point(10, 100);
-Group g = new Group(p1);
-p1.move(0, 0);
-System.out.println(Log.getString());
-</PRE></blockquote>
-
-<p> should print out "moving as a part of Group(Point(10, 100));",
-which you can do by using the toString() method already defined on
-Group. </p>
-
-<p> <em> Hint: This exercise combines the tracing from parts a and b.
-If you start with an aspect that includes the solutions to those
-previous exercises, you'll be most of the way there. </em> </p>
-
-<p> Test this with the JUnit test case <code>tests.Test3c</code>.
-
-
-<h3>Help Yourself by Helping Others</h3>
-
-<p> At this point, check the people to your left and right. If
-they're stuck somewhere, see if you can help them. </p>
-
-<hr />
+<p> Extend your solution to problem (d) by using the string
+representation of the Point's containing group as the <code>msg</code>
+part of the <code>IllegalStateException</code>. </p>
<!-- ============================== -->
<p> <strong>Task:</strong> Pass <code>tests.Test4b</code>.
</p>
-<p> <strong>Tools:</strong> <code>private Rectangle Group.mumble;</code>
+<p> <strong>Tools:</strong> inter-type field.
</p>
<p> Instead of making the (very) conservative approximation of
<code>move()</code> method of <code>Group</code> is called.
</p>
+<br style="page-break-after: always" />
<h3>d. Invalidate, part 2</h3>
<p> <strong>Task:</strong> Pass <code>tests.Test4d</code>.</p>
-<p> <strong>Tools:</strong> <code>your solution to 3c</code></p>
-
<p> Of course, part (c) didn't really solve the problem. What if a
<code>Point</code> that is part of a <code>Group</code> moves?
Whenever either of a Point's fields are set it should invalidate the