From: jhugunin Date: Fri, 1 Aug 2003 18:53:07 +0000 (+0000) Subject: Addendum to the original contribution from PARC. Three presentations: X-Git-Tag: V1_1_1~162 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=57445dd3ec8a67d06f16fe02e7c0eaefb8ea4051;p=aspectj.git Addendum to the original contribution from PARC. Three presentations: oneHour talk three hour tutorial six hour tutorial including exercises --- diff --git a/docs/teaching/exercises/answers/Answer1a.java b/docs/teaching/exercises/answers/Answer1a.java new file mode 100644 index 000000000..94d4522c4 --- /dev/null +++ b/docs/teaching/exercises/answers/Answer1a.java @@ -0,0 +1,22 @@ +/* ******************************************************************* + * 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 answers; + +import figures.*; + +aspect Answer1a { + declare error + : get(java.io.PrintStream System.out) + && within(figures..*) + : "illegal access to System.out"; +} diff --git a/docs/teaching/exercises/answers/Answer1b.java b/docs/teaching/exercises/answers/Answer1b.java new file mode 100644 index 000000000..ef634a974 --- /dev/null +++ b/docs/teaching/exercises/answers/Answer1b.java @@ -0,0 +1,21 @@ +/* ******************************************************************* + * 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 answers; + +aspect Answer1b { + declare warning + : set(private * *) + && !withincode(* set*(..)) + && within(figures.*) + : "bad field set"; +} diff --git a/docs/teaching/exercises/answers/Answer1c.java b/docs/teaching/exercises/answers/Answer1c.java new file mode 100644 index 000000000..ff31b6378 --- /dev/null +++ b/docs/teaching/exercises/answers/Answer1c.java @@ -0,0 +1,21 @@ +/* ******************************************************************* + * 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 answers; + +aspect Answer1c { + declare error + : set(private * *) + && !(withincode(* set*(..)) || withincode(new(..))) + && within(figures.*) + : "bad field set"; +} diff --git a/docs/teaching/exercises/answers/Answer1d.java b/docs/teaching/exercises/answers/Answer1d.java new file mode 100644 index 000000000..9fb32390b --- /dev/null +++ b/docs/teaching/exercises/answers/Answer1d.java @@ -0,0 +1,23 @@ +/* ******************************************************************* + * 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 answers; + +aspect Answer1c { + declare error + : set(private * *) + && !(withincode(* set*(..)) + || withincode(new(..)) + || withincode(void figures.Point.move(int, int))) + && within(figures.*) + : "bad field set"; +} diff --git a/docs/teaching/exercises/answers/Answer2a.java b/docs/teaching/exercises/answers/Answer2a.java new file mode 100644 index 000000000..b874f06eb --- /dev/null +++ b/docs/teaching/exercises/answers/Answer2a.java @@ -0,0 +1,26 @@ +/* ******************************************************************* + * 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 answers; + +import figures.Point; +import figures.FigureElement; + +public aspect Answer2a { + before(int newValue): set(int Point.*) && args(newValue) { + if (newValue < FigureElement.MIN_VALUE) { + throw new IllegalArgumentException("too small"); + } else if (newValue > FigureElement.MAX_VALUE) { + throw new IllegalArgumentException("too large"); + } + } +} diff --git a/docs/teaching/exercises/answers/Answer2b.java b/docs/teaching/exercises/answers/Answer2b.java new file mode 100644 index 000000000..fc45ad265 --- /dev/null +++ b/docs/teaching/exercises/answers/Answer2b.java @@ -0,0 +1,26 @@ +/* ******************************************************************* + * 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 answers; + +import figures.Group; +import figures.FigureElement; + +public aspect Answer2b { + before(FigureElement newValue): + call(void Group.add(FigureElement)) + && args(newValue) { + if (newValue == null) { + throw new IllegalArgumentException("null not allowed"); + } + } +} diff --git a/docs/teaching/exercises/answers/Answer2c.java b/docs/teaching/exercises/answers/Answer2c.java new file mode 100644 index 000000000..6dbd7fa90 --- /dev/null +++ b/docs/teaching/exercises/answers/Answer2c.java @@ -0,0 +1,31 @@ +/* ******************************************************************* + * 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 answers; + +import figures.Group; +import figures.FigureElement; + +public aspect Answer2c { + before(FigureElement newValue, Group g): + call(void Group.add(FigureElement)) + && args(newValue) + && target(g) { + if (newValue == null) { + throw new IllegalArgumentException("null not allowed"); + } + if (newValue == g) { + throw new IllegalArgumentException("self not allowed"); + } + + } +} diff --git a/docs/teaching/exercises/answers/Answer2d.java b/docs/teaching/exercises/answers/Answer2d.java new file mode 100644 index 000000000..75937ca86 --- /dev/null +++ b/docs/teaching/exercises/answers/Answer2d.java @@ -0,0 +1,24 @@ +/* ******************************************************************* + * 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 answers; + +import figures.SlothfulPoint; + +aspect Answer2d { + after(int newValue, SlothfulPoint p) returning: + call(void setX(int)) && args(newValue) && target(p) { + if (newValue != p.getX()) { + throw new RuntimeException("setter didn't set"); + } + } +} diff --git a/docs/teaching/exercises/answers/Answer2e.java b/docs/teaching/exercises/answers/Answer2e.java new file mode 100644 index 000000000..a0500bc6b --- /dev/null +++ b/docs/teaching/exercises/answers/Answer2e.java @@ -0,0 +1,24 @@ +/* ******************************************************************* + * 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 answers; + +import figures.*; + +public aspect Answer2e { + pointcut checkpoint(Box box): + call(void move(int, int)) && target(box); + + after(Box box) returning: checkpoint(box) { + box.checkBoxness(); + } +} diff --git a/docs/teaching/exercises/answers/Answer2f.java b/docs/teaching/exercises/answers/Answer2f.java new file mode 100644 index 000000000..aad64f4e2 --- /dev/null +++ b/docs/teaching/exercises/answers/Answer2f.java @@ -0,0 +1,24 @@ +/* ******************************************************************* + * 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 answers; + +import figures.*; + +public aspect Answer2f { + pointcut checkpoint(Box box): + target(box) && call(public * *(..)) && !within(Answer*); + + after(Box box) returning: checkpoint(box) { + box.checkBoxness(); + } +} diff --git a/docs/teaching/exercises/answers/Answer2g.java b/docs/teaching/exercises/answers/Answer2g.java new file mode 100644 index 000000000..9bc9a521c --- /dev/null +++ b/docs/teaching/exercises/answers/Answer2g.java @@ -0,0 +1,27 @@ +/* ******************************************************************* + * 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 answers; + +import figures.*; + +aspect Answer2g { + int around(int val): (set(int Point._x) || set(int Point._y)) + && args(val) { + return proceed(trim(val)); + } + + private int trim(int val) { + return Math.max(Math.min(val, FigureElement.MAX_VALUE), + FigureElement.MIN_VALUE); + } +} diff --git a/docs/teaching/exercises/answers/Answer2h.java b/docs/teaching/exercises/answers/Answer2h.java new file mode 100644 index 000000000..3dcc47bef --- /dev/null +++ b/docs/teaching/exercises/answers/Answer2h.java @@ -0,0 +1,31 @@ +/* ******************************************************************* + * 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 answers; + +import figures.*; + +import java.awt.Rectangle; + +aspect Answer2h { + void around(FigureElement fe, int dx, int dy): + target(fe) && call(void move(int, int)) && args(dx, dy) { + Rectangle preBounds = new Rectangle(fe.getBounds()); + proceed(fe, dx, dy); + + preBounds.translate(dx, dy); + + if (!preBounds.equals(fe.getBounds())) { + throw new IllegalStateException("bounds don't match move"); + } + } +} diff --git a/docs/teaching/exercises/answers/Answer3a.java b/docs/teaching/exercises/answers/Answer3a.java new file mode 100644 index 000000000..7d9c91f0e --- /dev/null +++ b/docs/teaching/exercises/answers/Answer3a.java @@ -0,0 +1,23 @@ +/* ******************************************************************* + * 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 answers; + +import support.Log; + +import figures.Point; + +aspect Answer3a { + before(): execution(void Point.move(int, int)) { + Log.log("moving"); + } +} diff --git a/docs/teaching/exercises/answers/Answer3b.java b/docs/teaching/exercises/answers/Answer3b.java new file mode 100644 index 000000000..b978f1a5e --- /dev/null +++ b/docs/teaching/exercises/answers/Answer3b.java @@ -0,0 +1,26 @@ +/* ******************************************************************* + * 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 answers; + +import support.Log; + +import figures.Point; +import figures.Group; +import figures.FigureElement; + +aspect Answer3b { + before(): + execution(void Group.add(FigureElement)) && args(Point) { + Log.log("adding Point"); + } +} diff --git a/docs/teaching/exercises/answers/Answer3c.java b/docs/teaching/exercises/answers/Answer3c.java new file mode 100644 index 000000000..68797b9e0 --- /dev/null +++ b/docs/teaching/exercises/answers/Answer3c.java @@ -0,0 +1,34 @@ +/* ******************************************************************* + * 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 answers; + +import support.Log; + +import figures.Point; +import figures.Group; +import figures.FigureElement; + +aspect Answer3c { + private Group Point.enclosingGroup = null; + + before(Point p, Group g): + execution(void add(FigureElement)) && args(p) && target(g) { + p.enclosingGroup = g; + } + + before(Point p): + call(void move(int, int)) && target(p) { + Log.log("moving as a part of " + p.enclosingGroup); + } + +} diff --git a/docs/teaching/exercises/answers/Answer4a.java b/docs/teaching/exercises/answers/Answer4a.java new file mode 100644 index 000000000..2f3956aea --- /dev/null +++ b/docs/teaching/exercises/answers/Answer4a.java @@ -0,0 +1,28 @@ +/* ******************************************************************* + * 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 answers; + +import figures.FigureElement; +import figures.Group; +import java.awt.Rectangle; + +aspect Answer4a { + private Rectangle wholeCanvas = + new Rectangle(FigureElement.MIN_VALUE, FigureElement.MIN_VALUE, + FigureElement.MAX_VALUE - FigureElement.MIN_VALUE, + FigureElement.MAX_VALUE - FigureElement.MIN_VALUE); + + Rectangle around(): execution(Rectangle Group.getBounds()) { + return wholeCanvas; + } +} diff --git a/docs/teaching/exercises/answers/Answer4b.java b/docs/teaching/exercises/answers/Answer4b.java new file mode 100644 index 000000000..d0292b14f --- /dev/null +++ b/docs/teaching/exercises/answers/Answer4b.java @@ -0,0 +1,29 @@ +/* ******************************************************************* + * 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 answers; + +import figures.FigureElement; +import figures.Group; +import java.awt.Rectangle; + +aspect Answer4b { + private Rectangle Group.cache = null; + + Rectangle around(Group g): + execution(Rectangle Group.getBounds()) && this(g) { + if (g.cache == null) { + g.cache = proceed(g); + } + return g.cache; + } +} diff --git a/docs/teaching/exercises/answers/Answer4c.java b/docs/teaching/exercises/answers/Answer4c.java new file mode 100644 index 000000000..54107cf8f --- /dev/null +++ b/docs/teaching/exercises/answers/Answer4c.java @@ -0,0 +1,33 @@ +/* ******************************************************************* + * 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 answers; + +import figures.FigureElement; +import figures.Group; +import java.awt.Rectangle; + +aspect Answer4c { + private Rectangle Group.cache = null; + + Rectangle around(Group 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) { + g.cache = null; + } +} diff --git a/docs/teaching/exercises/answers/Answer4d.java b/docs/teaching/exercises/answers/Answer4d.java new file mode 100644 index 000000000..10d90f6dd --- /dev/null +++ b/docs/teaching/exercises/answers/Answer4d.java @@ -0,0 +1,42 @@ +/* ******************************************************************* + * 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 answers; + +import figures.FigureElement; +import figures.Group; +import figures.Point; +import java.awt.Rectangle; + +aspect Answer4d { + private Rectangle Group.cache = null; + private Group Point.enclosingGroup = null; + + before(Point p, Group g): + execution(void add(FigureElement)) && args(p) && target(g) { + p.enclosingGroup = g; + } + + Rectangle around(Group 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) { + if (p.enclosingGroup != null) { + p.enclosingGroup.cache = null; + } + } +} diff --git a/docs/teaching/exercises/answers/Answer4e.java b/docs/teaching/exercises/answers/Answer4e.java new file mode 100644 index 000000000..20f98909a --- /dev/null +++ b/docs/teaching/exercises/answers/Answer4e.java @@ -0,0 +1,44 @@ +/* ******************************************************************* + * 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 answers; + +import figures.FigureElement; +import figures.Group; +import figures.Point; +import java.awt.Rectangle; + +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) { + p.enclosingGroup = g; + } + + Rectangle around(Group 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) { + FigureElement fe = p; + while (fe.enclosingGroup != null) { + fe.enclosingGroup.cache = null; + fe = fe.enclosingGroup; + } + } +} diff --git a/docs/teaching/exercises/base.lst b/docs/teaching/exercises/base.lst new file mode 100644 index 000000000..ae9c8c65e --- /dev/null +++ b/docs/teaching/exercises/base.lst @@ -0,0 +1,29 @@ +figures/Box.java +figures/FigureElement.java +figures/Group.java +figures/Line.java +figures/Point.java +figures/ShapeFigureElement.java +figures/SlothfulPoint.java + +support/Log.java + +answers/Answer.java + +tests/Test.java +tests/Test2a.java +tests/Test2b.java +tests/Test2c.java +tests/Test2d.java +tests/Test2e.java +tests/Test2f.java +tests/Test2g.java +tests/Test2h.java +tests/Test3a.java +tests/Test3b.java +tests/Test3c.java +tests/Test4a.java +tests/Test4b.java +tests/Test4c.java +tests/Test4d.java +tests/Test4e.java diff --git a/docs/teaching/exercises/figures/Box.java b/docs/teaching/exercises/figures/Box.java new file mode 100644 index 000000000..b10faa612 --- /dev/null +++ b/docs/teaching/exercises/figures/Box.java @@ -0,0 +1,64 @@ +/* ******************************************************************* + * 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 figures; + +import java.awt.*; +import java.awt.geom.*; + +public class Box extends ShapeFigureElement { + private Point _p0; + private Point _p1; + private Point _p2; + private Point _p3; + + public Box(int x0, int y0, int width, int height) { + _p0 = new Point(x0, y0); + _p1 = new Point(x0+width, y0); + _p2 = new Point(x0+width, y0+height); + _p3 = new Point(x0, y0+height); + } + + public Point getP0() { return _p0; } + public Point getP1() { return _p1; } + public Point getP2() { return _p2; } + public Point getP3() { return _p3; } + + public void move(int dx, int dy) { + _p0.move(dx, dy); + _p1.move(dx, dy); + _p2.move(dx, dy); + _p3.move(dx, dy); + } + + public void checkBoxness() { + if ((_p0.getX() == _p3.getX()) && + (_p1.getX() == _p2.getX()) && + (_p0.getY() == _p1.getY()) && + (_p2.getY() == _p3.getY())) + return; + throw new IllegalStateException("This is not a square."); + } + + public String toString() { + return "Box(" + _p0 + ", " + _p1 + ", " + _p2 + ", " + _p3 + ")"; + } + + public Shape getShape() { + return new Rectangle(getP1().getX(), + getP1().getY(), + getP3().getX() - getP1().getX(), + getP3().getY() - getP1().getY()); + } +} + diff --git a/docs/teaching/exercises/figures/FigureElement.java b/docs/teaching/exercises/figures/FigureElement.java new file mode 100644 index 000000000..d6d5c261c --- /dev/null +++ b/docs/teaching/exercises/figures/FigureElement.java @@ -0,0 +1,30 @@ +/* ******************************************************************* + * 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 figures; + +import java.awt.*; +import java.awt.geom.*; + +public interface FigureElement { + public static final int MIN_VALUE = 0; + public static final int MAX_VALUE = 500; + + public abstract void move(int dx, int dy); + + public abstract Rectangle getBounds(); + + public abstract boolean contains(Point2D p); + + public abstract void paint(Graphics2D g2); +} diff --git a/docs/teaching/exercises/figures/Group.java b/docs/teaching/exercises/figures/Group.java new file mode 100644 index 000000000..ad2f224c6 --- /dev/null +++ b/docs/teaching/exercises/figures/Group.java @@ -0,0 +1,97 @@ +/* ******************************************************************* + * 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 figures; + +import java.util.*; +import java.awt.*; +import java.awt.geom.*; + +public class Group implements FigureElement { + private Collection _members; + private String _identifier; + + public Group(FigureElement first) { + this._members = new ArrayList(); + add(first); + } + + public void add(FigureElement fe) { + _members.add(fe); + } + + public Iterator members() { + return _members.iterator(); + } + + public void move(int dx, int dy) { + for (Iterator i = _members.iterator(); i.hasNext(); ) { + FigureElement fe = (FigureElement)i.next(); + fe.move(dx, dy); + } + } + + public void setIdentifier(String identifier) { + _identifier = identifier; + } + + public String toString() { + if (_identifier != null) { + return _identifier; + } + + StringBuffer buf = new StringBuffer("Group("); + for (Iterator i = _members.iterator(); i.hasNext(); ) { + buf.append(i.next().toString()); + if (i.hasNext()) { + buf.append(", "); + } + } + buf.append(")"); + return buf.toString(); + } + + public Rectangle getBounds() { + Rectangle previous = null; + for (Iterator i = _members.iterator(); i.hasNext(); ) { + FigureElement fe = (FigureElement)i.next(); + Rectangle rect = fe.getBounds(); + if (previous != null) { + previous = previous.union(rect); + } else { + previous = rect; + } + } + return previous; + } + + public boolean contains(Point2D p) { + for (Iterator i = _members.iterator(); i.hasNext(); ) { + FigureElement fe = (FigureElement)i.next(); + if (fe.contains(p)) return true; + } + return false; + } + + public void paint(Graphics2D g2) { + for (Iterator i = _members.iterator(); i.hasNext(); ) { + FigureElement fe = (FigureElement)i.next(); + fe.paint(g2); + } + } + + public int size() { + return _members.size(); + } +} + diff --git a/docs/teaching/exercises/figures/Line.java b/docs/teaching/exercises/figures/Line.java new file mode 100644 index 000000000..f21c1eff1 --- /dev/null +++ b/docs/teaching/exercises/figures/Line.java @@ -0,0 +1,64 @@ +/* ******************************************************************* + * 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 figures; + +import java.awt.*; +import java.awt.geom.*; + +public class Line extends ShapeFigureElement { + private Point _p1; + private Point _p2; + + public Line(Point p1, Point p2) { + _p1 = p1; + _p2 = p2; + } + + public Point getP1() { return _p1; } + public Point getP2() { return _p2; } + + public void move(int dx, int dy) { + _p1.move(dx, dy); + _p2.move(dx, dy); + } + + public String toString() { + return "Line(" + _p1 + ", " + _p2 + ")"; + } + + /** + * Used to determine if this line {@link contains(Point2D)} a point. + */ + final static int THRESHHOLD = 5; + + /** + * Returns true if the point segment distance is less than + * {@link THRESHHOLD}. + */ + public boolean contains(Point2D p) { + return getLine2D().ptLineDist(p) < THRESHHOLD; + } + + private Line2D getLine2D() { + return new Line2D.Float((float)getP1().getX(), + (float)getP1().getY(), + (float)getP2().getX(), + (float)getP2().getY()); + } + + public Shape getShape() { + return getLine2D(); + } +} + diff --git a/docs/teaching/exercises/figures/Point.java b/docs/teaching/exercises/figures/Point.java new file mode 100644 index 000000000..63126d96f --- /dev/null +++ b/docs/teaching/exercises/figures/Point.java @@ -0,0 +1,58 @@ +/* ******************************************************************* + * 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 figures; + +import java.awt.*; +import java.awt.geom.*; + +public class Point extends ShapeFigureElement { + private int _x; + private int _y; + + public Point(int x, int y) { + _x = x; + _y = y; + } + + public int getX() { return _x; } + + public int getY() { return _y; } + + public void setX(int x) { _x = x; } + + public void setY(int y) { _y = y; } + + public void move(int dx, int dy) { + _x += dx; + _y += dy; + } + + public String toString() { + return "Point(" + _x + ", " + _y + ")"; + } + + /** The height of displayed {@link Point}s. */ + private final static int HEIGHT = 10; + + /** The width of displayed {@link Point}s. -- same as {@link HEIGHT}. */ + private final static int WIDTH = Point.HEIGHT; + + public Shape getShape() { + return new Ellipse2D.Float((float)getX()-Point.WIDTH/2, + (float)getY()-Point.HEIGHT/2, + (float)Point.HEIGHT, + (float)Point.WIDTH); + } +} + diff --git a/docs/teaching/exercises/figures/ShapeFigureElement.java b/docs/teaching/exercises/figures/ShapeFigureElement.java new file mode 100644 index 000000000..b09bad10e --- /dev/null +++ b/docs/teaching/exercises/figures/ShapeFigureElement.java @@ -0,0 +1,47 @@ +/* ******************************************************************* + * 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 figures; + +import java.awt.*; +import java.awt.geom.*; + +public abstract class ShapeFigureElement implements FigureElement { + public abstract void move(int dx, int dy); + + public abstract Shape getShape(); + + public Rectangle getBounds() { + return getShape().getBounds(); + } + + public boolean contains(Point2D p) { + return getShape().contains(p); + } + + public Color getLineColor() { + return Color.black; + } + + public Color getFillColor() { + return Color.red; + } + + public final void paint(Graphics2D g2) { + Shape shape = getShape(); + g2.setPaint(getFillColor()); + g2.fill(shape); + g2.setPaint(getLineColor()); + g2.draw(shape); + } +} diff --git a/docs/teaching/exercises/figures/SlothfulPoint.java b/docs/teaching/exercises/figures/SlothfulPoint.java new file mode 100644 index 000000000..ede073b24 --- /dev/null +++ b/docs/teaching/exercises/figures/SlothfulPoint.java @@ -0,0 +1,50 @@ +/* ******************************************************************* + * 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 figures; + +import java.awt.*; +import java.awt.geom.*; + +/** + * This class makes mistakes to be caught by invariant checkers. + */ +public class SlothfulPoint extends ShapeFigureElement { + private int _x; + private int _y; + + public SlothfulPoint(int x, int y) { + } + + public int getX() { return _x; } + + public int getY() { return _y; } + + public void setX(int x) { } + + public void setY(int y) { } + + public void move(int dx, int dy) { + System.out.println("Slothful moving"); + } + + public String toString() { + return "SlothfulPoint"; + } + + public Shape getShape() { + return new Ellipse2D.Float((float)_x, + (float)_y, 1.0f, 1.0f); + } +} + diff --git a/docs/teaching/exercises/figures/gui/FigurePanel.java b/docs/teaching/exercises/figures/gui/FigurePanel.java new file mode 100644 index 000000000..4746bc057 --- /dev/null +++ b/docs/teaching/exercises/figures/gui/FigurePanel.java @@ -0,0 +1,181 @@ +/* ******************************************************************* + * 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 figures.gui; + +import figures.Point; +import figures.Line; +import figures.FigureElement; +import figures.Group; + + +import java.awt.*; +import java.awt.geom.*; +import java.awt.event.*; +import java.io.*; +import java.util.*; +import javax.swing.*; +import javax.swing.text.*; +import javax.swing.border.*; + +public class FigurePanel extends JComponent { + + ButtonsPanel bp = new ButtonsPanel(); + FigureSurface fs = new FigureSurface(); + ConsolePanel cp = new ConsolePanel(); + + + public FigurePanel() { + setLayout(new BorderLayout()); + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.add(fs); + panel.add(bp); + JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, panel, cp); + sp.setPreferredSize(new Dimension(500, 400)); + sp.setDividerLocation(250); + add(BorderLayout.CENTER, sp); + } + + class ButtonsPanel extends JPanel { + JLabel msgs = new JLabel("click to add a point or line"); + public ButtonsPanel() { + setLayout(new FlowLayout(FlowLayout.LEFT)); + add(new JButton(new AbstractAction("Main") { + public void actionPerformed(ActionEvent e) { + Main.main(new String[]{}); + fs.repaint(); + } + })); + add(msgs); + } + + public void log(String msg) { + msgs.setText(msg); + } + } + + static class ConsolePanel extends JPanel { + + JTextArea text = new JTextArea(); + + public ConsolePanel() { + super(new BorderLayout()); + text.setFont(StyleContext.getDefaultStyleContext().getFont("SansSerif", Font.PLAIN, 10)); + JScrollPane scroller = new JScrollPane(text); + scroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + add(BorderLayout.CENTER, scroller); + } + + public void println(String msg) { + text.append(msg + '\n'); + } + } + + final static Color BACKGROUND = Color.white; + + static class FigureSurface extends JPanel implements MouseListener, MouseMotionListener { + Group canvas; + + public FigureSurface() { + canvas = new Group(new Point(250, 250)); + addMouseMotionListener(this); + addMouseListener(this); + setPreferredSize(new Dimension(500,500)); + } + + private Point addPoint(int x, int y) { + Point p = new Point(x, y); + canvas.add(p); + repaint(); + return p; + } + + private Line addLine(Point p1, Point p2) { + if (Math.abs(p1.getX()-p2.getX()) < 5 || + Math.abs(p1.getY()-p2.getY()) < 5) { + return null; + } + + Line line = null; + if (p1 != null && p2 != null) { + line = new Line(p1, p2); + canvas.add(line); + } + repaint(); + return line; + } + + public void paint(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + g2.setPaint(BACKGROUND); + g2.fill(new Rectangle2D.Float(0f, 0f, (float)g2.getClipBounds().width, (float)g2.getClipBounds().height)); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + canvas.paint(g2); + } + + + int lastX, lastY; + int pressX, pressY; + + FigureElement first = null; + Point point1 = null; + + public void mousePressed(MouseEvent e){ + int x = e.getX(), y = e.getY(); + pressX = lastX = x; pressY = lastY = y; + first = findFigureElement(x, y); + if (first == null) { + point1 = addPoint(x, y); + } + } + + public void mouseDragged(MouseEvent e) { + int x = e.getX(), y = e.getY(), dx = lastX-x, dy = lastY-y; + lastX = x; + lastY = y; + if (first == null) { + Line line = addLine(point1, new Point(x, y)); + if (line != null) { + canvas.add(line.getP2()); + first = line.getP2(); + canvas.add(line); + } + } else { + first.move(-dx, -dy); + } + repaint(); + } + + public void mouseReleased(MouseEvent e){ + mouseDragged(e); + first = null; + point1 = null; + } + + + public void mouseMoved(MouseEvent e){} + public void mouseClicked(MouseEvent e){} + public void mouseExited(MouseEvent e){} + public void mouseEntered(MouseEvent e){} + + private FigureElement findFigureElement(int x, int y) { + Point2D p = new Point2D.Float((float)x, (float)y); + for (Iterator i = canvas.members(); i.hasNext(); ) { + FigureElement fe = (FigureElement)i.next(); + if (fe.contains(p)) return fe; + } + return null; + } + } +} diff --git a/docs/teaching/exercises/figures/gui/LogAdapter.java b/docs/teaching/exercises/figures/gui/LogAdapter.java new file mode 100644 index 000000000..9d7d7d94d --- /dev/null +++ b/docs/teaching/exercises/figures/gui/LogAdapter.java @@ -0,0 +1,25 @@ +/* ******************************************************************* + * 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 figures.gui; + +import support.Log; + +aspect LogAdapter { + + before(String s): call(void Log.log(String)) && args(s) { + if (Main.panel != null) { + Main.panel.cp.println(s); + } + } +} diff --git a/docs/teaching/exercises/figures/gui/Main.java b/docs/teaching/exercises/figures/gui/Main.java new file mode 100644 index 000000000..c2d41c3b0 --- /dev/null +++ b/docs/teaching/exercises/figures/gui/Main.java @@ -0,0 +1,31 @@ +/* ******************************************************************* + * 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 figures.gui; + +import javax.swing.*; +import support.Log; + +public class Main { + static FigurePanel panel; + + public static void main(String[] args) { + JFrame figureFrame = new JFrame("Figure Editor"); + panel = new FigurePanel(); + figureFrame.setContentPane(panel); + figureFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + figureFrame.pack(); + figureFrame.setVisible(true); + } + +} diff --git a/docs/teaching/exercises/guibase.lst b/docs/teaching/exercises/guibase.lst new file mode 100644 index 000000000..0a9371462 --- /dev/null +++ b/docs/teaching/exercises/guibase.lst @@ -0,0 +1,5 @@ +-argfile +base.lst +figures/gui/FigurePanel.java +figures/gui/Main.java +figures/gui/LogAdapter.java \ No newline at end of file diff --git a/docs/teaching/exercises/index.html b/docs/teaching/exercises/index.html new file mode 100644 index 000000000..4dff3dae0 --- /dev/null +++ b/docs/teaching/exercises/index.html @@ -0,0 +1,769 @@ + + +AspectJ Tutorial Exercises + + + +

AspectJ Tutorial Exercises

+ +

Organization

+ +

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.

+ +

We have made 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 +setpaths.bat or source setpaths to export +some other needed environment variables.

+ +

All the files in the program are listed in base.lst, including +test cases and an empty answer aspect, +answers/Answer.java. Therefore, if you write your +answers there, all you need to do is compile base.lst, either in an +IDE or with

+ +
+$ ajc -Xlint -argfile base.lst
+
+ +

Before you move onto another exercise, though, make sure to copy +your answer into a different file so we can discuss the answers +together: +

+ +
+> copy answers/Answer.java answers/2a.java  (Windows)
+$ cp answers/Answer.java answers/2a.java    (Linux)
+
+ +

If you want to put your answer in a different file, say, +answers/Answer2a.java, you can compile with

+ +
+$ ajc -Xlint -argfile base.lst answers/Answer2a.java
+
+ +

In any case, after building the system, you should invoke Java on +the compiled test class. On the command-line, this this would be

+ +
+$ java tests.Test2a
+
+ +

(For these exercises, when we give examples of execution we will +show the command-line use, but of course if you are using JBuilder, +Forte/NetBeans, Emacs, or Eclipse, use the appropriate compile and +execute tools.)

+ +

The default test, tests.Test, performs some +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, +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 +duplicate some code.

+ +
+ +

1. Static Invariants

+ +

a. Catch old tracing

+ +

The way that we are all taught to print "hello world" from Java is +to use System.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. +

+ +

When you use this on the given system, you'll find one incorrect +trace in SlothfulPoint. +

+ +
+$ ajc -argfile base.lst
+./figures/SlothfulPoint.java:29:9: illegal access to System.out
+        System.out.println("Slothful moving");
+               ^
+1 errors
+
+ +

Remove the illegal tracing call. +

+ +

Make sure your program still passes the JUnit test +tests.Test (which it should also pass at the beginning of +all exercises) before continuing.

+ +
+$ java tests.Test
+....
+Time: 0.076
+
+OK (4 tests)
+
+ +

Answer: +

+ +
+package answers;
+
+import figures.*;
+
+aspect Answer1a {
+    declare error
+        : get(java.io.PrintStream System.out) && within(figures..*)
+        : "illegal access to System.out";
+}
+
+ +

Note that this answer does not say that the call to the +println() method is incorrect, rather, that the field get +of the out field is illegal. This will also catch those +users who bind System.out to a static field to save typing.

+ + +

b. Mandate setters

+ +

One common coding convention is that no private field should be +set outside of setter methods. Write an aspect to warn at compile +time when such an illegal assignment expression exists.

+ +

This is going to look like +

+ +
+aspect A {
+    declare warning: <pointcut here> : "bad field set";
+}
+
+ +

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 text of the setter (a setter is +a method that looks like "void set*(..)"), so check out the quick +reference for set and withincode primitive +pointcuts. )

+ +

Make sure your program still passes the JUnit test +tests.Test before continuing, and that you see all of the +following warning messages. You'll notice a LOT of warnings here. +Wait to fix them until the next exercise... +

+ +
+.\figures\Box.java:17:9: bad field set (warning)
+        _p0 = new Point(x0, y0);
+        ^
+.\figures\Box.java:18:9: bad field set (warning)
+        _p1 = new Point(x0+width, y0);
+        ^
+.\figures\Box.java:19:9: bad field set (warning)
+        _p2 = new Point(x0+width, y0+height);
+        ^
+.\figures\Box.java:20:9: bad field set (warning)
+        _p3 = new Point(x0, y0+height);
+        ^
+.\figures\Group.java:16:23: bad field set (warning)
+        this._members = new ArrayList();
+                      ^
+.\figures\Line.java:15:9: bad field set (warning)
+        _p1 = p1;
+        ^
+.\figures\Line.java:16:9: bad field set (warning)
+        _p2 = p2;
+        ^
+.\figures\Point.java:15:9: bad field set (warning)
+        _x = x;
+        ^
+.\figures\Point.java:16:9: bad field set (warning)
+        _y = y;
+        ^
+.\figures\Point.java:28:9: bad field set (warning)
+        _x += dx;
+        ^
+.\figures\Point.java:29:9: bad field set (warning)
+        _y += dy;
+        ^
+
+ + +

c. Refine setters mandate

+ +

Look at some of the warnings. 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.

+ +

You'll want to add another withincode primitive +pointcut to deal with the constructors. +

+ +

After you specify your pointcut correctly, you'll still find that +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;
+        ^
+2 errors
+
+ +

(If you see more, go back to 1b; you may be capturing sets to +too many fields.) +

+ +

Rewrite these two occurrences so as not to violate +the convention. Make sure your program still passes the JUnit test +tests.Test before continuing.

+ +

d. Re-refine setters mandate

+ +

In part (c), you rewrote the code to fit the convention enforced +by the aspect. It may be that this code doesn't violate the convention +of your mythical organization. Try to instead fix the pointcut so it +doesn't signal an error for these two assignments, and then change +your code back to making the assignments.

+ +

Make sure your program still passes the JUnit test +tests.Test before continuing.

+ +

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.

+ + + + +
+ +

2. Dynamic invariants

+ + +

a. Check a simple precondition

+ +

Write an aspect to throw an IllegalArgumentException +whenever an attempt is made to set one of Point's +int fields to a value that is either too large (greater +than FigureElement.MAX_VALUE) or too small (less than +FigureElement.MIN_VALUE).

+ +

This should make the test case of tests.Test2a pass, +which wouldn't without your aspect. So before compiling in the +aspect, +

+ +
+$ ajc -Xlint -argfile base.lst
+
+$ java tests.Test2a
+.F.F.F....
+Time: 0.099
+There were 3 failures:
+1) testTooSmall(tests.Test2a)junit.framework.AssertionFailedError: should have thrown IllegalArgumentException
+2) testTooBig(tests.Test2a)junit.framework.AssertionFailedError: should have thrown IllegalArgumentException
+3) testMove(tests.Test2a)junit.framework.AssertionFailedError: should have thrown IllegalArgumentException
+
+FAILURES!!!
+Tests run: 7,  Failures: 3,  Errors: 0
+
+ +

But after compiling in the aspect... +

+ +
+$ ajc -Xlint -argfile base.lst
+
+$ java tests.Test2a
+.......
+Time: 0.097
+
+OK (7 tests)
+
+ +

Answer: +

+ +
+package answers;
+
+import figures.*;
+
+aspect Answer2a {
+    before(int newValue): set(int Point.*) && args(newValue) {
+        if (newValue < FigureElement.MIN_VALUE) {
+            throw new IllegalArgumentException("too small");
+        } else if (newValue > FigureElement.MAX_VALUE) {
+            throw new IllegalArgumentException("too large");
+        }
+    }
+}
+
+ +

b. Check another precondition

+ +

Group is a FigureElement class that +encapsulates groups of other figure elements. As such, only actual +figure element objects should be added to Group objects. Write +an aspect to throw an IllegalArgumentException whenever +Group.add() is called with a +null value. If you look at the source code for +tests/Test2b.java, you'll see an example of the desired behavior, +i.e.

+ +
+    public void testNull() {
+        try {
+	    g.add(null);
+            fail("should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException ea) {
+        }
+    }
+
+ +

For each of these exercises, you'll find that the corresponding +test case provides that most concrete example of the desired behavior +for your aspect. Please avail yourself of this resource.

+ +

With this aspect in place, your code should pass +tests.Test2b. +

+ +

c. Check yet another precondition

+ +

Another constraint on a well-formed group is that it should not +contain itself as a member (though it may contain other groups). Write +an aspect to throw an IllegalArgumentException whenever +an attempt is made to call Group.add() on a +null value, or on the group itself.

+ +

You will want to use a target pointcut to expose the +Group object that is the target of the add +call. +

+ +

With this aspect in place, your code should pass +tests.Test2c. +

+ +

d. Check a simple postcondition

+ +

One of the simplest postconditions to check is that a setter +actually sets its value. Write an aspect that throws a +java.lang.RuntimeException if, after calling +setX() on SlothfulPoint objects, +getX() doesn't return the new value.

+ +

You'll want to use an args pointcut to expose the +argument to setX() and a target pointcut to +expose the SlothfulPoint object itself (so you can later +call getX() on it). +

+ +

An interesting question to think about for discussion is whether +this postcondition should apply when getX() throws an exception, or +when it returns normally, or both?

+ +

With this aspect in place, your code should pass +tests.Test2d. +

+ +

e. Check invariant

+ +

There is a method on the Box class, void +checkBoxness(), that checks whether the four points making up a +box are correctly positioned relative to each other (i.e., they form a +rectangle). Write an aspect that will make sure that after every time +the void move(int, int) method on Box is +called, that you also call Box.checkBoxness() to ensure +that the move didn't break this invariant.

+ +

With this aspect in place, your code should pass +tests.Test2e. +

+ +

f. Refine your invariant

+ +

move is not the only interesting method on +Box. It may be that a box gets malformed between calls +to move. So instead of checking boxness only +after the move method of Box, check +after the call to every one of Box's public methods. +

+ +

When testing this aspect, you may find yourself facing a +StackOverflowException. If so, carefully look at your +pointcuts. Needless to say, there should not be an infinite loop in +your program. You might want to look at using a within +pointcut for a filter.

+ +

(You might even find that this test case aborts with no message, +i.e., +

+ +
+$ java tests.test2f
+.
+$
+
+ +

this is a bug in Sun's JVM where a particular stack overflow +causes the VM to abort.) +

+ +

Make sure to pass the JUnit test tests.Test2f +before continuing.

+ + +

g. Assure input

+ +

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 an args pointcut, and +proceed with the trimmed value. Becuase this is tricky, +type in the below aspect... the trick for this exercise is not to come +up with an answer, but to understand the answer.

+ +

Make sure to pass the JUnit test tests.Test2g +before continuing.

+ +

Answer: +

+ +
+package answers;
+
+import figures.*;
+
+aspect Answer2g {
+    int around(int val):
+            (set(int Point._x) || set(int Point._y))
+            && args(val) {
+        return proceed(trim(val));
+    }
+
+    private int trim(int val) {
+        return Math.max(Math.min(val, FigureElement.MAX_VALUE),
+                        FigureElement.MIN_VALUE);
+    }
+}
+
+ + +

h. Check another invariant

+ +

FigureElement objects have a getBounds() +method that returns a java.awt.Rectangle representing the +bounds of the object. An important postcondition of the +move operation is that the figure element's bounds +rectangle should move by the same amount as the figure itself. Write +an aspect to check for this postcondition -- throw an +IllegalStateException if it is violated.

+ +

Note that because we're dealing with how the bounds changes during +move, we need some way of getting access to the bounds both before +and after the move, in one piece of advice. Also, note that +you can create a copy of a figure element's bounds rectangle with +new Rectangle(fe.getBounds()), and you can move a bounds +rectangle rect with rect.translate(dx, +dy).

+ +

Make sure to pass the JUnit test tests.Test2h +before continuing.

+ + +

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.

+ +

a. Simple tracing

+ +

Write an aspect to trace whenever a Point is moved. +To do this, use the utility class Log (with an import +from support.Log) and call

+ +
+Log.log("moving")
+
+ +

This will write the string "moving", followed by a semicolon +terminator, to the Log. For example, with your aspect enabled, +

+ +
+Point p1 = new Point(10, 100);
+p1.move(37, 8);
+System.out.println(Log.getString());
+
+ +

should print out "moving;". +

+ +

Test this with the JUnit test case tests.Test3a. +Without adding any aspects, this test should fail:

+ +
+$ ajc -Xlint -argfile base.lst 
+$ java tests.Test3a
+..F.......
+Time: 0.07
+There was 1 failure:
+1) testMovePointLog(tests.Test3a)junit.framework.AssertionFailedError: expected:<set;> but was:<>
+        at tests.Test3a.testMovePointLog(Test1a.java:30)
+        at tests.Test3a.main(Test1a.java:16)
+
+FAILURES!!!
+Tests run: 9,  Failures: 1,  Errors: 0
+
+ +

But with the proper aspect added to the compilation, (in this +case, answers/Answer3a.java, but you should feel free to +use more evocative names), the test should pass

+ +
+$ ajc -Xlint -argfile base.lst answers/Answer3a.java
+$ java tests.Test3a
+.........
+Time: 0.089
+
+OK (9 tests)
+
+ +

Answer: +

+ +
+package answers;
+
+import support.Log;
+import figures.*;
+
+aspect Answer3a {
+    before(): execution(void Point.move(int, int)) {
+        Log.log("moving");
+    }
+}
+
+ +

b. More complex tracing

+ +

Write an aspect to trace whenever a Point is added to +a group (including initially). To do this, use the utility class +Log (with an import from support.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());
+
+ +

should print out "adding Point;adding Point;". +

+ +

Hint: The args pointcut allows you to select join points +based on the type of a parameter to a method call.

+ +

Test this with the JUnit test case tests.Test3b. + + +

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 with Point objects, and then +work with that field, setting it appropriately when the +Point is added to a Group (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.

+ + + + +
+ + +

4. Caching

+ +

Computation of the bounding box of Group objects +needs to deal with all aggregate parts of the group, and this +computation can be expensive. In this section, we will explore +various ways of reducing this expense.

+ +

Optional: In all of these exercises, you should +only deal with points that are added directly to Groups, rather than +those that are added "indirectly" through Lines and Boxes. You should +handle those points contained in Lines and Boxes only if time permits. +

+ +

a. Make a constant override

+ +

Group's getBounds() method could be +understood to be a conservative approximation of the bounding box of a +group. If that is true, then it would be a legal (and much faster) +implementation of getBounds() to simply always return a +rectangle consisting of the entire canvas, that is +

+ +
+new Rectangle(FigureElement.MIN_VALUE, FigureElement.MIN_VALUE, 
+              FigureElement.MAX_VALUE - FigureElement.MIN_VALUE,
+              FigureElement.MAX_VALUE - FigureElement.MIN_VALUE)
+
+ +

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

+ +

Your code should pass the JUnit test case +tests.Test4a with this change. +

+ +

Answer: +

+ +
+package answers;
+
+import figures.*;
+import java.awt.Rectangle;
+
+aspect Answer4a {
+    private Rectangle wholeCanvas =
+        new Rectangle(FigureElement.MIN_VALUE, FigureElement.MIN_VALUE, 
+                      FigureElement.MAX_VALUE - FigureElement.MIN_VALUE,
+                      FigureElement.MAX_VALUE - FigureElement.MIN_VALUE);
+
+    Rectangle around(): execution(Rectangle Group.getBounds()) {
+        return wholeCanvas;
+    }
+}
+
+ +

b. Make a constant cache

+ +

Instead of making the (very) conservative approximation of +getBounds() from part (a), write an aspect instead that +remembers the return value from the first time +getBounds() has been called on a Group, and +returns that first Rectangle for every subsequent +call.

+ +

Hint: You can use an inter-type declaration to keep some +state for every Group object.

+ +

Your code should pass the JUnit test case +tests.Test4b with this change. +

+ + +

c. Invalidate, part 1

+ +

While caching in this way does save computation, it will lead to +incorrect bounding boxes if a Group is ever moved. +Change your aspect so that it invalidates the cache whenever the +move() method of Group is called. +

+ +

Your code should pass the JUnit test case +tests.Test4c with this change. +

+ +

d. Invalidate, part 2

+ +

Of course, part (c) didn't really solve the problem. What if a +Point that is part of a Group moves? +Whenever either of a Point's fields are set it should invalidate the +caches of all enclosing groups. Use your solution to problem 3c to +modify your invalidation criteria in this way, but note that this is +slightly different than the problem in 3c: Here you care about fields, +where there you cared about method calls.

+ +

Your code should pass the JUnit test case +tests.Test4d with this change. +

+ +

e. Invalidate, part 3

+ +

Did you really do part (d) correctly? Run the JUnit test +tests.Test4e to see. If you pass, congratulations, now +go help other people. Otherwise, you have fallen prey to our cruel +trap: Remember that whenever a point moves it should invalidate the +caches of all enclosing groups.

+ +
+ diff --git a/docs/teaching/exercises/pre-letter.txt b/docs/teaching/exercises/pre-letter.txt new file mode 100644 index 000000000..4833beeb5 --- /dev/null +++ b/docs/teaching/exercises/pre-letter.txt @@ -0,0 +1,130 @@ +Dear OOPSLA 2002 attendee; + +We have you listed as being registered for tutorial T40, +Aspect-oriented programming with AspectJ. We are excited about giving +this tutorial, and hope you will enjoy the presentation, exercises and +discussion we have prepared. + +As with our past tutorials of this form, in the afternoon we would +like to break the attendees into groups of two or three and work +through a number of AspectJ exercises together. + +We will be bringing media and making ourselves available during breaks +for help with setup, but in order to jump straight in and give you the +most we can from this tutorial, it would really help us if many of you +had an AspectJ environment installed early. + +This message contains basic instructions on where to get some needed +tools. These instructions will not take much time. + +If you are planning to bring a laptop to the tutorial, would you +please take the time to do the steps outlined in this message? + +If you're not planning to, you might want to install an AspectJ +environment on your desktop anyway and try the instructions below, so +you will be comfortable when we meet on Wednesday. + +[If you already have a working AspectJ environment and are familliar +with it, we still recommend that you upgrade to 1.0.6 and follow the +steps below] + +Thank you, and please don't hesitate to contact us (at +support@aspectj.org) if you have any questions. See you on +Wednesday... + +-Erik Hilsdale, + Jim Hugunin, + and the whole AspectJ Team + + +Getting Ready for T40, Aspect-oriented programming with AspectJ +-------------------------------------- + +Overview: + + 0. Install AspectJ + 1. Download JUnit and put it on your classpath + 2. Test your setup + +------------------------------ +0. AspectJ + +Download the AspectJ 1.0.6 from + + http://aspectj.org/dl + +You should definitly download and intstall the tools package and the +docs package. If you plan to use JBuilder, Forte/NetBeans, Emacs, or +Eclipse for your development, you should download the appropriate +plugin. + + +------------------------------ +1. JUnit + +We use the JUnit framework for testing our exercises. Download JUnit +from + + http://www.junit.org + +and place junit.jar on your CLASSPATH. + + +------------------------------ +2. Test your setup + +a. Create a file "Hello.java" with this class: + + class Hello { + public static void main(String[] args) { + System.err.println(getHelloString()); + } + public static String getHelloString() { + return "Hello, WORLD"; + } + } + +b. Compile the class with ajc and run it... + + > ajc Hello.java + > java Hello + Hello, WORLD + +c. Create a file "TestHello.java" with this class: + + public class TestHello extends junit.framework.TestCase { + public TestHello(String name) { + super(name); + } + public static void main(String[] args) { + junit.textui.TestRunner.run(TestHello.class); + } + public void testHello() { + assertEquals("Hello, OOPSLA", Hello.getHelloString()); + } + } + +d. Compile the class with ajc and run it... + + > ajc TestHello.java + > java TestHello + .F + Time: 0.01 + There was 1 failure: + 1) testHello(TestHello)junit.framework.ComparisonFailure: + expected:<...OOPSLA> but was:<...WORLD> + at TestHello.testHello(TestHello.java:9) + at TestHello.main(TestHello.java:6) + + FAILURES!!! + Tests run: 1, Failures: 1, Errors: 0 + +e. Oops... the test case seems to want a different string than the + tested class. Fix that, compile whichever file you changed with + ajc, run the tester again, and you're done. Thanks! + + > java TestHello + . + Time: 0 + + OK (1 test) diff --git a/docs/teaching/exercises/setpaths b/docs/teaching/exercises/setpaths new file mode 100644 index 000000000..1e9a858c4 --- /dev/null +++ b/docs/teaching/exercises/setpaths @@ -0,0 +1,14 @@ +#!/bin/sh + +# Change this to be the full path for this directory +EXTRACTION=$HOME/aj-oopsla + +if [ "$JAVA_HOME" = "" ] +then + echo Please remember to manually set $JAVA_HOME to + echo the location of your java installation +fi + +export ASPECTJ_HOME=$EXTRACTION/aspectj +export PATH=$ASPECTJ_HOME/bin:$PATH +export CLASSPATH=.:$ASPECTJ_HOME/lib/aspectjrt.jar:$EXTRACTION/junit.jar diff --git a/docs/teaching/exercises/setpaths.bat b/docs/teaching/exercises/setpaths.bat new file mode 100644 index 000000000..bfb9a8046 --- /dev/null +++ b/docs/teaching/exercises/setpaths.bat @@ -0,0 +1,15 @@ +@echo off + +rem Change this to be the full path for this directory +set EXTRACTION=c:\aj-oopsla + +if exist "%JAVA_HOME%\bin\java.exe" goto haveJava +if exist "%JAVA_HOME%\bin\java.bat" goto haveJava +if exist "%JAVA_HOME%\bin\java" goto haveJava +echo java does not exist as %JAVA_HOME%\bin\java +echo please fix the JAVA_HOME environment variable + +:haveJava +set ASPECTJ_HOME=%EXTRACTION%\aspectj +set PATH=%ASPECTJ_HOME%\bin;%PATH% +set CLASSPATH=.;%ASPECTJ_HOME%\lib\aspectjrt.jar;%EXTRACTION%\junit.jar diff --git a/docs/teaching/exercises/support/Log.java b/docs/teaching/exercises/support/Log.java new file mode 100644 index 000000000..37d4d7ad2 --- /dev/null +++ b/docs/teaching/exercises/support/Log.java @@ -0,0 +1,45 @@ +/* ******************************************************************* + * 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 support; + +public class Log { + static StringBuffer data = new StringBuffer(); + + public static void traceObject(Object o) { + throw new UnsupportedOperationException(); + } + + public static void log(String s) { + data.append(s); + data.append(';'); + } + + 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 String getString() { + return data.toString(); + } + + public static void clear() { + data.setLength(0); + } +} diff --git a/docs/teaching/exercises/tests/Test.java b/docs/teaching/exercises/tests/Test.java new file mode 100644 index 000000000..e4f5b60f9 --- /dev/null +++ b/docs/teaching/exercises/tests/Test.java @@ -0,0 +1,80 @@ +/* ******************************************************************* + * 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 junit.framework.*; + +public class Test extends TestCase { + public Test(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test.class); + } + + Box bb; + Point p1; + Point p2; + Line l1; + SlothfulPoint sloth1; + Group g; + + public void setUp() { + p1 = new Point(10, 100); + p2 = new Point(20, 200); + l1 = new Line(p1, p2); + bb = new Box(5, 5, 10, 10); + sloth1 = new SlothfulPoint(0, 0); + g = new Group(p1); + } + + public final void testCreate() { + assertEquals(p1.getX(), 10); + assertEquals(p1.getY(), 100); + + assertEquals(l1.getP1(), p1); + assertEquals(l1.getP2(), p2); + } + + public final void testSetPoint() { + p1.setX(20); + assertEquals(p1.getX(), 20); + assertEquals(p1.getY(), 100); + + p1.setY(10); + assertEquals(p1.getX(), 20); + assertEquals(p1.getY(), 10); + } + + public final void testMoveLine1() { + l1.move(40, 40); + assertEquals(l1.getP1(), p1); + assertEquals(l1.getP2(), p2); + + assertEquals(p1.getX(), 50); + assertEquals(p1.getY(), 140); + + assertEquals(p2.getX(), 60); + assertEquals(p2.getY(), 240); + } + + public final void testMoveLine2() { + l1.move(-10, -10); + assertEquals(p1.getX(), 0); + assertEquals(p1.getY(), 90); + + assertEquals(p2.getX(), 10); + assertEquals(p2.getY(), 190); + } +} diff --git a/docs/teaching/exercises/tests/Test1a.java b/docs/teaching/exercises/tests/Test1a.java new file mode 100644 index 000000000..b8bb2e120 --- /dev/null +++ b/docs/teaching/exercises/tests/Test1a.java @@ -0,0 +1,55 @@ +/* ******************************************************************* + * 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.*; + +public class Test1a extends Test { + public Test1a(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test1a.class); + } + + public void setUp() { + Log.clear(); + super.setUp(); + } + + public void testCreateLog() { + assertEquals("", Log.getString()); + } + + public void testSetXPointLog() { + p1.setX(20); + assertEquals("set;", Log.getString()); + } + + public void testSetYPointLog() { + p1.setY(10); + assertEquals("", Log.getString()); + } + + public void testGetYPointLog() { + p1.getY(); + assertEquals("", Log.getString()); + } + + public void testMoveLineLog() { + l1.move(40, 40); + assertEquals("", Log.getString()); + } +} diff --git a/docs/teaching/exercises/tests/Test2a.java b/docs/teaching/exercises/tests/Test2a.java new file mode 100644 index 000000000..21ce08a9f --- /dev/null +++ b/docs/teaching/exercises/tests/Test2a.java @@ -0,0 +1,55 @@ +/* ******************************************************************* + * 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 junit.framework.*; + +public class Test2a extends Test { + public Test2a(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test2a.class); + } + + public void setUp() { + super.setUp(); + } + + public void testTooSmall() { + try { + p1.setX(-10); + fail("should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException ea) { + } + } + + + public void testTooBig() { + try { + p1.setY(1000); + fail("should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException ea) { + } + } + + + public void testMove() { + try { + l1.move(-500, -500); + fail("should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException ea) { + } + } +} diff --git a/docs/teaching/exercises/tests/Test2b.java b/docs/teaching/exercises/tests/Test2b.java new file mode 100644 index 000000000..63a10b7b0 --- /dev/null +++ b/docs/teaching/exercises/tests/Test2b.java @@ -0,0 +1,37 @@ +/* ******************************************************************* + * 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 junit.framework.*; + +public class Test2b extends Test { + public Test2b(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test2b.class); + } + + public void setUp() { + super.setUp(); + } + + public void testNull() { + try { + g.add(null); + fail("should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException ea) { + } + } +} diff --git a/docs/teaching/exercises/tests/Test2c.java b/docs/teaching/exercises/tests/Test2c.java new file mode 100644 index 000000000..cfcb0d1d8 --- /dev/null +++ b/docs/teaching/exercises/tests/Test2c.java @@ -0,0 +1,45 @@ +/* ******************************************************************* + * 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 junit.framework.*; + +public class Test2c extends Test { + public Test2c(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test2c.class); + } + + public void setUp() { + super.setUp(); + } + + public void testNull() { + try { + g.add(null); + fail("should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException ea) { + } + } + + public void testSelf() { + try { + g.add(g); + fail("should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException ea) { + } + } +} diff --git a/docs/teaching/exercises/tests/Test2d.java b/docs/teaching/exercises/tests/Test2d.java new file mode 100644 index 000000000..89e47c088 --- /dev/null +++ b/docs/teaching/exercises/tests/Test2d.java @@ -0,0 +1,37 @@ +/* ******************************************************************* + * 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 junit.framework.*; + +public class Test2d extends Test { + public Test2d(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test2d.class); + } + + public void setUp() { + super.setUp(); + } + + public void testSetting() { + try { + sloth1.setX(10); + fail("should have thrown RuntimeException"); + } catch (RuntimeException ea) { + } + } +} diff --git a/docs/teaching/exercises/tests/Test2e.java b/docs/teaching/exercises/tests/Test2e.java new file mode 100644 index 000000000..57af08501 --- /dev/null +++ b/docs/teaching/exercises/tests/Test2e.java @@ -0,0 +1,42 @@ +/* ******************************************************************* + * 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 junit.framework.*; + +public class Test2e extends Test { + public Test2e(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test2e.class); + } + + public void setUp() { + super.setUp(); + } + + public void testEasy() { + Box sq = new Box(0, 0, 10, 10); + sq.move(5,5); + assertEquals(sq.getP0().getX(), 5); + assertEquals(sq.getP0().getY(), 5); + + try { + sq.getP0().setX(100); + sq.move(37, 1); + fail("should have thrown IllegalStateException"); + } catch (IllegalStateException e) { } + } +} diff --git a/docs/teaching/exercises/tests/Test2f.java b/docs/teaching/exercises/tests/Test2f.java new file mode 100644 index 000000000..da63b12e1 --- /dev/null +++ b/docs/teaching/exercises/tests/Test2f.java @@ -0,0 +1,42 @@ +/* ******************************************************************* + * 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 junit.framework.*; + +public class Test2f extends Test { + public Test2f(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test2f.class); + } + + public void setUp() { + super.setUp(); + } + + public void testEasy() { + Box sq = new Box(0, 0, 10, 10); + sq.move(5,5); + assertEquals(sq.getP0().getX(), 5); + assertEquals(sq.getP0().getY(), 5); + + try { + sq.getP0().setX(100); + sq.getP1(); + fail("should have thrown IllegalStateException"); + } catch (IllegalStateException e) { } + } +} diff --git a/docs/teaching/exercises/tests/Test2g.java b/docs/teaching/exercises/tests/Test2g.java new file mode 100644 index 000000000..7ed9ba341 --- /dev/null +++ b/docs/teaching/exercises/tests/Test2g.java @@ -0,0 +1,42 @@ +/* ******************************************************************* + * 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 junit.framework.*; + +public class Test2g extends Test { + public Test2g(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test2g.class); + } + + public void setUp() { + super.setUp(); + } + + public void testBounds() { + p1.setX(FigureElement.MAX_VALUE + 1); + assertEquals(FigureElement.MAX_VALUE, p1.getX()); + p1.setY(FigureElement.MIN_VALUE - 1); + assertEquals(FigureElement.MIN_VALUE, p1.getY()); + } + + public void testBox() { + Box s = new Box(50, 50, 20000, 20000); + assertEquals(FigureElement.MAX_VALUE, s.getP2().getX()); + assertEquals(FigureElement.MAX_VALUE, s.getP2().getY()); + } +} diff --git a/docs/teaching/exercises/tests/Test2h.java b/docs/teaching/exercises/tests/Test2h.java new file mode 100644 index 000000000..9ed695d9b --- /dev/null +++ b/docs/teaching/exercises/tests/Test2h.java @@ -0,0 +1,42 @@ +/* ******************************************************************* + * 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 junit.framework.*; + +public class Test2h extends Test { + public Test2h(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test2h.class); + } + + public void setUp() { + super.setUp(); + } + + public void testSloth() { + FigureElement fe = new SlothfulPoint(10, 10); + try { + fe.move(10, 10); + fail("should have thrown IllegalStateException"); + } catch (IllegalStateException e) { } + } + + public void movePoints() { + p1.move(30, 45); + p2.move(10, 33); + } +} diff --git a/docs/teaching/exercises/tests/Test3a.java b/docs/teaching/exercises/tests/Test3a.java new file mode 100644 index 000000000..3cb063251 --- /dev/null +++ b/docs/teaching/exercises/tests/Test3a.java @@ -0,0 +1,49 @@ +/* ******************************************************************* + * 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.*; + +public class Test3a extends Test { + public Test3a(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test3a.class); + } + + public void setUp() { + Log.clear(); + super.setUp(); + } + + public void testCreateLog() { + assertEquals("", Log.getString()); + } + + public void testMovePointLog() { + p1.move(20, 30); + assertEquals("moving;", Log.getString()); + } + + public void testSetYPointLog() { + assertEquals("", Log.getString()); + } + + public void testGetYPointLog() { + p1.getY(); + assertEquals("", Log.getString()); + } +} diff --git a/docs/teaching/exercises/tests/Test3b.java b/docs/teaching/exercises/tests/Test3b.java new file mode 100644 index 000000000..6ec933cee --- /dev/null +++ b/docs/teaching/exercises/tests/Test3b.java @@ -0,0 +1,54 @@ +/* ******************************************************************* + * 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.*; + +public class Test3b extends Test { + public Test3b(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test3b.class); + } + + public void setUp() { + super.setUp(); + Log.clear(); + } + + public void testCreateLog() { + assertEquals("", Log.getString()); + } + + public void testCreateWithPointLog() { + g = new Group(p1); + assertEquals("adding Point;", Log.getString()); + } + + public void testCreateWithoutPointLog() { + g = new Group(l1); + assertEquals("", Log.getString()); + } + + public void testAddPointLog() { + g.add(p1); + assertEquals("adding Point;", Log.getString()); + } + public void testAddNonPointLog() { + g.add(l1); + assertEquals("", Log.getString()); + } +} diff --git a/docs/teaching/exercises/tests/Test3c.java b/docs/teaching/exercises/tests/Test3c.java new file mode 100644 index 000000000..6c135e91c --- /dev/null +++ b/docs/teaching/exercises/tests/Test3c.java @@ -0,0 +1,47 @@ +/* ******************************************************************* + * 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.*; + +public class Test3c extends Test { + public Test3c(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test3c.class); + } + + public void setUp() { + Log.clear(); + super.setUp(); + } + + public void testCreateLog() { + assertEquals("", Log.getString()); + } + + public void testMoveLonePoint() { + p1 = new Point(0, 0); + p1.move(37, 88); + assertEquals("moving as a part of null;", Log.getString()); + } + + public void testMoveGroupedPoint() { + g = new Group(p1); + p1.move(0, 0); + assertEquals("moving as a part of " + g + ";", Log.getString()); + } +} diff --git a/docs/teaching/exercises/tests/Test4a.java b/docs/teaching/exercises/tests/Test4a.java new file mode 100644 index 000000000..ddb18415a --- /dev/null +++ b/docs/teaching/exercises/tests/Test4a.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 java.awt.Rectangle; + +import junit.framework.*; + +public class Test4a extends Test { + Rectangle wholeCanvas = + new Rectangle(FigureElement.MIN_VALUE, FigureElement.MIN_VALUE, + FigureElement.MAX_VALUE, FigureElement.MAX_VALUE); + + public Test4a(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test4a.class); + } + + public void setUp() { + super.setUp(); + } + + public void testGroupBounds() { + assertEquals(g.getBounds(), wholeCanvas); + } +} diff --git a/docs/teaching/exercises/tests/Test4b.java b/docs/teaching/exercises/tests/Test4b.java new file mode 100644 index 000000000..609289508 --- /dev/null +++ b/docs/teaching/exercises/tests/Test4b.java @@ -0,0 +1,70 @@ +/* ******************************************************************* + * 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 java.awt.Rectangle; + +import junit.framework.*; + +public class Test4b extends Test { + + public Test4b(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test4b.class); + } + + public void setUp() { + super.setUp(); + } + + public void testBasicEquality() { + assertTrue(g.getBounds() == g.getBounds()); + } + + public void testEqualityAfterAddition() { + Point p0 = new Point(1, 2); + Point p1 = new Point(2, 3); + + Group g0 = new Group(p0); + Group g1 = new Group(p1); + + Rectangle r0 = g0.getBounds(); + Rectangle r1 = g1.getBounds(); + assertTrue(r0 != r1); + g0.add(new Point(37, 90)); + assertTrue(g0.getBounds() == r0); + assertTrue(g1.getBounds() != r0); + assertTrue(g0.getBounds() != r1); + assertTrue(g1.getBounds() == r1); + + g1.add(new Point(4, 8)); + assertTrue(g0.getBounds() == r0); + assertTrue(g1.getBounds() != r0); + assertTrue(g0.getBounds() != r1); + assertTrue(g1.getBounds() == r1); + } + + public void testNotWholeCanvas() { + assertTrue("bounds for this group should not be the whole canvas", + g.getBounds().getWidth() < + (FigureElement.MAX_VALUE - FigureElement.MIN_VALUE)); + assertTrue("bounds for this group should not be the whole canvas", + g.getBounds().getHeight() < + (FigureElement.MAX_VALUE - FigureElement.MIN_VALUE)); + + } +} + + diff --git a/docs/teaching/exercises/tests/Test4c.java b/docs/teaching/exercises/tests/Test4c.java new file mode 100644 index 000000000..b5bf8f708 --- /dev/null +++ b/docs/teaching/exercises/tests/Test4c.java @@ -0,0 +1,84 @@ +/* ******************************************************************* + * 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 java.awt.Rectangle; + +import junit.framework.*; + +public class Test4c extends Test { + + public Test4c(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test4c.class); + } + + public void setUp() { + super.setUp(); + } + + public void testBasicEquality() { + assertTrue(g.getBounds() == g.getBounds()); + } + + public void testEqualityAfterAddition() { + Point p0 = new Point(1, 2); + Point p1 = new Point(2, 3); + + Group g0 = new Group(p0); + Group g1 = new Group(p1); + + Rectangle r0 = g0.getBounds(); + Rectangle r1 = g1.getBounds(); + assertTrue(r0 != r1); + g0.add(new Point(37, 90)); + assertTrue(g0.getBounds() == r0); + assertTrue(g1.getBounds() != r0); + assertTrue(g0.getBounds() != r1); + assertTrue(g1.getBounds() == r1); + + g1.add(new Point(4, 8)); + assertTrue(g0.getBounds() == r0); + assertTrue(g1.getBounds() != r0); + assertTrue(g0.getBounds() != r1); + assertTrue(g1.getBounds() == r1); + } + + public void testEqualityAfterMove() { + Point p0 = new Point(1, 2); + Point p1 = new Point(2, 3); + + Group g0 = new Group(p0); + Group g1 = new Group(p1); + + Rectangle r0 = g0.getBounds(); + Rectangle r1 = g1.getBounds(); + assertTrue(r0 != r1); + assertTrue(g0.getBounds() == r0); + assertTrue(g1.getBounds() != r0); + assertTrue(g0.getBounds() != r1); + assertTrue(g1.getBounds() == r1); + + g0.move(3, 1); + Rectangle r00 = g0.getBounds(); + Rectangle r10 = g1.getBounds(); + + assertTrue(r10 != r00); + assertTrue(r0 != r00); + assertTrue(g0.getBounds() == r00); + } +} + + diff --git a/docs/teaching/exercises/tests/Test4d.java b/docs/teaching/exercises/tests/Test4d.java new file mode 100644 index 000000000..e4458c6a4 --- /dev/null +++ b/docs/teaching/exercises/tests/Test4d.java @@ -0,0 +1,81 @@ +/* ******************************************************************* + * 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 java.awt.Rectangle; + +import junit.framework.*; + +public class Test4d extends Test { + + public Test4d(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test4d.class); + } + + public void setUp() { + super.setUp(); + } + + public void testBasicEquality() { + assertTrue(g.getBounds() == g.getBounds()); + } + + public void testNonGroupMove() { + p1.move(3, 27); + } + + public void testEqualityAfterAddition() { + Rectangle r = g.getBounds(); + g.add(new Point(37, 90)); + assertTrue(g.getBounds() == r); + } + + public void testEqualityAfterMove() { + Point p0 = new Point(1, 2); + Point p1 = new Point(2, 3); + + Group g0 = new Group(p0); + Group g1 = new Group(p1); + + Rectangle r0 = g0.getBounds(); + Rectangle r1 = g1.getBounds(); + assertTrue(r0 != r1); + assertTrue(g0.getBounds() == r0); + assertTrue(g1.getBounds() != r0); + assertTrue(g0.getBounds() != r1); + assertTrue(g1.getBounds() == r1); + + p0.move(3, 1); + Rectangle r00 = g0.getBounds(); + Rectangle r10 = g1.getBounds(); + + assertTrue(r10 != r00); + assertTrue(r0 != r00); + assertTrue(g0.getBounds() == r00); + } + + public void testEqualityAfterMove0() { + g = new Group(p1); + Rectangle r0 = g.getBounds(); + assertTrue(g.getBounds() == r0); + p1.move(3, 1); + Rectangle r1 = g.getBounds(); + assertTrue(r0 != r1); + assertTrue(r1 == g.getBounds()); + } +} + + diff --git a/docs/teaching/exercises/tests/Test4e.java b/docs/teaching/exercises/tests/Test4e.java new file mode 100644 index 000000000..f6a3635d2 --- /dev/null +++ b/docs/teaching/exercises/tests/Test4e.java @@ -0,0 +1,68 @@ +/* ******************************************************************* + * 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 java.awt.Rectangle; + +import junit.framework.*; + +public class Test4e extends Test { + + public Test4e(String name) { super(name); } + + public static void main(String[] args) { + junit.textui.TestRunner.run(Test4e.class); + } + + public void setUp() { + super.setUp(); + } + + public void testBasicEquality() { + assertTrue(g.getBounds() == g.getBounds()); + } + + public void testNonGroupMove() { + p1.move(3, 27); + } + + public void testEqualityAfterAddition() { + Rectangle r = g.getBounds(); + g.add(new Point(37, 90)); + assertTrue(g.getBounds() == r); + } + + public void testEqualityAfterMove() { + g = new Group(p1); + Rectangle r0 = g.getBounds(); + assertTrue(g.getBounds() == r0); + p1.move(3, 1); + Rectangle r1 = g.getBounds(); + assertTrue(r0 != r1); + assertTrue(r1 == g.getBounds()); + } + + public void testSecondEnclosingGroup() { + g = new Group(p1); + Group h = new Group(g); + Rectangle r0 = h.getBounds(); + assertTrue(h.getBounds() == r0); + p1.move(3, 1); + Rectangle r1 = h.getBounds(); + assertTrue(r0 != r1); + assertTrue(r1 == h.getBounds()); + } +} + + diff --git a/docs/teaching/oneHour.ppt b/docs/teaching/oneHour.ppt new file mode 100644 index 000000000..c6a00c4e3 Binary files /dev/null and b/docs/teaching/oneHour.ppt differ diff --git a/docs/teaching/readme.txt b/docs/teaching/readme.txt new file mode 100644 index 000000000..f346cd414 --- /dev/null +++ b/docs/teaching/readme.txt @@ -0,0 +1,11 @@ +These presentations (oneHour.ppt, tutorial.ppt, and the teaching materials in exercises) are +Copyright (c) 1998-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 \ No newline at end of file diff --git a/docs/teaching/tutorial.ppt b/docs/teaching/tutorial.ppt new file mode 100644 index 000000000..0ba0c5b20 Binary files /dev/null and b/docs/teaching/tutorial.ppt differ