Bläddra i källkod

revised with info from OOPSLA 2004:

  renaming support.Log.log to support.Log.write
  renaming test.Test to test.CoreTest
  (r)ing aspectj
  clearing up a few random things
tags/Root_AspectJ5_Development
ehilsdal 19 år sedan
förälder
incheckning
90da53cec2

+ 31
- 6
docs/teaching/exercises/README.txt Visa fil

@@ -1,9 +1,34 @@
AspectJ Figures Exercises
------------------------------

This file is really out-of-date. We're in the middle of recovery
from OOPSLA 2004, and we need to move stuff around in this
package. In particular, we need to build in a new structure.

One idea is that we should have _four_ projects within the
workspace, one for each problem set. There's still a bit of work
necessary to avoid duplicating code here (in CVS) even though we
want to duplicate code in the generated workspaces.

------------------------------
Generated Structure

We want a particular _generated_ structure for users. We're
eventually going to dump to a zip file or a CD.

Folder: aj-<event>:
/eclipse (arch)
/workspace (noarch)
/packages (noarch)
j2sdk for win, linux
aspectj for everybody

------------------------------
------------------------------

THIS FILE IS OUT-OF-DATE !!! (2003-3-17)

These exercises are designed to be used with AspectJ 1.0.6.
These exercises are designed to be used with AspectJ 1.0.6.

THEY MUST NOT BE DISTRIBUTED ELECTRONICALLY WITHOUT THINKING FIRST!!!
There may be licence issues with just sticking the junit jar in there
@@ -17,7 +42,7 @@ To build distribution zips, use ant -f build.xml. This will create
EV-allcontent.zip -- the exercises bundled with the answers


If you don't want to be bothered with specifying where AspectJ is,
If you don't want to be bothered with specifying where AspectJ is,
feel free to just do ant -f build.xml answers.zip. By default it will
build both exercises and answers.

@@ -52,12 +77,12 @@ files, but they might want to be refreshed every now and again.
Printing

It would be really nice to have an automated solution to generate the
documents, but no such luck.
documents, but no such luck.

* index.html should print out with useful page breaks. It should be
separated into four chunks if possible.
separated into four chunks if possible.

* answers in four chunks.
* answers in four chunks.

* quick reference sheets.

@@ -88,5 +113,5 @@ scripts under CVS.
---- Instructors

Since the only difference is the answers, just overwrite the
extraction directory with answers.zip.
extraction directory with answers.zip.


+ 1
- 1
docs/teaching/exercises/answers/Answer3a.java Visa fil

@@ -16,6 +16,6 @@ import support.Log;

aspect Answer3a {
before(): execution(public * *(..)) && within(figures.*) {
Log.log(thisJoinPoint.toString());
Log.write(thisJoinPoint);
}
}

+ 5
- 3
docs/teaching/exercises/answers/Answer3b.java Visa fil

@@ -21,9 +21,11 @@ import figures.FigureElement;
aspect Answer3b {
before(Object o):
execution(public * *(..))
&& within(figures.*) && target(o)
&& !withincode(public String toString(..)) // don't overflow!
&& !execution(public String toString(..))
// or perhaps !cflow(adviceexecution())
&& within(figures.*)
&& target(o)
{
Log.log(thisJoinPoint.toString() + " at " + o);
Log.write(thisJoinPoint + " at " + o);
}
}

+ 3
- 2
docs/teaching/exercises/answers/Answer3c.java Visa fil

@@ -18,7 +18,8 @@ import figures.*;

