From ce801a083791f978fb69fc7cb362109b688a98c1 Mon Sep 17 00:00:00 2001
From: ehilsdal 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. 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 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. 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. 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 All the files in the program are listed in base.lst, including
test cases and an empty answer aspect,
@@ -29,7 +42,7 @@ answers there, all you need to do is compile base.lst, either in an
IDE or with Before you move onto another exercise, though, make sure to copy
@@ -39,18 +52,11 @@ together:
If you want to put your answer in a different file, say,
- In any case, after building the system, you should invoke Java on
-the compiled test class. On the command-line, this this would be After building the system, you should invoke Java on the compiled
+test class. On the command-line, this this would be AspectJ Tutorial Exercises
+AspectJ Exercises
Organization
-setpaths.bat
or source setpaths
to
-export some other needed environment variables. Command-line usage
+
+setpaths.bat
or
+source setpaths
to export some other needed environment
+variables.
-$ ajc -Xlint -argfile base.lst
+$ ajc -argfile base.lst
-
> copy answers/Answer.java answers/2a.java (Windows)
-$ cp answers/Answer.java answers/2a.java (Linux)
+$ cp answers/Answer.java answers/2a.java (Unix)
answers/Answer2a.java
, you can compile with
-
-
-$ ajc -Xlint -argfile base.lst answers/Answer2a.java
-
$ java tests.Test2a
@@ -66,7 +72,7 @@ rudimentary tests on figure elements, and so is a useful test to run
periodically. Looking at the JUnit tests for each exercise may also
be helpful.
Again, ae will be looking at some solutions and having discussion, +
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 @@ -91,13 +97,15 @@ shell, though, to run the JUnit tests (and don't forget to run the set up the run button to run a test through the Options menu, but we've found this is fairly cumbersome.
- -The easiest way to get started with AspectJ is to use it to +enforce static invariants. +
+Sample Exercise: The main point of this exercise @@ -114,7 +122,7 @@ test.
to useSystem.out.println()
, 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.
When you use this on the given system, you'll find one incorrect
@@ -163,6 +171,7 @@ aspect Answer1a {
of the out
field is illegal. This will also catch those
users who bind System.out to a static field to save typing.
Make sure your program still passes the JUnit test
-tests.Test
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.
tests.Test
before continuing. Make sure you get 11
+warnings from this. Wait to fix them until the next exercise.
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 or constructors. 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.
+setter methods or constructors. Modify your answer to signal +an actual error at compile time (rather than just a warning) when such +an illegal assignment expression exists.You'll want to add another withincode
primitive
pointcut to deal with the constructors.
@@ -217,33 +225,38 @@ pointcut to deal with the constructors.
the convention is violated twice in the figures package. You should see
the following two errors:
-.\figures\Point.java:28:9: bad field set - _x += dx; - ^ -.\figures\Point.java:29:9: bad field set - _y += dy; - ^ ++.\figures\Point.java:37 bad field set +.\figures\Point.java:38 bad field set + 2 errors -+
Rewrite these two occurrences so as not to violate
the convention. Make sure your program still passes the JUnit test
tests.Test
before continuing.
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.
-The next step in AspectJ adoption is often to augment a test suite +by including additional dynamic tests. +
+ +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.
+Sample Exercise: We've provided the answer to @@ -280,7 +293,7 @@ Tests run: 7, Failures: 2, Errors: 0
-$ ajc -Xlint -argfile base.lst answers/Answer.java +$ ajc -argfile base.lst answers/Answer.java $ java tests.Test2a ....... @@ -310,6 +323,9 @@ aspect Answer2a {Task: Pass
+tests.Test2b
.Tools:
+call
. +
Group
is aFigureElement
class that encapsulates groups of other figure elements. As such, only actual figure element objects should be added toGroup
objects. @@ -340,19 +356,32 @@ call.d. Assure input
-Task: Pass
tests.Test2g
. +Task: Pass
tests.Test2d
.Tools: around advice
Instead of throwing an exception when one of
+Point
's -int
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 -around
advice that exposes the new value of the field -assignment with anargs
pointcut, and -proceed
with the trimmed value.int
fields are set to a negative value, write an aspect +to trim the value to zero. You'll want to usearound
+advice that exposes the new value of the field assignment with an +args
pointcut, andproceed
with the trimmed +value. + +This is going to look something like +
+ ++aspect A { + void around(int val): <Pointcut> { + <Do something with val> + proceed(val); + } +} ++
e. Check a postcondition
Task: Pass
tests.Test2e
@@ -363,7 +392,7 @@ assignment with anargs
pointcut, andA postcondition of a
@@ -389,22 +418,14 @@ element's bounds rectangle should move by the same amount as the figure itself. Write an aspect to check for this postcondition -- throw anPoint
'smove
operation is that thePoint
'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 anIllegalStateException
should be thrown.IllegalStateException
if it is violated. -Help Yourself by Helping Others
- -At this point, check the people to your left and right. If -they're stuck somewhere, see if you can help them.
- -
-
3. Tracing
-The crosscutting feature you will be adding in part (4) will be -support for caching the bound objects of
+Group
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.Tracing is one of the classic AspectJ applications, and is often +the first where AspectJ is used on deployed code. +
a. Simple logging
@@ -420,7 +441,7 @@ in the figures package. To do this, use the utility classLog
(with an import fromsupport.Log
) and callLog.log(String)
-b. Simple logging
+b. Exposing a value
Task: Pass
@@ -441,35 +462,16 @@ but also the target object, with the formtests.Test3b
.Task: Pass
-tests.Test3c
.Tools: +
Tools:
-args
.Write an aspect to log whenever a
- -Point
is added to -a group (including initially). To do this, use the utility class -Log
(with an import fromsupport.Log
) and -call- --Log.log("adding Point") -This will write the string "adding Point", followed by a semicolon -terminator, to the Log. For example, with your aspect enabled,
- -+-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()); -Write an aspect to log whenever a
-Point
is added to a +group. Theargs
pointcut allows you to select join points +based on the type of a parameter to a method call.should print out "adding Point;adding Point;". +
Look at the test case for details about the tested log message.
-Hint: The
-args
pointcut allows you to select join points -based on the type of a parameter to a method call.d. Logging extended to checking an invariant
Task: Pass
@@ -477,8 +479,18 @@ based on the type of a parameter to a method call.tests.Test3d
.Tools:
-inter-type field declaration
Make sure that a Point is never added to more than one Group.
+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
+ +++boolean Point.hasBeenAdded = false; +Check and set this flag with the same kind of advice from your +answer to problem (c). Throw an
IllegalStateException
if +the point has already been added. +e. Better error messages for 3d
@@ -487,53 +499,9 @@ based on the type of a parameter to a method call.Tools:
-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.
- -c. Keeping track of state
- -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 -
- -Group
field withPoint
objects, and then -work with that field, setting it appropriately when the -Point
is added to aGroup
(at the same join -points you were tracing in part b). So- --Point p1 = new Point(10, 100); -p1.move(0, 0); -System.out.println(Log.getString()); -should print out "moving as a part of null;", but -
- -- --Point p1 = new Point(10, 100); -Group g = new Group(p1); -p1.move(0, 0); -System.out.println(Log.getString()); -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.
- -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.
- -Test this with the JUnit test case
tests.Test3c
. - - -Help Yourself by Helping Others
- -At this point, check the people to your left and right. If -they're stuck somewhere, see if you can help them.
- -
+Extend your solution to problem (d) by using the string +representation of the Point's containing group as the
@@ -577,7 +545,7 @@ around advice intercepting the method.msg
+part of theIllegalStateException
.Task: Pass
-tests.Test4b
.Tools:
private Rectangle Group.mumble;
+Tools: inter-type field.
Instead of making the (very) conservative approximation of @@ -605,12 +573,11 @@ Change your aspect so that it invalidates the cache whenever the
+move()
method ofGroup
is called.
d. Invalidate, part 2
Task: Pass
-tests.Test4d
.Tools:
-your solution to 3c
Of course, part (c) didn't really solve the problem. What if a
Point
that is part of aGroup
moves? Whenever either of a Point's fields are set it should invalidate the diff --git a/docs/teaching/exercises/tests/Test3d.java b/docs/teaching/exercises/tests/Test3d.java new file mode 100755 index 000000000..4fe8a04ca --- /dev/null +++ b/docs/teaching/exercises/tests/Test3d.java @@ -0,0 +1,38 @@ +/* ******************************************************************* + * Copyright (c) 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: + * PARC initial implementation + * ******************************************************************/ + +package tests; + +import figures.*; +import support.Log; +import junit.framework.*; +import java.util.List; +import java.util.Arrays; + +public class Test3d extends Test { + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test3d.class); + } + + public void testDuplicateAdd() { + Log.clear(); + Point p1 = new Point(10, 100); + Group g1 = new Group(p1); + try { + Group g2 = new Group(p1); + fail("should have thrown IllegalStateException"); + } catch (IllegalStateException ea) { + } + } +} + diff --git a/docs/teaching/exercises/tests/Test3e.java b/docs/teaching/exercises/tests/Test3e.java new file mode 100755 index 000000000..d9f6b9c35 --- /dev/null +++ b/docs/teaching/exercises/tests/Test3e.java @@ -0,0 +1,39 @@ +/* ******************************************************************* + * Copyright (c) 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: + * PARC initial implementation + * ******************************************************************/ + +package tests; + +import figures.*; +import support.Log; +import junit.framework.*; +import java.util.List; +import java.util.Arrays; + +public class Test3e extends Test { + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test3e.class); + } + + public void testDuplicateAdd() { + Log.clear(); + Point p1 = new Point(10, 100); + Group g1 = new Group(p1); + try { + Group g2 = new Group(p1); + fail("should have thrown IllegalStateException"); + } catch (IllegalStateException ea) { + assertEquals(g1.toString(), ea.getMessage()); + } + } +} + -- 2.39.5