package figures; class Display { static void needsRepaint() { } } package figures; aspect DisplayUpdating { pointcut move(): call(void FigureElement.moveBy(int, int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() returning: move() && !cflowbelow(move()) { Display.needsRepaint(); } } package figures; aspect FactoryEnforcement { pointcut illegalNewFigElt(): call(FigureElement+.new(..)) && !withincode(FigureElement+ Figure.make*(..)); /* * declare error is not described in the CACM article. It is a * special declarative form of advice that says "Throw an error * at any join point matched by the specified pointcut, and * throw that error at compile time." This is useful for aspects * like this one that check design invariants in your code. * * See the comment in Main.java that says how to demonstrate the * effect of this aspect. */ declare error: illegalNewFigElt(): "Illegal figure element constructor call."; } package figures; interface FigureElement { public void moveBy(int dx, int dy); } package figures; import java.util.List; import java.util.LinkedList; class Figure { private List elements = new LinkedList(); public Point makePoint(int x, int y) { Point p = new Point(x, y); elements.add(p); return p; } public Line makeLine(Point p1, Point p2) { Line l = new Line(p1, p2); elements.add(l); return l; } } package figures; class Line implements FigureElement { private Point p1, p2; Line(Point p1, Point p2) { super(); this.p1 = p1; this.p2 = p2; } public Point getP1() { return p1; } public Point getP2() { return p2; } public void setP1(Point p1) { this.p1 = p1; } public void setP2(Point p2) { this.p2 = p2; } public void moveBy(int dx, int dy) { getP1().moveBy(dx, dy); getP2().moveBy(dx, dy); } } package figures; class Main { public static void main(String [] args) { Figure fig = new Figure(); Point p1 = fig.makePoint(2, 2); Point p2 = fig.makePoint(4, 4); Line l1 = fig.makeLine(p1, p2); /* * Uncomment the next line of code and re-compile the whole example * to see the FactoryEnforcement aspect do its thing. */ //Point p3 = new Point(2, 2); System.out.println(); System.out.println("Main is about to mark display dirty."); Display.needsRepaint(); System.out.println(); System.out.println("Main is about to move p1."); p1.setX(10); System.out.println(); System.out.println("Main is about to move l1."); l1.moveBy(2, 2); } } package figures; aspect PointBoundsChecking { static final int MIN_X = 0; static final int MAX_X = 100; static final int MIN_Y = 0; static final int MAX_Y = 100; before(Point p, int x): call(void Point.setX(int)) && target(p) && args(x) { checkX(x); } before(Point p, int y): call(void Point.setY(int)) && args(y) && target(p) { checkY(y); } before(Point p, int dx, int dy): call(void Point.moveBy(int, int)) && args(dx, dy) && target(p) { checkX(p.getX() + dx); checkY(p.getY() + dy); } void checkX(int x) { check("New x value illegal.", (MIN_X < x) && (x < MAX_X)); } void checkY(int y) { check("New y value illegal.", (MIN_Y < y) && (y < MAX_Y)); } void check(String description, boolean test) { if ( !test ) throw new Error(description); } } package figures; class Point implements FigureElement { private int x = 0, y = 0; Point(int x, int y) { super(); this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public void moveBy(int dx, int dy) { setX(getX() + dx); setY(getY() + dy); } } package figures; aspect Tracing { pointcut setXY(): call(void Point.setX(int)) || call(void Point.setY(int)); before(): setXY() { System.out.println("Entering:" + thisJoinPoint); } after() returning: call(void Display.needsRepaint()) && !within(DisplayUpdating) { System.out.print("Display was marked dirty outside of DisplayUpdating."); } after() returning: call(void Display.needsRepaint()) && within(DisplayUpdating) { System.out.print("Display was marked dirty by DisplayUpdating."); } }