aspect Answer3c {
before():
execution(void Group.add(FigureElement)) && args(Point) {
Log.log("adding Point");
execution(void Group.add(FigureElement))
&& args(Point) {
Log.write("adding Point");
}
}

+ 9
- 7
docs/teaching/exercises/answers/Answer3d.java Visa fil

@@ -18,13 +18,15 @@ import figures.*;

aspect Answer3d {

boolean Point.inGroup = false;
private boolean Point.inGroup = false;

before(Point p): execution(void Group.add(FigureElement)) && args(p) {
if (p.inGroup) {
throw new IllegalStateException();
} else {
p.inGroup = true;
}
before(Point p):
execution(void Group.add(FigureElement))
&& args(p) {
if (p.inGroup) {
throw new IllegalStateException();
} else {
p.inGroup = true;
}
}
}

+ 10
- 7
docs/teaching/exercises/answers/Answer3e.java Visa fil

@@ -18,13 +18,16 @@ import figures.*;

aspect Answer3e {

Group Point.containingGroup = null;
private Group Point.containingGroup = null;

before(Group g, Point p): execution(void Group.add(FigureElement)) && this(g) && args(p) {
if (p.containingGroup != null) {
throw new IllegalStateException(p.containingGroup.toString());
} else {
p.containingGroup = g;
}
before(Group g, Point p):
execution(void Group.add(FigureElement))
&& this(g)
&& args(p) {
if (p.containingGroup != null) {
throw new IllegalStateException(p.containingGroup.toString());
} else {
p.containingGroup = g;
}
}
}

+ 2
- 2
docs/teaching/exercises/answers/Answer4b.java Visa fil

@@ -20,8 +20,8 @@ aspect Answer4b {
private Rectangle Group.cache = null;

Rectangle around(Group g):
execution(Rectangle Group.getBounds()) && this(g)
{
execution(Rectangle Group.getBounds())
&& this(g) {
if (g.cache == null) {
g.cache = proceed(g);
}

+ 5
- 3
docs/teaching/exercises/answers/Answer4c.java Visa fil

@@ -20,15 +20,17 @@ aspect Answer4c {
private Rectangle Group.cache = null;

Rectangle around(Group g):
execution(Rectangle Group.getBounds()) && this(g)
{
execution(Rectangle Group.getBounds())
&& this(g) {
if (g.cache == null) {
g.cache = proceed(g);
}
return g.cache;
}

before(Group g): call(void move(int, int)) && target(g) {
before(Group g):
call(void move(int, int))
&& target(g) {
g.cache = null;
}
}

+ 8
- 5
docs/teaching/exercises/answers/Answer4d.java Visa fil

@@ -22,21 +22,24 @@ aspect Answer4d {
private Group Point.enclosingGroup = null;

before(Point p, Group g):
execution(void add(FigureElement)) && args(p) && target(g)
{
execution(void add(FigureElement))
&& args(p)
&& target(g) {
p.enclosingGroup = g;
}

Rectangle around(Group g):
execution(Rectangle Group.getBounds()) && this(g)
{
execution(Rectangle Group.getBounds())
&& this(g) {
if (g.cache == null) {
g.cache = proceed(g);
}
return g.cache;
}

before(Point p): set(* Point.*) && target(p) {
before(Point p):
set(* Point.*)
&& target(p) {
if (p.enclosingGroup != null) {
p.enclosingGroup.cache = null;
}

+ 9
- 6
docs/teaching/exercises/answers/Answer4e.java Visa fil

@@ -21,22 +21,25 @@ aspect Answer4e {
private Rectangle Group.cache = null;
private Group FigureElement.enclosingGroup = null;

before(FigureElement p, Group g):
execution(void add(FigureElement)) && args(p) && target(g)
{
before(FigureElement p, Group g):
execution(void add(FigureElement))
&& args(p)
&& target(g) {
p.enclosingGroup = g;
}

Rectangle around(Group g):
execution(Rectangle Group.getBounds()) && this(g)
{
execution(Rectangle Group.getBounds())
&& this(g) {
if (g.cache == null) {
g.cache = proceed(g);
}
return g.cache;
}

before(Point p): set(* Point.*) && target(p) {
before(Point p):
set(* Point.*)
&& target(p) {
FigureElement fe = p;
while (fe.enclosingGroup != null) {
fe.enclosingGroup.cache = null;

+ 59
- 41
docs/teaching/exercises/index.html Visa fil

@@ -3,21 +3,28 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<!-- This file represents the Exercises for the hands-on AspectJ
tutorial. It is commonly checked into CVS with identifying
information for the latest conference (such as presenters
and publication information). -->
<!-- This file represents the Exercises for the hands-on AspectJ
tutorial. It is commonly checked into CVS with identifying
information for the latest conference (such as presenters
and publication information).

<!-- When you use it for your own purposes, don't forget to
When you use it for your own purposes, don't forget to
modify at the very least anything that says
id="copyright" or class="presenter" -->
id="copyright" or class="presenter". If you're in an A4
country, don't forget to modify the paper size.

<!-- Also, the gif included at the end is somewhat fragile,
so be careful with different paper sizes. -->
The gif included at the end is somewhat fragile,
so be careful with different paper sizes.

TODO: There is currently something weird about PDF generation
from this: If generated from a windows machine, it will
generate mac-unfriendly PDF because of the requested windows
font. If the PDF is only used for immediate printing,
that's fine, but if it's used for distribution, bad.
-->

<head>
<title>Hands-on Programming with AspectJ &mdash; Exercises</title>
<title>Hands-on Programming with AspectJ&reg; &mdash; Exercises</title>
<style type="text/css">
div.instruction { padding: 0.5em; border-width: 1px; border-style: solid }
body { background-color: #FFF; margin: 2em }
@@ -51,7 +58,7 @@ h3 { margin-top: 4ex; border-bottom-style: solid; border-width: 1px }

<body>

<h1>Hands-on Programming with AspectJ</h1>
<h1>Hands-on Programming with AspectJ<sup>&reg;</sup></h1>

<div class="presenter">Erik Hilsdale</div>
<div class="presenter">Mik Kersten</div>
@@ -90,11 +97,17 @@ diagram and quick reference. But you'll be cheating yourself if
you try to do the exercises early; you'll learn a lot more by
working through it in groups during the tutorial proper. </div>

<!--
This space is used for a copyright that appears on the
bottom of the _printed_ page. It's suppressed when viewed on
a computer screen by the stylesheet.

<div id="copyright">
Copyright is held by the author/owner(s). <br />
OOPSLA’04, October 24-28, 2004, Vancouver, British Columbia, Canada <br />
2004 ACM 04/0010
</div>
-->

<h3 class="newpage">Command-line usage</h3>

@@ -138,9 +151,9 @@ test class. On the command-line, this this would be </p>

<pre>
$ java tests.Test2a
</pre>
</pre>

<p> The default test, <code>tests.Test</code>, performs some
<p> The default test, <code>tests.CoreTest</code>, performs some
rudimentary tests on figure elements, and so is a useful test to run
periodically. You should also look at the JUnit tests for each
exercise as you do it. </p>
@@ -161,7 +174,7 @@ are using the AspectJ browser, Emacs, or Eclipse. </div>
<h2 class="newpage">1. Static Invariants</h2>

<p> The easiest way to get started with AspectJ is to use it to
enforce static invariants.
enforce static invariants.
</p>

<h3>1.a. Find old tracing</h3>
@@ -173,7 +186,7 @@ you get the desired compile-time error, remove the offending
line, and make sure you pass the JUnit test. </div>

<p> <strong>Task:</strong> Signal an error for calls to
<code>System.out.println</code>.
<code>System.out.println</code>.
</p>

<p> The way that we are all taught to print "hello world" from Java is
@@ -199,7 +212,7 @@ aspect Answer1a {
</pre>

<p> When you use this on the given system, you'll find one incorrect
trace in <code>SlothfulPoint</code>.
trace in <code>SlothfulPoint</code>.
</p>

<pre>
@@ -218,11 +231,11 @@ users who bind System.out to a static field to save typing. </p>
program to remove the illegal tracing call. </p>

<p> Make sure your program still passes the JUnit test
<code>tests.Test</code> (which it should also pass at the beginning of
<code>tests.CoreTest</code> (which it should also pass at the beginning of
all exercises) before continuing. </p>

<pre>
$ java tests.Test
$ java tests.CoreTest
....
Time: 0.03

@@ -254,10 +267,10 @@ aspect A {

<p> where the pointcut picks out join points of private field sets
outside of setter methods. "Outside", here, means that the code for
the assignment is outside the <em>text</em> of the setter.
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. Make sure you get eleven
<code>tests.CoreTest</code> before continuing. Make sure you get eleven
warnings from this. Wait to fix them until the next exercise. </p>

<h3>1.c. Refine setters mandate</h3>
@@ -275,7 +288,7 @@ 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.
pointcut to deal with the constructors.
</p>

<p>After you specify your pointcut correctly, you'll still find that
@@ -291,7 +304,7 @@ the following two errors:</p>

<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>
<code>tests.CoreTest</code> before continuing. </p>

<div class="instruction"> Congratulations, you've taken your
first steps. At this point, check the people to your left and
@@ -332,7 +345,7 @@ whenever an attempt is made to set one of <code>Point</code>'s

<p> This should make the test case of <code>tests.Test2a</code> pass,
which wouldn't without your aspect. So before compiling in the
aspect,
aspect,
</p>

<pre>
@@ -360,7 +373,7 @@ Time: 0.04
OK (7 tests)
</pre>

<p> <strong>Answer:</strong>
<p> <strong>Answer:</strong>
</p>

<pre>
@@ -372,7 +385,7 @@ aspect Answer2a {
before(int newValue): set(int Point.*) &amp;&amp; args(newValue) {
if (newValue &lt; 0) {
throw new IllegalArgumentException("too small");
}
}
}
}
</pre>
@@ -409,7 +422,7 @@ an attempt is made to call <code>Group.add()</code> on a

<p> You will want to use a <code>target</code> pointcut to expose the
<code>Group</code> object that is the target of the <code>add</code>
call.
call.
</p>

<h3>2.d. Assure input</h3>
@@ -421,7 +434,7 @@ call.
</p>

<p> Instead of throwing an exception when one of <code>Point</code>'s
<code>int</code> fields are set to a negative value, write an aspect
<code>int</code> fields is 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
@@ -483,19 +496,22 @@ throw an <code>IllegalStateException</code> if it is violated. </p>
the first where AspectJ is used on deployed code.
</p>

<h3>3.a. Simple logging</h3>
<h3>3.a. Simple tracing</h3>

<p> <strong>Task:</strong> Pass <code>tests.Test3a</code>.</p>

<p> <strong>Tools:</strong> <code>Log.log(String)</code>,
<code>thisJoinPoint.toString()</code>, <code>execution</code>,
<code>within</code>
<p> <strong>Tools:</strong>
<code>Log.write(String)</code>,
<code>thisJoinPoint.toString()</code>,
<code>execution</code>,
<code>within</code>
</p>

<p> Write an aspect to log the execution of all public methods
in the figures package. To do this, use the utility class
<code>Log</code> (with an import from <code>support.Log</code>)
and call <code>Log.log(String)</code></p>
<code>Log</code> (this is in the <code>support</code> package, so
remember to import it into your answer aspect). Write a message
into the log with the static <code>write(String)</code> method.</p>

<h3>3.b. Exposing a value</h3>

@@ -525,7 +541,8 @@ but also the target object, with the form
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> Look at the test case for details about the required log message.
<p> Look at the test case to see the trace message we expect you
to write in the log.
</p>

<h3 class="newpage">3.d. Logging extended to checking an invariant</h3>
@@ -535,9 +552,10 @@ based on the type of a parameter to a method call. </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.
To do so, associate a boolean flag with each Point using an inter-type
declaration, such as </p>
<p> Make sure that a <code>Point</code> is never added to more
than one <code>Group</code>. To do so, associate a boolean flag
with each <code>Point</code> using an inter-type declaration,
such as </p>

<pre>
boolean Point.hasBeenAdded = false;
@@ -575,8 +593,8 @@ contained in Lines and Boxes only if time permits. </div>

<p> <strong>Task:</strong> Pass <code>tests.Test4a</code>.</p>

<p> <strong>Tools:</strong> <code>around</code>,
<code>FigureElement.MAX_BOUNDS</code>
<p> <strong>Tools:</strong> <code>around</code>,
<code>FigureElement.MAX_BOUNDS</code>
</p>

<p> <code>Group</code>'s <code>getBounds()</code> method could be
@@ -589,7 +607,7 @@ by the static method <code>FigureElement.MAX_BOUNDS</code>.

<p> Write an aspect to implement this change. You can override
<code>Group</code>'s <code>getBounds()</code> method entirely with
around advice intercepting the method.
around advice intercepting the method.
</p>

<h3>4.b. Make a constant cache</h3>
@@ -622,7 +640,7 @@ state for every <code>Group</code> object.</em> </p>
<p> While caching in this way does save computation, it will lead to
incorrect bounding boxes if a <code>Group</code> is ever moved.
Change your aspect so that it invalidates the cache whenever the
<code>move()</code> method of <code>Group</code> is called.
<code>move()</code> method of <code>Group</code> is called.
</p>

<h3 class="newpage">4.d. Invalidate, part 2</h3>
@@ -663,7 +681,7 @@ an active user community for AspectJ at</p>
<blockquote>
http://www.eclipse.org/aspectj
</blockquote>
</div>

<img style="newpage" src="figures_classes.gif" height="900" alt="" />

+ 1
- 15
docs/teaching/exercises/support/Log.java Visa fil

@@ -19,24 +19,10 @@ import java.util.ArrayList;
public class Log {
static List data = new ArrayList();

public static void traceObject(Object o) {
throw new UnsupportedOperationException();
}

public static void log(String s) {
public static void write(String s) {
data.add(s);
}

// public static void logClassName(Class _class) {
// String name = _class.getName();
// int dot = name.lastIndexOf('.');
// if (dot == -1) {
// log(name);
// } else {
// log(name.substring(dot+1, name.length()));
// }
// }

public static List getData() {
return data;
}

docs/teaching/exercises/tests/Test.java → docs/teaching/exercises/tests/CoreTest.java Visa fil

@@ -16,7 +16,7 @@ import figures.*;

import junit.framework.*;

public class Test extends TestCase {
public class CoreTest extends TestCase {

public static void main(String[] args) {
junit.textui.TestRunner.run(Test.class);

Laddar…
Avbryt
Spara