diff options
author | wisberg <wisberg> | 2002-12-16 18:51:06 +0000 |
---|---|---|
committer | wisberg <wisberg> | 2002-12-16 18:51:06 +0000 |
commit | 144143c2970a1e874d74cdbd0f8c622d4282a3c3 (patch) | |
tree | b12383d3d9e76c7e1f25f7fbec83051ef17f81fb /tests/ajde | |
parent | fafae443719b26159ab2d7dac1c9b46b5e00b671 (diff) | |
download | aspectj-144143c2970a1e874d74cdbd0f8c622d4282a3c3.tar.gz aspectj-144143c2970a1e874d74cdbd0f8c622d4282a3c3.zip |
initial version
Diffstat (limited to 'tests/ajde')
67 files changed, 3562 insertions, 0 deletions
diff --git a/tests/ajde/examples/figures-cacm/Test_Figures_CACM.jpx b/tests/ajde/examples/figures-cacm/Test_Figures_CACM.jpx new file mode 100644 index 000000000..a17994a55 --- /dev/null +++ b/tests/ajde/examples/figures-cacm/Test_Figures_CACM.jpx @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?>
+
+<!--JBuilder XML Project-->
+<project>
+ <property category="runtime.0" name="RunnableType" value="com.borland.jbuilder.runtime.ApplicationRunner" />
+ <property category="runtime.0" name="application.class" value="figures.Main" />
+ <property category="sys" name="BackupPath" value="bak" />
+ <property category="sys" name="CheckStable" value="1" />
+ <property category="sys" name="Company" value="" />
+ <property category="sys" name="Copyright" value="Copyright (c) 2001" />
+ <property category="sys" name="Description" value="" />
+ <property category="sys" name="DocPath" value="." />
+ <property category="sys" name="ExcludeClassEnabled" value="0" />
+ <property category="sys" name="JDK" value="java 1.3.0_02" />
+ <property category="sys" name="LastTag" value="0" />
+ <property category="sys" name="Libraries" value="" />
+ <property category="sys" name="MakeStable" value="0" />
+ <property category="sys" name="OutPath" value="." />
+ <property category="sys" name="SourcePath" value="." />
+ <property category="sys" name="Title" value="" />
+ <property category="sys" name="Version" value="1.0" />
+ <property category="sys" name="WorkingDirectory" value="." />
+ <node type="Package" name="figures" />
+ <file path="Vanilla.lst" />
+</project>
+
diff --git a/tests/ajde/examples/figures-cacm/figures/Display.java b/tests/ajde/examples/figures-cacm/figures/Display.java new file mode 100644 index 000000000..5857d719f --- /dev/null +++ b/tests/ajde/examples/figures-cacm/figures/Display.java @@ -0,0 +1,9 @@ + +package figures; + +class Display { + + static void needsRepaint() { } + +} + diff --git a/tests/ajde/examples/figures-cacm/figures/DisplayUpdating.java b/tests/ajde/examples/figures-cacm/figures/DisplayUpdating.java new file mode 100644 index 000000000..7feade6ee --- /dev/null +++ b/tests/ajde/examples/figures-cacm/figures/DisplayUpdating.java @@ -0,0 +1,15 @@ + +package figures; + +aspect DisplayUpdating { + + pointcut moves(): 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(): moves() { + Display.needsRepaint(); + } +} diff --git a/tests/ajde/examples/figures-cacm/figures/FactoryEnforcement.java b/tests/ajde/examples/figures-cacm/figures/FactoryEnforcement.java new file mode 100644 index 000000000..a5ff5b5ec --- /dev/null +++ b/tests/ajde/examples/figures-cacm/figures/FactoryEnforcement.java @@ -0,0 +1,12 @@ + +package figures; + +aspect FactoryEnforcement { + + pointcut illegalNewFigElt(): call(FigureElement+.new(..)) && + !withincode(* Figure.make*(..)); + + declare error: illegalNewFigElt(): + "Illegal figure element constructor call."; + +} diff --git a/tests/ajde/examples/figures-cacm/figures/Figure.java b/tests/ajde/examples/figures-cacm/figures/Figure.java new file mode 100644 index 000000000..0516e4d1e --- /dev/null +++ b/tests/ajde/examples/figures-cacm/figures/Figure.java @@ -0,0 +1,23 @@ + +package figures; + +import java.util.List; +import java.util.LinkedList; + + +class Figure { + + List elements = new LinkedList(); + + Point makePoint(int x, int y) { + Point p = new Point(x, y); + elements.add(p); + return p; + } + + Line makeLine(Point p1, Point p2) { + Line l = new Line(p1, p2); + elements.add(l); + return l; + } +} diff --git a/tests/ajde/examples/figures-cacm/figures/FigureElement.java b/tests/ajde/examples/figures-cacm/figures/FigureElement.java new file mode 100644 index 000000000..591359e11 --- /dev/null +++ b/tests/ajde/examples/figures-cacm/figures/FigureElement.java @@ -0,0 +1,8 @@ + +package figures; + +interface FigureElement { + + public void moveBy(int dx, int dy); + +} diff --git a/tests/ajde/examples/figures-cacm/figures/Line.java b/tests/ajde/examples/figures-cacm/figures/Line.java new file mode 100644 index 000000000..3e8f6582d --- /dev/null +++ b/tests/ajde/examples/figures-cacm/figures/Line.java @@ -0,0 +1,23 @@ + +package figures; + +class Line { + private Point p1, p2; + + Line(Point p1, Point p2) { + super(); + this.p1 = p1; + this.p2 = p2; + } + + Point getP1() { return p1; } + Point getP2() { return p2; } + + void setP1(Point p1) { this.p1 = p1; } + void setP2(Point p2) { this.p2 = p2; } + + void moveBy(int dx, int dy) { + getP1().moveBy(dx, dy); + getP2().moveBy(dx, dy); + } +} diff --git a/tests/ajde/examples/figures-cacm/figures/Main.java b/tests/ajde/examples/figures-cacm/figures/Main.java new file mode 100644 index 000000000..b38e1fcdb --- /dev/null +++ b/tests/ajde/examples/figures-cacm/figures/Main.java @@ -0,0 +1,17 @@ + +package figures; + +class Main { + + public static void main(String [] args) { + System.out.println("> starting figures. . . " + 0); +// Figure fig = new Figure(); + Point p1 = new Point(2, 2); + p1.setX(10); + p1.setX(20); + System.out.println("> p1.x: " + p1.getX()); +// Point p2 = fig.makePoint(4, 4); +// System.out.println("> finished."); + } +} + diff --git a/tests/ajde/examples/figures-cacm/figures/Point.java b/tests/ajde/examples/figures-cacm/figures/Point.java new file mode 100644 index 000000000..322c23cca --- /dev/null +++ b/tests/ajde/examples/figures-cacm/figures/Point.java @@ -0,0 +1,33 @@ + +package figures; + +class Point { + private int x = 0, y = 0; + + Point(int x, int y) { + super(); + this.x = x; + this.y = y; + } + + int getX() { + return x; + } + + int getY() { + return y; + } + + void setX(int x) { + this.x = x; + } + + void setY(int y) { + this.y = y; + } + + void moveBy(int dx, int dy) { + setX(getX() + dx); + setY(getY() + dy); + } +} diff --git a/tests/ajde/examples/figures-cacm/figures/PointBoundsChecking.java b/tests/ajde/examples/figures-cacm/figures/PointBoundsChecking.java new file mode 100644 index 000000000..9338b26b7 --- /dev/null +++ b/tests/ajde/examples/figures-cacm/figures/PointBoundsChecking.java @@ -0,0 +1,13 @@ + +package figures; + +aspect PointBoundsChecking { + + pointcut tracePoints(): call(void Point.setX(int)) || + call(void Point.setY(int)); + + before(): tracePoints() { + System.out.println("Entering:" + thisJoinPoint); + } +} + diff --git a/tests/ajde/examples/figures-cacm/figures/SimpleTracing.java b/tests/ajde/examples/figures-cacm/figures/SimpleTracing.java new file mode 100644 index 000000000..d65eb158a --- /dev/null +++ b/tests/ajde/examples/figures-cacm/figures/SimpleTracing.java @@ -0,0 +1,13 @@ + +package figures; + +aspect SimpleTracing { + + pointcut tracePoints(): call(void Point.setX(int)) || + call(void Point.setY(int)); + + before(): tracePoints() { + System.out.println("Entering:" + thisJoinPoint); + } +} + diff --git a/tests/ajde/examples/figures-coverage/Test_Figures_Coverage.jpr b/tests/ajde/examples/figures-coverage/Test_Figures_Coverage.jpr new file mode 100644 index 000000000..3019853b1 --- /dev/null +++ b/tests/ajde/examples/figures-coverage/Test_Figures_Coverage.jpr @@ -0,0 +1,25 @@ +;JBuilder -- PROJECT FILE VERSION {2.00} - do not alter this line!
+#0=Test_Figures_Coverage.jpr
+#2=figures
+#3=editor
+sys[0].BackupPath=bak
+sys[0].CheckStable=1
+sys[0].Company=
+sys[0].Copyright=Copyright (c) 2001
+sys[0].DefaultPackage=test_figures_coverage
+sys[0].Description=
+sys[0].DocPath=doc
+sys[0].ExcludeClassEnabled=0
+sys[0].JDK=java 1.3.0-C
+sys[0].LastTag=3
+sys[0].Libraries=
+sys[0].MakeStable=0
+sys[0].OutPath=.
+sys[0].SourcePath=.
+sys[0].Title=
+sys[0].Version=1.0
+sys[0].WorkingDirectory=.
+sys[2].Parent=0
+sys[2].Type=Package
+sys[3].Parent=0
+sys[3].Type=Package
diff --git a/tests/ajde/examples/figures-coverage/Test_Figures_Coverage.jpx b/tests/ajde/examples/figures-coverage/Test_Figures_Coverage.jpx new file mode 100644 index 000000000..fee70a8d0 --- /dev/null +++ b/tests/ajde/examples/figures-coverage/Test_Figures_Coverage.jpx @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<!--JBuilder XML Project-->
+<project>
+ <property category="ajde" name="ajc.flags" value="-deprecation "/>
+ <property category="ajde" name="browser.associations" value="introduces on;uses pointcut;affects methods;affects method call sites;affects constructions;affects handlers;affects initializers;"/>
+ <property category="idl" name="ProcessIDL" value="false"/>
+ <property category="runtime.0" name="RunnableType" value="com.borland.jbuilder.runtime.ApplicationRunner"/>
+ <property category="runtime.0" name="application.class" value="figures.Main"/>
+ <property category="sys" name="AuthorLabel" value="@author"/>
+ <property category="sys" name="BackupPath" value="../temp"/>
+ <property category="sys" name="CheckStable" value="1"/>
+ <property category="sys" name="Company" value=""/>
+ <property category="sys" name="CompanyLabel" value="Company:"/>
+ <property category="sys" name="CompileOnRun" value="0"/>
+ <property category="sys" name="Copyright" value="Copyright (c) 2001"/>
+ <property category="sys" name="CopyrightLabel" value="Copyright:"/>
+ <property category="sys" name="Description" value=""/>
+ <property category="sys" name="DescriptionLabel" value="Description:"/>
+ <property category="sys" name="DocPath" value="."/>
+ <property category="sys" name="ExcludeClassEnabled" value="0"/>
+ <property category="sys" name="JDK" value="java 1.3.0_02"/>
+ <property category="sys" name="LastTag" value="0"/>
+ <property category="sys" name="Libraries" value=""/>
+ <property category="sys" name="MakeStable" value="0"/>
+ <property category="sys" name="OutPath" value="classes"/>
+ <property category="sys" name="SourcePath" value="."/>
+ <property category="sys" name="Title" value=""/>
+ <property category="sys" name="TitleLabel" value="Title:"/>
+ <property category="sys" name="Version" value="1.0"/>
+ <property category="sys" name="VersionLabel" value="@version"/>
+ <property category="sys" name="WorkingDirectory" value="../temp"/>
+ <property category="sys" name="enable.auto.packages" value="false"/>
+ <node name="figures" type="Package"/>
+ <file path="Probe.lst"/>
+ <file path="Test_Figures_Coverage.lst"/>
+ <file path="Trace.aj"/>
+</project>
diff --git a/tests/ajde/examples/figures-coverage/Trace.aj b/tests/ajde/examples/figures-coverage/Trace.aj new file mode 100644 index 000000000..81fd1c739 --- /dev/null +++ b/tests/ajde/examples/figures-coverage/Trace.aj @@ -0,0 +1,4 @@ +
+aspect Trace {
+
+}
diff --git a/tests/ajde/examples/figures-coverage/_JoinpointProbe.java b/tests/ajde/examples/figures-coverage/_JoinpointProbe.java new file mode 100644 index 000000000..52507042d --- /dev/null +++ b/tests/ajde/examples/figures-coverage/_JoinpointProbe.java @@ -0,0 +1,3 @@ +aspect JoinpointProbe { +before(): null +{ } }
\ No newline at end of file diff --git a/tests/ajde/examples/figures-coverage/editor/Editor.java b/tests/ajde/examples/figures-coverage/editor/Editor.java new file mode 100644 index 000000000..99e2b5d5b --- /dev/null +++ b/tests/ajde/examples/figures-coverage/editor/Editor.java @@ -0,0 +1,4 @@ + +package editor; + +class Editor { } diff --git a/tests/ajde/examples/figures-coverage/figures/Debug.java b/tests/ajde/examples/figures-coverage/figures/Debug.java new file mode 100644 index 000000000..01e895abc --- /dev/null +++ b/tests/ajde/examples/figures-coverage/figures/Debug.java @@ -0,0 +1,7 @@ + +package figures; + +aspect Debug { + +} + diff --git a/tests/ajde/examples/figures-coverage/figures/Figure.java b/tests/ajde/examples/figures-coverage/figures/Figure.java new file mode 100644 index 000000000..78aae3a37 --- /dev/null +++ b/tests/ajde/examples/figures-coverage/figures/Figure.java @@ -0,0 +1,78 @@ + +package figures; + +//import figures.primitives.planar.Point; + +aspect Figure { + //pointcut sendSuccess(): cflow(setX()) && !handler(Exception); + + public String Point.getName() { + return Point.name; + } + + public int Point.DEFAULT_X = 0; + + public pointcut constructions(): call(Point.new(int, int)) || call(SolidPoint.new(int, int, int)); + + public pointcut moves(FigureElement fe): target(fe) && + (call(String Point.getName()) || + call(void FigureElement.incrXY(int, int)) || + call(void Point.setX(int)) || + call(void Point.setY(int)) || + call(void SolidPoint.setZ(int))); + + pointcut mainExecution(): execution(void main(*)); + pointcut runtimeHandlers(): mainExecution() || handler(RuntimeException); + public pointcut mumble(): runtimeHandlers(); + + before(): constructions() { + System.out.println("> before construction, jp: " + thisJoinPoint.getSignature()); + } + + before(FigureElement fe): moves(fe) { + System.out.println("> about to move FigureElement at X-coord: "); + } + + after(): initialization(Point.new(..)) || staticinitialization(Point) { + System.out.println("> Point initialized"); + } + + // should be around + after(): mumble() { + System.err.println(">> in after advice..."); + //proceed(); + } + + after(FigureElement fe): target(fe) && + (call(void FigureElement.incrXY(int, int)) || + call(void Point.setX(int)) || + call(void Point.setY(int)) || + call(void SolidPoint.setZ(int))) { + System.out.println("> yo."); + } + + after(FigureElement fe): + target(fe) && + (call(void FigureElement.incrXY(int, int)) || + call(void Line.setP1(Point)) || + call(void Line.setP2(Point)) || + call(void Point.setX(int)) || + call(void Point.setY(int))) { } + + declare parents: Point extends java.io.Serializable; + + declare parents: Point implements java.util.Observable; + + declare soft: Point: call(* *(..)); +} + +aspect Checks { + pointcut illegalNewFigElt(): call(FigureElement+.new(..)) && + !withincode(* Main.main(..)); + + declare error: illegalNewFigElt(): + "Illegal figure element constructor call."; + + declare warning: illegalNewFigElt(): + "Illegal figure element constructor call."; +} diff --git a/tests/ajde/examples/figures-coverage/figures/FigureElement.java b/tests/ajde/examples/figures-coverage/figures/FigureElement.java new file mode 100644 index 000000000..d2ce9eb82 --- /dev/null +++ b/tests/ajde/examples/figures-coverage/figures/FigureElement.java @@ -0,0 +1,9 @@ + +package figures; + +public interface FigureElement extends Element { + + public void incrXY(int dx, int dy); +} + +interface Element { } diff --git a/tests/ajde/examples/figures-coverage/figures/Main.java b/tests/ajde/examples/figures-coverage/figures/Main.java new file mode 100644 index 000000000..b1e8520d4 --- /dev/null +++ b/tests/ajde/examples/figures-coverage/figures/Main.java @@ -0,0 +1,48 @@ + +package figures; + +import figures.primitives.planar.Point; +import figures.primitives.solid.SolidPoint; + +class Main { + + private static Point startPoint; + + public static void main(String[] args) { + try { + System.out.println("> starting..."); + + startPoint = makeStartPoint(); + //startPoint.setX(3); new Point(0, 0); +// SolidPoint sp1 = new SolidPoint(1, 3, 3); + +// sp1.setZ(1); +// p1.incrXY(3, 3); + } catch (RuntimeException re) { + re.printStackTrace(); + } + System.out.println("> finished."); + } + + /** @deprecated use something else */ + public static Point makeStartPoint() { + //return new Point(1, 2); + return null; + } + + /** This should produce a deprecation warning with JDK > 1.2 */ + static class TestGUI extends javax.swing.JFrame { + TestGUI() { + this.disable(); + } + } + + /** This should produce a porting-deprecation warning. */ + //static pointcut mainExecution(): execution(void main(*)); +} + +privileged aspect Test { + before(Point p, int newval): target(p) && set(int Point.xx) && args(newval) { + System.err.println("> new value of x is: " + p.x + ", setting to: " + newval); + } +} diff --git a/tests/ajde/examples/figures-coverage/figures/Trace.aj b/tests/ajde/examples/figures-coverage/figures/Trace.aj new file mode 100644 index 000000000..81fd1c739 --- /dev/null +++ b/tests/ajde/examples/figures-coverage/figures/Trace.aj @@ -0,0 +1,4 @@ +
+aspect Trace {
+
+}
diff --git a/tests/ajde/examples/figures-coverage/figures/composites/Line.java b/tests/ajde/examples/figures-coverage/figures/composites/Line.java new file mode 100644 index 000000000..1f7ee5dc8 --- /dev/null +++ b/tests/ajde/examples/figures-coverage/figures/composites/Line.java @@ -0,0 +1,6 @@ + +package figures.composites; + +class Line { } + +class BoundedLine extends Line { } diff --git a/tests/ajde/examples/figures-coverage/figures/composites/Square.java b/tests/ajde/examples/figures-coverage/figures/composites/Square.java new file mode 100644 index 000000000..8ba3825d6 --- /dev/null +++ b/tests/ajde/examples/figures-coverage/figures/composites/Square.java @@ -0,0 +1,6 @@ + +package figures.composites; + +class Square { + private String name = "Square"; +} diff --git a/tests/ajde/examples/figures-coverage/figures/primitives/planar/Point.java b/tests/ajde/examples/figures-coverage/figures/primitives/planar/Point.java new file mode 100644 index 000000000..6a745a540 --- /dev/null +++ b/tests/ajde/examples/figures-coverage/figures/primitives/planar/Point.java @@ -0,0 +1,65 @@ + +package figures.primitives.planar; + +import figures.*; +import java.util.Collection; + +public class Point implements FigureElement { + + static int xx = -1; + private int x; + private int y; + transient int currVal = 0; + public static String name; + + int c; int b; int a; + { + x = 0; + y = 0; + } + + static { + Point.name = "2-Dimensional Point"; + } + + public Point(int x, int y) { + this.x = x; + this.y = y; + } + + int getCurrVal() { + return currVal; + } + + /** + * @see Figure#moves + */ + public int getX() { return x; } + + public int getY() { return y; } + + public void setX(int x) { this.x = x; } + + public void setY(int x) { this.y = x; } + + public void incrXY(int dx, int dy) { + setX(getX() + dx); + setY(getY() + dy); + } + public void check(int dx, int dy) + throws ArithmeticException, PointBoundsException { + if (dx < 0 || dy < 0) throw new PointBoundsException(); + } +} + +class PointBoundsException extends Exception { } + +class BoundedPoint extends Point { + public BoundedPoint(int x, int y) { super(x, y); } +} + +class StrictlyBoundedPoint extends BoundedPoint { + public StrictlyBoundedPoint(int x, int y) { super(x, y); } +} + + diff --git a/tests/ajde/examples/figures-coverage/figures/primitives/solid/SolidPoint.java b/tests/ajde/examples/figures-coverage/figures/primitives/solid/SolidPoint.java new file mode 100644 index 000000000..80c1fc1ca --- /dev/null +++ b/tests/ajde/examples/figures-coverage/figures/primitives/solid/SolidPoint.java @@ -0,0 +1,24 @@ + +package figures.primitives.solid; + +import java.util.Collection; +import java.lang.String; +import figures.primitives.planar.*; + +public class SolidPoint extends Point { + private int z; + + public SolidPoint(int x, int y, int z) { + super(x, y); + this.z = z; + } + + public int getZ() { return z; } + + public void setZ(int z) { this.z = z; } + + public void incrXY(int dx, int dy) { + super.incrXY(dx, dy); + setZ(getZ() + dx + dy); + } +} diff --git a/tests/ajde/examples/observer-gof/Test_Observer.jpx b/tests/ajde/examples/observer-gof/Test_Observer.jpx new file mode 100644 index 000000000..1474caaf0 --- /dev/null +++ b/tests/ajde/examples/observer-gof/Test_Observer.jpx @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?>
+
+<!--JBuilder XML Project-->
+<project>
+ <property category="runtime.0" name="application.class" value="" />
+ <property category="sys" name="BackupPath" value="bak" />
+ <property category="sys" name="CheckStable" value="1" />
+ <property category="sys" name="Company" value="" />
+ <property category="sys" name="Copyright" value="Copyright (c) 2001" />
+ <property category="sys" name="Description" value="" />
+ <property category="sys" name="DocPath" value="." />
+ <property category="sys" name="ExcludeClassEnabled" value="0" />
+ <property category="sys" name="JDK" value="java 1.3.0_02" />
+ <property category="sys" name="LastTag" value="0" />
+ <property category="sys" name="Libraries" value="" />
+ <property category="sys" name="MakeStable" value="0" />
+ <property category="sys" name="OutPath" value="." />
+ <property category="sys" name="SourcePath" value="." />
+ <property category="sys" name="Title" value="" />
+ <property category="sys" name="Version" value="1.0" />
+ <property category="sys" name="WorkingDirectory" value="." />
+ <node type="Package" name="clock" />
+ <file path="../figures-coverage/Test_Figures_Coverage.lst" />
+</project>
+
diff --git a/tests/ajde/examples/observer-gof/clock/AnalogClock.java b/tests/ajde/examples/observer-gof/clock/AnalogClock.java new file mode 100644 index 000000000..b60d45e51 --- /dev/null +++ b/tests/ajde/examples/observer-gof/clock/AnalogClock.java @@ -0,0 +1,12 @@ + +package clock; +public class AnalogClock implements Clock { + public AnalogClock(ClockTimer subject) { + super(); + } + public void update(ClockTimer subject, Object args) { + } + + public void draw() { + } +}
\ No newline at end of file diff --git a/tests/ajde/examples/observer-gof/clock/Clock.java b/tests/ajde/examples/observer-gof/clock/Clock.java new file mode 100644 index 000000000..7fc150a4d --- /dev/null +++ b/tests/ajde/examples/observer-gof/clock/Clock.java @@ -0,0 +1,5 @@ + +package clock; +interface Clock { + void update(ClockTimer subject, Object args); +}
\ No newline at end of file diff --git a/tests/ajde/examples/observer-gof/clock/ClockTimer.java b/tests/ajde/examples/observer-gof/clock/ClockTimer.java new file mode 100644 index 000000000..b0fa08461 --- /dev/null +++ b/tests/ajde/examples/observer-gof/clock/ClockTimer.java @@ -0,0 +1,33 @@ + +package clock; +import java.util.*; + +public class ClockTimer extends Observable { + List observers; + public int getHour() { + return 0; + } + + public int getMinute() { + return 0; + } + + public int getSeconds() { + return 0; + } + + public void addObserver(Object observer) { + this.observers.add(observer); + } + + public void tick() { + this.notifyObservers(); + } + + public ClockTimer() { + super(); + { + this.observers = new ArrayList(); + } + } +}
\ No newline at end of file diff --git a/tests/ajde/examples/observer-gof/clock/DigitalClock.java b/tests/ajde/examples/observer-gof/clock/DigitalClock.java new file mode 100644 index 000000000..1d56055a2 --- /dev/null +++ b/tests/ajde/examples/observer-gof/clock/DigitalClock.java @@ -0,0 +1,26 @@ + +package clock; + +public class DigitalClock implements Clock { + private ClockTimer subject; + + public DigitalClock(ClockTimer subject) { + super(); + this.subject = subject; + this.subject.addObserver(this); + } + public void removeObserver(Object observer) { + this.subject.observers.remove(observer); + } + + public void update(ClockTimer subject, Object args) { + if (this.subject == subject) { + this.draw(); + } + } + + public void draw() { + int hour = this.subject.getHour(); + int minute = this.subject.getMinute(); + } +}
\ No newline at end of file diff --git a/tests/ajde/examples/observer-gof/clock/Main.java b/tests/ajde/examples/observer-gof/clock/Main.java new file mode 100644 index 000000000..7b5436164 --- /dev/null +++ b/tests/ajde/examples/observer-gof/clock/Main.java @@ -0,0 +1,14 @@ + +package clock; + +import java.util.Observer; +import java.util.Observable; + +public class Main { + + public static void main(String[] args) { + ClockTimer clockTimer = new ClockTimer(); + DigitalClock digitalClock = new DigitalClock(clockTimer); + AnalogClock analogClock = new AnalogClock(clockTimer); + } +}
\ No newline at end of file diff --git a/tests/ajde/examples/observer-gof/clock/MonitorObservation.java b/tests/ajde/examples/observer-gof/clock/MonitorObservation.java new file mode 100644 index 000000000..6d3028ecb --- /dev/null +++ b/tests/ajde/examples/observer-gof/clock/MonitorObservation.java @@ -0,0 +1,9 @@ +package clock; + +aspect MonitorObservation { + + before(): call(void Clock.update(..)) + || execution(void *.addObserver(..)) + || execution(void *.removeObserver(..)) { + } +} diff --git a/tests/ajde/examples/observer/Test_Observer.jpx b/tests/ajde/examples/observer/Test_Observer.jpx new file mode 100644 index 000000000..cdccdd53a --- /dev/null +++ b/tests/ajde/examples/observer/Test_Observer.jpx @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?>
+
+<!--JBuilder XML Project-->
+<project>
+ <property category="sys" name="BackupPath" value="bak" />
+ <property category="sys" name="CheckStable" value="1" />
+ <property category="sys" name="Company" value="" />
+ <property category="sys" name="Copyright" value="Copyright (c) 2001" />
+ <property category="sys" name="Description" value="" />
+ <property category="sys" name="DocPath" value="." />
+ <property category="sys" name="ExcludeClassEnabled" value="0" />
+ <property category="sys" name="JDK" value="java 1.3.0_02" />
+ <property category="sys" name="LastTag" value="0" />
+ <property category="sys" name="Libraries" value="" />
+ <property category="sys" name="MakeStable" value="0" />
+ <property category="sys" name="OutPath" value="." />
+ <property category="sys" name="SourcePath" value="." />
+ <property category="sys" name="Title" value="" />
+ <property category="sys" name="Version" value="1.0" />
+ <property category="sys" name="WorkingDirectory" value="." />
+ <node type="Package" name="clock" />
+</project>
+
diff --git a/tests/ajde/examples/observer/clock/AnalogueClock.java b/tests/ajde/examples/observer/clock/AnalogueClock.java new file mode 100644 index 000000000..898b96d6b --- /dev/null +++ b/tests/ajde/examples/observer/clock/AnalogueClock.java @@ -0,0 +1,21 @@ + +package clock; + +import java.util.Observer; +import java.util.Observable; + +public class AnalogueClock implements Observer { + + public AnalogueClock (ClockTimer subject) { + + } + + public void update(Observable theChangedSubject, Object args) { + + } + + public void draw() { + + } +} + diff --git a/tests/ajde/examples/observer/clock/ClockTimer.java b/tests/ajde/examples/observer/clock/ClockTimer.java new file mode 100644 index 000000000..ffd9c905d --- /dev/null +++ b/tests/ajde/examples/observer/clock/ClockTimer.java @@ -0,0 +1,23 @@ + +package clock; + +import java.util.Observable; + +public class ClockTimer extends Observable { + + public void tick () { + notifyObservers(); + } + + public int getHour() { + return 0; + } + + public int getMinute() { + return 0; + } + + public int getSeconds() { + return 0; + } +} diff --git a/tests/ajde/examples/observer/clock/DigitalClock.java b/tests/ajde/examples/observer/clock/DigitalClock.java new file mode 100644 index 000000000..346f824ec --- /dev/null +++ b/tests/ajde/examples/observer/clock/DigitalClock.java @@ -0,0 +1,30 @@ + +package clock; + +import java.util.Observer; +import java.util.Observable; + +public class DigitalClock implements Observer { + + private ClockTimer subject; + + public DigitalClock (ClockTimer subject) { + this.subject = subject; + this.subject.addObserver(this); + } + + public void removeObserver() { + subject.deleteObserver(this); + } + + public void update(Observable theChangedSubject, Object args) { + if (theChangedSubject == subject) { + draw(); + } + } + + public void draw () { + int hour = subject.getHour(); + int minute = subject.getMinute(); + } +} diff --git a/tests/ajde/examples/observer/clock/Main.java b/tests/ajde/examples/observer/clock/Main.java new file mode 100644 index 000000000..90cd1d4bf --- /dev/null +++ b/tests/ajde/examples/observer/clock/Main.java @@ -0,0 +1,15 @@ +package clock; + +import java.util.Observer; +import java.util.Observable; + +public class Main { + + public static void main(String[] args) { + System.err.println("> starting clock..."); + ClockTimer clockTimer = new ClockTimer(); + DigitalClock digitalClock = new DigitalClock(clockTimer); + AnalogueClock analogueClock = new AnalogueClock(clockTimer); + } +} + diff --git a/tests/ajde/examples/observer/clock/MonitorObservation.java b/tests/ajde/examples/observer/clock/MonitorObservation.java new file mode 100644 index 000000000..12cfb1f74 --- /dev/null +++ b/tests/ajde/examples/observer/clock/MonitorObservation.java @@ -0,0 +1,14 @@ +package clock; + +import java.util.Observer; +import java.util.Observable; + +aspect MonitorObserveration { + before(): + (call(void Observer.update(Observable, Object)) + || call(void Observable.addObserver(Observer)) + || call(void Observable.removeObserver(Observer))) { + + } +} + diff --git a/tests/ajde/examples/spacewar/Test_Spacewar.jpx b/tests/ajde/examples/spacewar/Test_Spacewar.jpx new file mode 100644 index 000000000..351bb3588 --- /dev/null +++ b/tests/ajde/examples/spacewar/Test_Spacewar.jpx @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?>
+
+<!--JBuilder XML Project-->
+<project>
+ <property category="ajde" name="ajc.flags" value="" />
+ <property category="runtime.0" name="RunnableType" value="com.borland.jbuilder.runtime.ApplicationRunner" />
+ <property category="runtime.0" name="application.class" value="spacewar.Game" />
+ <property category="sys" name="BackupPath" value="bak" />
+ <property category="sys" name="CheckStable" value="1" />
+ <property category="sys" name="Company" value="" />
+ <property category="sys" name="Copyright" value="Copyright (c) 2001" />
+ <property category="sys" name="Description" value="" />
+ <property category="sys" name="DocPath" value="." />
+ <property category="sys" name="ExcludeClassEnabled" value="0" />
+ <property category="sys" name="JDK" value="java 1.3.0_02" />
+ <property category="sys" name="LastTag" value="0" />
+ <property category="sys" name="Libraries" value="" />
+ <property category="sys" name="MakeStable" value="0" />
+ <property category="sys" name="OutPath" value="." />
+ <property category="sys" name="SourcePath" value="." />
+ <property category="sys" name="Title" value="" />
+ <property category="sys" name="Version" value="1.0" />
+ <property category="sys" name="WorkingDirectory" value="." />
+ <node type="Package" name="coordination" />
+ <node type="Package" name="spacewar" />
+ <file path="Release.lst" />
+</project>
+
diff --git a/tests/ajde/examples/spacewar/coordination/Condition.java b/tests/ajde/examples/spacewar/coordination/Condition.java new file mode 100644 index 000000000..30fb84bfe --- /dev/null +++ b/tests/ajde/examples/spacewar/coordination/Condition.java @@ -0,0 +1,20 @@ + +package coordination; + + +/** + * Interface for pre-conditions that are passed to guardedEntry methods of + * Coordinator. + * Conditions should be passed as anonymous classes that simply implement + * the checkit method. + * + */ +public interface Condition { + + /** + * This method is called automatically by Coordinator.guardedEntry(...) + * and it's called everytime the coordination state changes. + */ + + public boolean checkit(); +} diff --git a/tests/ajde/examples/spacewar/coordination/CoordinationAction.java b/tests/ajde/examples/spacewar/coordination/CoordinationAction.java new file mode 100644 index 000000000..627b64e9f --- /dev/null +++ b/tests/ajde/examples/spacewar/coordination/CoordinationAction.java @@ -0,0 +1,20 @@ + +package coordination; + + +/** + * Interface for coordination actions that are passed to guardedEntry methods of + * Coordinator. + * Coordination actions should be passed as anonymous classes that simply + * implement the doit method. + * + */ +public interface CoordinationAction { + /** + * This method is called by Coordinator.guardedEntry(...) and + * Coordinator.guardedExit(...). Use it for changing coordination state + * upon entering and exiting methods. + */ + + public void doit(); +} diff --git a/tests/ajde/examples/spacewar/coordination/Coordinator.java b/tests/ajde/examples/spacewar/coordination/Coordinator.java new file mode 100644 index 000000000..69830c138 --- /dev/null +++ b/tests/ajde/examples/spacewar/coordination/Coordinator.java @@ -0,0 +1,432 @@ + +package coordination; + +import java.util.*; //!!! + +/** + * The Coordinator class provides the basic functionality for synchronizing + * and coordinating different threads upon entering and exiting methods. + * It can be used in two different ways: + * 1) by instantiating regular coordinator objects that are used by aspects; or + * 2) by extending it (sub-classing) with coordinator aspects. + * <P> + * Method invocations are the smallest units for defining critical sections + * and pre-conditions. The use of coordinators, either regular objects or aspect + * instances, should always end up by invoking guardedEntry(...) in a + * before weave and guardedExit(...) in an after weave for all methods that + * need coordination. guardedEntry and guardedExit are the methods that + * actually manage the synchronization and coordination constraints given + * by their parameters and by pre-existent exclusion markers. + * <P> + * The synchronization of threads for the execution of critical section + * methods in an object is done by marking those methods as self- and/or + * mutually-exclusive (addSelfex, addMutex). + * Just by itself, addSelfex("M") does not enforce the self-exclusion + * of method M - enforcement is done by invoking guardedEntry before + * M is executed. Similarly, addMutex(new String[] {"M1", "M2"}) does + * not enforce the mutual exclusion between methods M1 and M2. + * <P> + * A guardedEntry on a method that has been marked as self-exclusive + * ensures that the method is executed in the invoked object by only one thread + * at a time. A guardedEntry on a method that has been marked has mutually- + * exclusive with other methods ensures that the execution of that method + * by a thread in the invoked object temporarily blocks the execution by + * other threads of the methods that are in the same mutex set. + * <P> + * The coordination of threads, i.e. their explicit suspension and + * resumption, is done through the use of pre-conditions and coordination + * actions that are passed as parameters to guardedEntry and guardedExit + * with the form of anonymous classes. + */ +public abstract aspect Coordinator { + private Hashtable methods = null; + private Vector exclusions = null; + + abstract protected pointcut synchronizationPoint(); + + public Coordinator() { + methods = new Hashtable(); + exclusions = new Vector(5); + } + + before (): synchronizationPoint() { + this.guardedEntry(thisJoinPointStaticPart.getSignature().getName()); + } + + after (): synchronizationPoint() { + this.guardedExit(thisJoinPointStaticPart.getSignature().getName()); + } + + /** + * Takes a multi-part method name (eg "BoundedBuffer.put") + * and marks that method as self-exclusive. + * No checks are made with respect to the existence of the method + * whose name is given. + */ + public synchronized void addSelfex(String methName) { + Selfex sex = new Selfex (methName); + + // update db of all exclusions in this coordinator + exclusions.addElement(sex); + + // update local info in method + Method aMeth = getOrSetMethod(methName); + aMeth.addExclusion(sex); + } + + /** + * Takes a multi-part method name (e.g. "BoundedBuffer.put") + * and removes that method from the list of self-exclusive methods. + */ + public synchronized void removeSelfex(String methName) { + for (int i = 0; i < exclusions.size(); i++) { + Exclusion sex = (Exclusion)exclusions.elementAt(i); + if ((sex instanceof Selfex) && + (((Selfex)sex).methodName.equals(methName))) { + + // update db of all exclusions in this coordinator + exclusions.removeElementAt(i); + + // update local info in method + Method aMeth = getOrSetMethod(methName); + aMeth.removeExclusion(sex); + } + } + } + + /** + * Takes an array of multi-part method names and marks those + * methods as mutually exclusive. + * No checks are made with respect to the existence of the methods + * whose names are given. + */ + public synchronized void addMutex(String[] methNames) { + Mutex mux = new Mutex(methNames); + + // update db of all exclusions in this coordinator + exclusions.addElement(mux); + + // update local info in each method + for (int i = 0; i < methNames.length; i++) { + Method aMeth = getOrSetMethod(methNames[i]); + aMeth.addExclusion(mux); + } + } + + /** + * Takes an array of multi-part method names that correspond + * to an existing mutex set and remove the mutual exclusion constraint. + * If the given mutex set does not exist, removeMutex does nothing. + */ + public synchronized void removeMutex(String[] methNames) { + for (int i = 0; i < exclusions.size(); i++) { + Exclusion mux = (Exclusion)exclusions.elementAt(i); + if (mux instanceof Mutex) { + boolean same = true; + for (int j = 0; j < methNames.length; j++) + if (!methNames[j].equals(((Mutex)mux).methodNames[j])) + same = false; + if (same) { + // update db of all exclusions in this coordinator + exclusions.removeElementAt(i); + + // update local info in each method involved + for (int j = 0; j < methNames.length; j++) { + Method aMeth = getOrSetMethod(methNames[j]); + aMeth.removeExclusion(mux); + } + } + } + } + } + + /** + * This method is the guard for enforcing all synchronization and + * coordination constraints of a given method, and it should be called + * just before the method is executed. + * In this form, only the method name is given. The only constraints + * checked are the exclusion constraints. + * If the method was previousely marked as selfex (through addSelfex), + * guardedEntry ensures that the method is executed only when no other + * thread is executing it. + * If the method was previousely marked as being in one or more mutex + * sets, guardedEntry ensures that the method is executed only when no other + * thread is executing any of the methods with which the give method is + * mutexed. + */ + public synchronized void guardedEntry(String methName) { + guardedEntry(methName, new Condition() { + public boolean checkit() { + return true; + } + }, null); + } + + /** + * Just like guardedEntry(String methName), but the given method is executed + * only when the given condition is true. + * guardedEntry is the guard for enforcing all synchronization and + * coordination constraints of a given method, and it should be called + * just before the method is executed. + * In this form, the method name is given along with a condition. + * The constraints checked are the exclusion constraints and whether + * the given condition is true. + * If the method was previousely marked as selfex (through addSelfex), + * guardedEntry ensures that the method is executed only when no other + * thread is executing it. + * If the method was previousely marked as being in one or more mutex + * sets, guardedEntry ensures that the method is executed only when no other + * thread is executing any of the methods with which the give method is + * mutexed. + * If the condition is false, guardedEntry suspends the current thread. + * That thread remains suspended until the condition becomes true, in + * which case all constraints are rechecked before the method is executed. + * When all exclusion constraints are checked and the given condition is + * true, the given method is executed. + */ + public synchronized void guardedEntry(String methName, Condition condition) { + guardedEntry(methName, condition, null); + } + + /** + * Just like guardedEntry(String methName), but with an additional + * coordination action that is executed before the given method is + * executed. + * guardedEntry is the guard for enforcing all synchronization and + * coordination constraints of a given method, and it should be called + * just before the method is executed. + * In this form, the method name is given along with a coordination action. + * The only constraints checked are the exclusion constraints. + * If the method was previousely marked as selfex (through addSelfex), + * guardedEntry ensures that the method is executed only when no other + * thread is executing it. + * If the method was previousely marked as being in one or more mutex + * sets, guardedEntry ensures that the method is executed only when no other + * thread is executing any of the methods with which the give method is + * mutexed. + * The given coordination action is executed just before the given method + * is executed. + */ + public synchronized void guardedEntry(String methName, + CoordinationAction action) { + guardedEntry(methName, new Condition() { + public boolean checkit() { + return true; + } + }, + action); + } + + /** + * Just like guardedEntry(String methName), but the given method is executed + * only when the given condition is true; the additional + * coordination action that is executed before the given method is + * executed. + * guardedEntry is the guard for enforcing all synchronization and + * coordination constraints of a given method, and it should be called + * just before the method is executed. + * In this form, the method name is given along with a condition and + * a coordination action. + * The constraints checked are the exclusion constraints and whether the + * given condition is true. + * If the method was previousely marked as selfex (through addSelfex), + * guardedEntry ensures that the method is executed only when no other + * thread is executing it. + * If the method was previousely marked as being in one or more mutex + * sets, guardedEntry ensures that the method is executed only when no other + * thread is executing any of the methods with which the give method is + * mutexed. + * If the condition is false, guardedEntry suspends the current thread. + * That thread remains suspended until the condition becomes true, in + * which case all constraints are rechecked before the method is executed. + * When all exclusion constraints are checked and the given condition is + * true, the given method is executed. + * The given coordination action is executed just before the given method + * is executed. + */ + public synchronized void guardedEntry(String methName, + Condition condition, + CoordinationAction action) { + Method aMeth = getOrSetMethod(methName); + boolean canGo = false; + + // test pre-conditions for entering the method + while (!canGo) { + canGo = true; + for (int i = 0; i < aMeth.exes.size() && canGo; i++) + if (!((Exclusion)aMeth.exes.elementAt(i)).testExclusion(aMeth.name)) { + canGo = false; + } + if (canGo && !condition.checkit()) { + canGo = false; + } + if (!canGo) + try { + wait(); + } catch (InterruptedException e) { } + } + + // OK. + enterMethod(aMeth, action); + } + + /** + * This method is similar to guardedEntry, but it takes + * an additional parameter - the milliseconds after which any suspension + * will abort with a timeout. + */ + public synchronized void guardedEntryWithTimeout(String methName, + long millis) + throws TimeoutException { + guardedEntryWithTimeout(methName, new Condition() { + public boolean checkit() { + return true; + } + }, null, millis); + } + + /** + * This method is similar to guardedEntry, but it takes + * an additional parameter - the milliseconds after which any suspension + * will abort with a timeout. + */ + public synchronized void guardedEntryWithTimeout(String methName, + Condition condition, + long millis) + throws TimeoutException { + guardedEntryWithTimeout(methName, condition, null, millis); + } + + /** + * This method is similar to guardedEntry, but it takes + * an additional parameter - the milliseconds after which any suspension + * will abort with a timeout. + */ + public synchronized void guardedEntryWithTimeout(String methName, + CoordinationAction action, + long millis) + throws TimeoutException { + guardedEntryWithTimeout(methName, new Condition() { + public boolean checkit() { + return true; + } + }, action, millis); + } + + /** + * This method is similar to guardedEntry, but it takes + * an additional parameter - the milliseconds after which any suspension + * will abort with a timeout. + */ + public synchronized void guardedEntryWithTimeout(String methName, + Condition condition, + CoordinationAction action, + long millis) + throws TimeoutException { + + Method aMeth = getOrSetMethod(methName); + boolean canGo = false; + long waitTime = millis; + long startTime = System.currentTimeMillis(); + + // test pre-conditions for entering the method + while (!canGo) { + canGo = true; + for (int i = 0; i < aMeth.exes.size() && canGo; i++) + if ((!((Exclusion)aMeth.exes.elementAt(i)).testExclusion(aMeth.name)) || + (!condition.checkit())) { + canGo = false; + } + if (!canGo) { + try { + wait(waitTime); + } catch (InterruptedException e) {} + + long now = System.currentTimeMillis(); + long timeSoFar = now - startTime; + if (timeSoFar >= millis) // timeout! + throw new TimeoutException(timeSoFar); + else // adjust time + waitTime = millis - timeSoFar; + } + } + + // OK. + enterMethod(aMeth, action); + } + + /** + * This method provides the means for updating all synchronization and + * coordination state after the execution of a given method, and it should be + * called after the method is executed. + * In this form, only the method name is given. + * The synchronization state for self- and mutual-exclusion is + * automatically upadted. + */ + public synchronized void guardedExit(String methName) { + guardedExit(methName, null); + } + + /** + * Just like guardedExit(String methName) but with an additional + * coordination action that is executed. + * guardedExit provides the means for updating all synchronization and + * coordination state after the execution of a given method, and it should be + * called after the method is executed. + * In this form, the method name is given along with a coordination action. + * The synchronization state for self- and mutual-exclusion is + * automatically upadted. + * The given coordination action is executed. + */ + public synchronized void guardedExit(String methName, + CoordinationAction action) { + Method aMeth = getOrSetMethod(methName); + + for (int i = 0; i < aMeth.exes.size(); i++) + ((Exclusion)aMeth.exes.elementAt(i)).exitExclusion(methName); + if (action != null) action.doit(); + notifyAll(); + } + + private Method getOrSetMethod(String methName) { + Method aMeth = null; + if (!methods.containsKey(methName)) { + methods.put(methName, (aMeth = new Method(methName))); + } + else { + aMeth = (Method) methods.get(methName); + } + return aMeth; + } + + private void enterMethod(Method aMeth, CoordinationAction action) { + for (int i = 0; i < aMeth.exes.size(); i++) + ((Exclusion)aMeth.exes.elementAt(i)).enterExclusion(aMeth.name); + + if (action != null) action.doit(); + } + + + +} + +class Method { + String name; + Vector exes = new Vector(3); + + Method(String n) { + name = n; + } + + void addExclusion(Exclusion ex) { + exes.addElement(ex); + } + + void removeExclusion(Exclusion ex) { + for (int i = 0; i < exes.size(); i++) { + if (exes.elementAt(i) == ex) + exes.removeElementAt(i); + } + } +} + diff --git a/tests/ajde/examples/spacewar/coordination/Exclusion.java b/tests/ajde/examples/spacewar/coordination/Exclusion.java new file mode 100644 index 000000000..db2ffe0e5 --- /dev/null +++ b/tests/ajde/examples/spacewar/coordination/Exclusion.java @@ -0,0 +1,16 @@ + +package coordination; + + +interface Exclusion { + + boolean testExclusion(String methodName); + + void enterExclusion(String methodName); + + void exitExclusion(String methodName); + + // for debug !!! + void printNames(); +} + diff --git a/tests/ajde/examples/spacewar/coordination/MethodState.java b/tests/ajde/examples/spacewar/coordination/MethodState.java new file mode 100644 index 000000000..d823f26de --- /dev/null +++ b/tests/ajde/examples/spacewar/coordination/MethodState.java @@ -0,0 +1,28 @@ + +package coordination; + +import java.util.Vector; +import java.util.Enumeration; + + +class MethodState { + + Vector threads=new Vector(); + + void enterInThread (Thread t) { + threads.addElement(t); + } + + void exitInThread(Thread t) { + threads.removeElement(t); + } + + boolean hasOtherThreadThan(Thread t) { + Enumeration e = threads.elements(); + while (e.hasMoreElements()) + if (e.nextElement() != t) + return(true); + return (false); + } + +} diff --git a/tests/ajde/examples/spacewar/coordination/Mutex.java b/tests/ajde/examples/spacewar/coordination/Mutex.java new file mode 100644 index 000000000..04ed900d8 --- /dev/null +++ b/tests/ajde/examples/spacewar/coordination/Mutex.java @@ -0,0 +1,69 @@ + +package coordination; + +import java.lang.String; + + +class Mutex implements Exclusion { + String[] methodNames; + MethodState[] methodStates; + + String prettyName; + + Mutex (String[] _methodNames) { + methodNames = _methodNames; + methodStates = new MethodState[methodNames.length]; + for (int i = 0; i < methodNames.length; i++) { + methodStates[i] = new MethodState(); + } + } + + private boolean isMethodIn (String _methodName) { + for (int i = 0; i < methodNames.length; i++) { + if (_methodName.equals(methodNames[i])) + return(true); + } + return(false); + } + + private MethodState getMethodState (String _methodName) { + for (int i = 0; i < methodNames.length; i++) { + if (_methodName.equals(methodNames[i])) + return(methodStates[i]); + } + return(null); + } + + public boolean testExclusion (String _methodName) { + Thread ct = Thread.currentThread(); + // + // Loop through each of the other methods in this exclusion set, to be sure + // that no other thread is running them. Note that we have to be careful + // about selfex. + // + for (int i = 0; i < methodNames.length; i++) { + if (!_methodName.equals(methodNames[i])) { + if (methodStates[i].hasOtherThreadThan(ct)) + return(false); + } + } + return (true); + } + + public void enterExclusion (String _methodName) { + MethodState methodState = getMethodState(_methodName); + methodState.enterInThread(Thread.currentThread()); + } + + public void exitExclusion (String _methodName) { + MethodState methodState = getMethodState(_methodName); + methodState.exitInThread(Thread.currentThread()); + } + + public void printNames() { + System.out.print("Mutex names: "); + for (int i = 0; i < methodNames.length; i++) + System.out.print(methodNames[i] + " "); + System.out.println(); + } +} diff --git a/tests/ajde/examples/spacewar/coordination/Selfex.java b/tests/ajde/examples/spacewar/coordination/Selfex.java new file mode 100644 index 000000000..0a28e4499 --- /dev/null +++ b/tests/ajde/examples/spacewar/coordination/Selfex.java @@ -0,0 +1,38 @@ + +package coordination; + + +import java.lang.String; + +class Selfex implements Exclusion { + String methodName; + Thread thread; + int count = 0; + + Selfex (String _methodName) { + methodName = _methodName; + } + + public boolean testExclusion (String _methodName) { + if (count == 0) + return(true); + return (thread == Thread.currentThread()); + } + + public void enterExclusion (String _methodName) { + count++; + thread = Thread.currentThread(); // note that if count wasn't 0 + // we aren't changing thread + } + + public void exitExclusion (String _methodName) { + count--; + if (count == 0) // not stricly necessary, but... + thread = null; + } + + public void printNames() { + System.out.println("Selfex name: " + methodName); + } + +} diff --git a/tests/ajde/examples/spacewar/coordination/TimeoutException.java b/tests/ajde/examples/spacewar/coordination/TimeoutException.java new file mode 100644 index 000000000..3bfddef57 --- /dev/null +++ b/tests/ajde/examples/spacewar/coordination/TimeoutException.java @@ -0,0 +1,10 @@ + +package coordination; + + +public class TimeoutException extends Exception { + long time; + TimeoutException(long _time) { + time = _time; + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/Bullet.java b/tests/ajde/examples/spacewar/spacewar/Bullet.java new file mode 100644 index 000000000..0e2a88fb3 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Bullet.java @@ -0,0 +1,27 @@ + +package spacewar; + +class Bullet extends SpaceObject { + + static private final int SIZE = 3; //Can't be changed for now!!! + static private int LIFETIME = 50; + + private int lifeLeft; + + Bullet (Game theGame, double xP, double yP, double xV, double yV) { + super(theGame, xP, yP, xV, yV); + lifeLeft = LIFETIME; + } + + int getSize() { return SIZE; } + + void handleCollision(SpaceObject obj) { + die(); + } + + void clockTick() { + if (--lifeLeft == 0) + die(); + super.clockTick(); + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/Debug.java b/tests/ajde/examples/spacewar/spacewar/Debug.java new file mode 100644 index 000000000..d65b7de48 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Debug.java @@ -0,0 +1,199 @@ + +package spacewar; + +import java.awt.Menu; +import java.awt.CheckboxMenuItem; +import java.awt.Frame; +import java.awt.TextArea; +import java.awt.Dimension; + +/** + * This aspect specifies debugging information to be output to the + * information window. + * + * When the debug aspect is compiled in the Frame menu has several checkbox + * items that can be used to control the amount of tracing information + * displayed. (By default the first three are off, because they generate + * so much information.) + * + * There are two reasons to gather all this debugging code into an aspect + * like this: + * + * (1) It makes it easier to understand when it is all in one place. + * + * (2) It means that we can "plug and debug". We can enable/disable + * the debugging code simply by weaving or not weaving this + * aspect in. + * + * All in all, this is a lot better than the usual practice of writing + * complex debugging code and then deleting it when the bug is found, + * only to regret it a month later when a related bug surfaces. (Or even + * the same bug!) + * + * This file also defines a class InfoWin, which it uses to display all the + * debugging information. + */ +aspect Debug { + + private static InfoWin infoWin = new InfoWin(); + + private static Menu menu = new Menu("Debug"); + + private static CheckboxMenuItem traceConstructors = + new CheckboxMenuItem("trace constructors", false); + private static CheckboxMenuItem traceInitializations = + new CheckboxMenuItem("trace initializations", false); + private static CheckboxMenuItem traceMethods = + new CheckboxMenuItem("trace methods", false); + private static CheckboxMenuItem traceClockTick = + new CheckboxMenuItem("trace clock tick", false); + private static CheckboxMenuItem traceRegistry = + new CheckboxMenuItem("trace registry", true); + private static CheckboxMenuItem traceFireCollideDamage = + new CheckboxMenuItem("trace fire, collide, damage", true); + + after() returning (SWFrame frame): call(SWFrame+.new(..)) { + menu.add(traceConstructors); + menu.add(traceInitializations); + menu.add(traceMethods); + menu.add(traceClockTick); + menu.add(traceRegistry); + menu.add(traceFireCollideDamage); + frame.getMenuBar().add(menu); + } + + /* + * all constructors + */ + pointcut allConstructorsCut(): + call((spacewar.* && !(Debug+ || InfoWin+)).new(..)); + + before(): allConstructorsCut() { + if (traceConstructors.getState()) { + infoWin.println("begin constructing " + thisJoinPoint.getSignature()); + } + } + + after(): allConstructorsCut() { + if (traceConstructors.getState()) { + infoWin.println("done constructing " + thisJoinPoint.getSignature()); + } + } + + /* + * All dynamic initializations + */ + pointcut allInitializationsCut(): + initialization((spacewar.* && !(Debug+ || InfoWin+)).new(..)); + + before(): allInitializationsCut() { + if (traceConstructors.getState()) { + infoWin.println("begin initializing " + thisJoinPoint.getSignature()); + } + } + after(): allInitializationsCut() { + if (traceConstructors.getState()) { + infoWin.println("done initializing " + thisJoinPoint.getSignature()); + } + } + + /* + * all methods + */ + pointcut allMethodsCut(): + execution(* (spacewar.* && !(Debug+ || InfoWin+)).*(..)); + + before(): allMethodsCut() { + if (traceMethods.getState()) { + infoWin.println("entering " + thisJoinPoint.getSignature()); + } + } + after(): allMethodsCut() { + if (traceMethods.getState()) { + infoWin.println("exiting " + thisJoinPoint.getSignature()); + } + } + + /* + * clock ticks + */ + after(Object obj): + (target(obj) && (target(Game) || + target(Registry) || + target(SpaceObject))) + && call(void clockTick()) { + if (traceClockTick.getState()) + infoWin.println("ticking " + obj); + } + + /* + * registry contents + */ + after(Registry registry): + target(registry) && (call(void register(..)) || + call(void unregister(..))) { + if (traceRegistry.getState()) + infoWin.println(registry.getTable().size() + + " space objects in the registry."); + } + + /* + * fire, collide, damage + */ + after(): call(void Ship.fire()) { + if (traceFireCollideDamage.getState()) + infoWin.println("firing"); + } + + after(Ship ship, SpaceObject obj): + call(void Ship.handleCollision(SpaceObject)) && target(ship) && args(obj) { + if (traceFireCollideDamage.getState()) + infoWin.println(ship + " collides with " + obj); + } + + after(Ship shipA, Ship shipB): + execution(void Ship.bounce(Ship, Ship)) && args(shipA, shipB) { + if (traceFireCollideDamage.getState()) + infoWin.println(shipA + " bounces with " + shipB); + } + + before(Ship ship, double amount): + call(void Ship.inflictDamage(double)) && target(ship) && args(amount) { + if (traceFireCollideDamage.getState()) + if (amount > 0) + infoWin.println(ship + "gets " + + amount + " damage (" + + ship.getDamage() + ")"); + } + +} + +class InfoWin { + private Frame frame; + private TextArea info; + + InfoWin() { + frame = new Frame("debugging info for spacewar game"); + info = new TextArea(); + info.setEditable(false); + + Dimension screenSize = frame.getToolkit().getScreenSize(); + frame.setSize(250, 600); + frame.setLocation(screenSize.width - 250, 0); + frame.add(info); + frame.show(); + frame.toFront(); + } + + void clear() { + info.setText(""); + } + + void println(String line) { + info.append(line + "\n"); + } + + void print(String line) { + info.append(line); + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/Display.java b/tests/ajde/examples/spacewar/spacewar/Display.java new file mode 100644 index 000000000..0097c02fb --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Display.java @@ -0,0 +1,146 @@ + +package spacewar; + +import java.util.Vector; +import java.util.Enumeration; +import java.awt.Graphics; +import java.awt.Canvas; +import java.awt.Image; +import java.awt.event.KeyListener; + +/** + * The display aspects capture the look and feel of the Game in modular + * pluggable units. + * + * The model is that constructing a concrete subclass of Display attaches that + * kind of display to the game. It will Display the game as it goes along. + * A game can have any number of displays. Any of the displays will accept + * keyboard input. + * + */ + +class Display extends Canvas { + + private static Vector DISPLAYS = new Vector(2); + private static Vector PLAYERS = new Vector(2); + private static Pilot pilot1, pilot2; + + Game game; + SWFrame frame; + Image offImage; + Graphics offGraphics; + + Game getGame() { return game; } + static Pilot getPilot1() { return pilot1; } + static Pilot getPilot2() { return pilot2; } + + Display(Game g) { + super(); + game = g; + + frame = new SWFrame(game, this); + DISPLAYS.addElement(this); + } + + + void noticeSizeChange() { + initializeOffImage(); + } + + private void initializeOffImage () { + int w = getSize().width; + int h = getSize().height; + if ( w > 0 & h > 0) { + offImage = createImage(w, h); + offGraphics = offImage.getGraphics(); + } + } + + /* + * In our double buffering scheme, painting just means copying the buffer + * to the screen. The Display aspect draws into the buffer. + */ + public void paint(Graphics g) { + if (offImage != null) + g.drawImage(offImage, 0, 0, null); + } + + public void update(Graphics g) { + /* + * There are 4 steps to this: + * - clear the double buffer + * - paint the objects into the double buffer + * - paint the status into the double buffer + * - paint the doublebuffer into the buffer + */ + offGraphics.setColor(getBackground()); + offGraphics.fillRect(0, 0, getBounds().width, getBounds().height); + paintObjects(offGraphics); + paintStatus(offGraphics); + g.drawImage(offImage, 0, 0, null); + } + + void paintObjects(Graphics g) { } + void paintStatus(Graphics g) {} + + static aspect DisplayAspect { + + after (String mode) returning (Game game): call(Game+.new(String)) && args(mode) { + new Display1(game); +// new Display2(game); + + if ( mode.equals("1") ) { + pilot1 = game.newPlayer(1); + } + else if ( mode.equals("2") ) { + pilot1 = game.newPlayer(1); + pilot2 = game.newPlayer(2); + } + else if (mode. equals("demo")) { + pilot1 = game.newRobot(1); + pilot2 = game.newRobot(2); + } else { + game.error("Invalid mode: " + mode); + game.quit(); + } + } + + + /* + * I'm not really sure this belongs here. + * + * Being here what it does is makes the Display aspect + * responsible for having the Players couple up to it. That's + * kind of nice, but its a bit incomplete, since Player is + * really part of the GUI, not part of the core Game. + * + * In a future re-factoring this will get worked out better. + * What will happen is that GUI will be an aspect that has the + * core GUI. Each of the different kinds of displays will be + * aspects that tie themselves in. + */ + after () returning (Player player): call(Player+.new(..)) { + Enumeration elements = DISPLAYS.elements(); + while ( elements.hasMoreElements() ) { + Display display = (Display)elements.nextElement(); + display.addKeyListener(player); + } + } + + after() returning (Display display): call(Display+.new(..)) { + display.noticeSizeChange(); + } + + after(Display display) returning (): call(void setSize(..)) && target(display) { + display.noticeSizeChange(); + } + + after(): call(void Game.clockTick()) { + Enumeration elements = DISPLAYS.elements(); + while ( elements.hasMoreElements() ) { + Display display = (Display)elements.nextElement(); + display.repaint(); + } + } + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/Display1.java b/tests/ajde/examples/spacewar/spacewar/Display1.java new file mode 100644 index 000000000..1050cacf3 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Display1.java @@ -0,0 +1,183 @@ + +package spacewar; + + +import java.util.Vector; +import java.util.Enumeration; +import java.awt.Graphics; +import java.awt.Color; +import java.util.Random; + +/** + * This is the standard display aspect. + */ +class Display1 extends Display { + /* + * Here's the color scheme for the game. No other places in this file + * should say Color.xxx. Instead, that color should be given a symbolic + * name here. + */ + private static Color backgroundColor = Color.black; + private static Color player1ShipColor = Color.white; + private static Color player2ShipColor = Color.gray; + private static Color robotShipColor = new Color(0xa00000); + private static Color flameColor = Color.red; + private static Color shipExplosionColor = Color.red; + private static Color bulletColor = Color.green; + private static Color energyPacketOuterColor = Color.blue; + private static Color energyPacketInnerColor = new Color(0x7070FF); + private static Color statusLabelsColor = Color.white; + private static Color statusMeterBorderColor = Color.white; + private static Color energyStatusMeterColor = Color.blue; + private static Color damageStatusMeterColor = Color.red; + + + Display1(Game game) { + super(game); + frame.setLocation(20, 20); + } + + void noticeSizeChange() { + super.noticeSizeChange(); + setBackground(backgroundColor); + } + + void paintObjects(Graphics g) { + SpaceObject[] objects = game.getRegistry().getObjects(); + final int len = objects.length; + for (int i = 0; i < len; i++) { + objects[i].paint(g); + } + } + + static aspect SpaceObjectPainting { + + abstract private void SpaceObject.paint(Graphics g); + + /* + * Ships are by far and away the most complex of the space Objects + * to paint. First off, we need to set the color when the ship + * is made. + */ + private Color Ship.color; + + after(Pilot pilot) returning (Ship ship): call(Ship Game.newShip(Pilot)) && args(pilot) { + if (pilot.getNumber() == 1) + ship.color = player1ShipColor; + else if (pilot.getNumber() == 2) + ship.color = player2ShipColor; + else + ship.color = robotShipColor; + } + + private void Ship.paint(Graphics g) { + final double PI = Math.PI; + int[] radius = {15, 12, -4, 12, -9, -15, -9}; + double[] angle = {0, PI * 3/4, 0, -PI * 3/4, PI/8, 0, -PI/8}; + int[] x; + int[] y; + + Random random = new Random(); + + if (this.getDamage() >= this.MAX_DAMAGE) { + int lines = 20; + x = new int[lines]; + y = new int[lines]; + g.setColor(shipExplosionColor); + for (int i = 0; i < lines; i++) { + x[i] = (int)(this.getXPos()) + random.nextInt() % 20; + y[i] = (int)(this.getYPos()) + random.nextInt() % 20; + } + for (int i = 0; i < lines; i++) + g.drawLine(x[i], y[i], x[(i + 1) % lines], y[(i + 1) % lines]); + } else { + x = new int[7]; + y = new int[7]; + + g.setColor(this.color); + + radius[5] += random.nextInt() % 3; + // convert coordinates from polar to cartesian + for (int i = 0; i < 7; i++) { + x[i] = (int) + (this.getXPos() + + Math.cos(this.getOrientation() + angle[i]) * radius[i]); + y[i] = (int) + (this.getYPos() + + Math.sin(this.getOrientation() + angle[i]) * radius[i]); + } + + // draw the body as a polygon + g.drawPolygon(x, y, 4); + + // if the ship is accelerating, draw in a flame + if (this.getRAcc() != 0) { + g.setColor(flameColor); + g.drawLine(x[4], y[4], x[5], y[5]); + g.drawLine(x[5], y[5], x[6], y[6]); + } + } + } + + /* + * Bullets + */ + private void Bullet.paint(Graphics g) { + g.setColor(bulletColor); + g.fillOval((int)this.getXPos() - 1, + (int)this.getYPos() - 1, + 3, + 3); + } + + /* + * energy packets + */ + private void EnergyPacket.paint(Graphics g) { + g.setColor(energyPacketOuterColor); + g.fillOval((int)this.getXPos() - 5, + (int)this.getYPos() - 5, + 10, 10); + g.setColor(energyPacketInnerColor); + g.fillOval((int)this.getXPos() - 2, + (int)this.getYPos() - 2, + 3, 3); + } + } + + + void paintStatus(Graphics g) { + int left1 = 60; + int top1 = 0; + + int left2 = 200; + int top2 = 0; + + g.setColor(statusLabelsColor); + g.drawString("energy:", 5, top1 + 15); + g.drawString("damage:", 5, top1 + 30); + + if (getPilot1() != null) + paintLevels(g, getPilot1().getShip(), top1, left1); + if (getPilot2() != null) + paintLevels(g, getPilot2().getShip(), top2, left2); + } + + static void paintLevels(Graphics g, Ship ship, int top, int left) { + if (ship == null) + return; + else if (ship.isAlive()) { + g.setColor(statusMeterBorderColor); + g.drawRect(left, top + 6, 101, 10); + g.drawRect(left, top + 21, 101, 10); + g.setColor(energyStatusMeterColor); + g.fillRect(left + 1, top + 7, (int)(ship.getEnergyLevel()*100), 9); + g.setColor(damageStatusMeterColor); + g.fillRect(left + 1, top + 22, (int)(ship.getDamageLevel()*100), 9); + } + else { + g.setColor(damageStatusMeterColor); + g.drawString("Ship is destroyed", left+1, top+15); + } + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/Display2.java b/tests/ajde/examples/spacewar/spacewar/Display2.java new file mode 100644 index 000000000..ee20151f0 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Display2.java @@ -0,0 +1,118 @@ + +package spacewar; + + +import java.util.Vector; +import java.util.Enumeration; +import java.awt.Graphics; +import java.awt.Color; + + +/** + * This is the cheap Display aspect. + */ +class Display2 extends Display { + + Display2(Game game) { + super(game); + frame.setLocation(540, 20); + } + + void noticeSizeChange() { + super.noticeSizeChange(); + setBackground(Color.darkGray); + } + + void paintObjects(Graphics g) { + SpaceObject[] objects = game.getRegistry().getObjects(); + final int len = objects.length; + for (int i = 0; i < len; i++) { + objects[i].paint(g); + } + } + + static aspect SpaceObjectPainting { + + abstract private void SpaceObject.paint(Graphics g); + + /* + * Ships are by far and away the most complex of the space Objects + * to paint. + */ + private Color Ship.color; + + after(Pilot pilot) returning (Ship ship): call(Ship Game.newShip(Pilot)) && args(pilot) { + if (pilot.getNumber() == 1) + ship.color = Color.white; + else if (pilot.getNumber() == 2) + ship.color = Color.gray; + else + ship.color = new Color(0xa00000); + } + + private void Ship.paint(Graphics g) { + if (this.getDamage() < this.MAX_DAMAGE) { + double x = this.getXPos(); + double y = this.getYPos(); + double sinTheta = Math.sin(this.getOrientation()); + double cosTheta = Math.cos(this.getOrientation()); + + g.setColor(color); + g.drawLine((int)(x + 8*cosTheta), (int)(y + 8*sinTheta), + (int)(x - 8*cosTheta), (int)(y - 8*sinTheta)); + + // if the ship is accelerating, draw thruster + if (this.getRAcc() != 0) { + g.setColor(Color.red); + g.fillOval((int)(x - 8*cosTheta), (int)(y - 8*sinTheta), 6, 6); + } + } + } + + private void Bullet.paint(Graphics g) { + g.setColor(Color.green); + g.fillOval((int)this.getXPos() - 1, + (int)this.getYPos() - 1, + 3, + 3); + } + + private void EnergyPacket.paint(Graphics g) { + g.setColor(Color.white); + g.fillOval((int)this.getXPos() - 5, + (int)this.getYPos() - 5, + 10, + 10); + } + } + + void paintStatus(Graphics g) { + int left1 = 60; + int top1 = 0; + + int left2 = 200; + int top2 = 0; + + g.setColor(Color.white); + g.drawString("energy:", 5, top1 + 15); + g.drawString("damage:", 5, top1 + 30); + + if (getPilot1() != null) + paintLevels(g, getPilot1().getShip(), top1, left1); + if (getPilot2() != null) + paintLevels(g, getPilot2().getShip(), top2, left2); + } + + void paintLevels(Graphics g, Ship ship, int top, int left) { + if (ship == null) + return; + else if (ship.isAlive()) { + g.drawString(Float.toString(ship.getEnergyLevel()*100), left+1, top+15); + g.drawString(Float.toString(ship.getDamageLevel()*100), left+1, top+30); + } + else { + g.setColor(Color.red); + g.drawString("Ship is destroyed", left+1, top+15); + } + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/EnergyPacket.java b/tests/ajde/examples/spacewar/spacewar/EnergyPacket.java new file mode 100644 index 000000000..33fd06051 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/EnergyPacket.java @@ -0,0 +1,23 @@ + +package spacewar; + + +class EnergyPacket extends SpaceObject { + + static private final int SIZE = 5; //Can't be changed for now!!! + int getSize() { return SIZE; } + + private double energy; + + double getEnergy() { return energy; } + + EnergyPacket(Game theGame, + double xP, double yP, double xV, double yV, double e) { + super(theGame, xP, yP, xV, yV); + energy = e; + } + + void handleCollision(SpaceObject obj) { + die(); + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/EnergyPacketProducer.java b/tests/ajde/examples/spacewar/spacewar/EnergyPacketProducer.java new file mode 100644 index 000000000..c13f1ed3d --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/EnergyPacketProducer.java @@ -0,0 +1,40 @@ + +package spacewar; + + +class EnergyPacketProducer extends Thread { + private final static int MIN = -20; + private final static int MAX = 80; + private final static int EXPECTEDINTERVAL = 15; + + private Game game; + + Game getGame() { return game; } + + EnergyPacketProducer(Game theGame) { + super("EnergyPacketProducer"); + game = theGame; + } + + public void run() { + while(true) { + produceAPacket(); + waitForABit(); + } + } + + void waitForABit() { + try { Thread.sleep((int)(Math.random() * EXPECTEDINTERVAL * 2000)); } + catch (InterruptedException e) {} + } + + void produceAPacket() { + EnergyPacket pkt = + new EnergyPacket(game, + Math.random() * getGame().getWidth(), + Math.random() * getGame().getHeight(), + Math.random() * 2 - 1, + Math.random() * 2 - 1, + Math.random() * (MAX - MIN) + MIN); + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/EnsureShipIsAlive.java b/tests/ajde/examples/spacewar/spacewar/EnsureShipIsAlive.java new file mode 100644 index 000000000..8daab4a0d --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/EnsureShipIsAlive.java @@ -0,0 +1,15 @@ + +package spacewar; + +/** + * This aspect makes sure that the ship is alive before performing any console + * commands. + * + */ +aspect EnsureShipIsAlive { + void around (Ship ship): Ship.helmCommandsCut(ship) { + if ( ship.isAlive() ) { + proceed(ship); + } + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/Game.java b/tests/ajde/examples/spacewar/spacewar/Game.java new file mode 100644 index 000000000..6b7cf6da9 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Game.java @@ -0,0 +1,172 @@ + +package spacewar; + +import java.awt.Dimension; + +/** + * The Game class is the root of the spacewar game. To start a spacewar + * game, you can either call the main method, or instantiate this class + * directly. + * + * Synchronization is done by the GameSynchronization aspect. + */ +public class Game extends Thread { + + /** + * To run the game from top level, simply say Java Game, as usual. Passing + * an argument makes the game run in demo mode. Without an argument it runs + * in the normal player mode. + */ + public static void main(String[] args) { + if ( args.length == 0 ) + new Game("1").run(); + new Game(args[0]).run(); + } + + + private Timer timer; + private EnergyPacketProducer ePP; + + private Registry registry; + private Pilot pilot1, pilot2; + + private Dimension screenSize = new Dimension(500, 500); + + Registry getRegistry() { return registry; } + Pilot getPilot1() { return pilot1; } + Pilot getPilot2() { return pilot2; } + + int getWidth() { return screenSize.width; } + int getHeight() { return screenSize.height; } + + /** + * To run the game, simply instantiate this class. It runs in its own + * thread. You can instantiate multiple games at once. For the time being + * the only way to end the game is to exit from the Java VM. + * + * @param isDemo Controls whether the game runs in demo mode or not. True + * means it is a demo, false means it runs in normal 2 player mode. + */ + public Game(String mode) { + timer = new Timer(this); + ePP = new EnergyPacketProducer(this); + registry = new Registry(this); + } + + public void run() { + timer.start(); + ePP.start(); + + while(true) { + try { + newRobot(3); + Thread.sleep(15000); + } + catch (InterruptedException e) {} + } + } + + + + /* + * These are the menu commands. + */ + void addRobot() { + newRobot(3); + } + + void resetShips() { + Ship[] ships = registry.getShips(); + + for (int i = 0; i < ships.length; i++) { + Ship ship = ships[i]; + Pilot pilot = ship.getPilot(); + newShip(pilot); + } + } + + void quit() { + System.exit(0); + } + + void error(Object o) { + System.err.println(o); + } + + + /* + * These three methods are the ONLY ways to make a Player a Robot or a Ship. + * The structural invariant is that there should be no calls to new of one + * of these three classes outside these three methods. + */ + Player newPlayer(int number) { + Player player = new Player(this, number); + newShip(player); + return player; + } + + Robot newRobot(int number) { + Robot robot = new Robot(this, number); + newShip(robot); + robot.start(); + return robot; + } + + Ship newShip(Pilot pilot) { + // + // If there is an old ship (we're doing a reset), then remove it from + // the registry. + // + Ship oldShip = pilot.getShip(); + if (! (oldShip == null)) + oldShip.die(); + + Ship newShip = new Ship(this, + Math.random() * getWidth(), + Math.random() * getHeight(), + Math.random() * Math.PI * 2); + pilot.setShip(newShip); + newShip.setPilot(pilot); + + return newShip; + } + + void clockTick() { + registry.clockTick(); + handleCollisions(); + } + + // collision detection + + void handleCollisions() { + SpaceObject[] objects = registry.getObjects(); + + SpaceObject objI, objJ; + for (int i = 0; i < objects.length; i++) { + objI = objects[i]; + for (int j = i + 1; j < objects.length; j++) { + objJ = objects[j]; + if (objI instanceof Bullet && objJ instanceof Bullet) + continue; + if (isCollision(objI, objJ)) { + if (objI instanceof Ship && objJ instanceof Ship) + Ship.bounce((Ship)(objI), (Ship)(objJ)); + else { + objI.handleCollision(objJ); + objJ.handleCollision(objI); + } + } + } + } + } + + /* + * Is the distance between the two centers less than the sum of the two + * radii. This is a cheap and dirty (i.e. wrong) implementation of this. + */ + static boolean isCollision(SpaceObject a, SpaceObject b) { + return (Math.abs(a.getXPos() - b.getXPos()) + + Math.abs(a.getYPos() - b.getYPos())) < + (a.getSize()/2 + b.getSize()/2); + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/GameSynchronization.java b/tests/ajde/examples/spacewar/spacewar/GameSynchronization.java new file mode 100644 index 000000000..18f5cbd33 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/GameSynchronization.java @@ -0,0 +1,33 @@ + +package spacewar; + +import coordination.Coordinator; + +/** + * This aspect ensures synchronized access to methods of the Game in the + * presence of several threads. + * + * It uses the Coordinator class, from the AspectJ coordination library. + * (This case is right on the borderline of being too simple to use the + * coordination library, but we use it anyways to keep the similarity + * with the RegistrySynchronizer.) + * + * It uses a per-Game coordination scheme, so there is one instance of + * this class for each instance of the Game class. When this class is + * constructed, it registers appropriate mutexes and selfexes using + * the behavior inherited from Coordinator. + * + * The coordination constraints for the Game are simple. We just need to + * make sure that newShip and handleCollisions are mutually exclusive. That + * ensures that they we can't destroy a ship that has just been replaced. + */ +aspect GameSynchronization extends Coordinator perthis(this(Game)) { + + protected pointcut synchronizationPoint(): + call(void Game.handleCollisions(..)) || call(Ship Game.newShip(..)); + + public GameSynchronization() { + addMutex(new String[] {"handleCollisions", "newShip"}); + } + +} diff --git a/tests/ajde/examples/spacewar/spacewar/Pilot.java b/tests/ajde/examples/spacewar/spacewar/Pilot.java new file mode 100644 index 000000000..833001762 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Pilot.java @@ -0,0 +1,26 @@ + +package spacewar; + + +/** + * Pilot is the abstract superclass of Player and Robot. + * + */ + +abstract class Pilot { + private Game game; + private int number; + protected Ship ship = null; + + Game getGame() { return game; } + int getNumber() { return number; } + Ship getShip() { return ship; } + + void setShip(Ship s) { ship = s; } + + Pilot (Game g, int n) { + super(); + game = g; + number = n; + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/Player.java b/tests/ajde/examples/spacewar/spacewar/Player.java new file mode 100644 index 000000000..e7655aa10 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Player.java @@ -0,0 +1,101 @@ + +package spacewar; + +import java.util.Enumeration; +import java.awt.event.KeyListener; +import java.awt.event.KeyEvent; + +class Player extends Pilot implements KeyListener { + + private KeyMapping keyMapping; + + private int rotation_direction = Ship.STOP; // current rotation key + private boolean thrust_on = false; // current thrust + + Player(Game theGame, int number) { + super(theGame,number); + + if (getNumber() == 1) + keyMapping = KeyMapping.keyMapping1; + else if (getNumber() == 2) + keyMapping = KeyMapping.keyMapping2; + + } + + public void keyPressed(KeyEvent e) { + int keyCode = e.getKeyCode(); + boolean consumed = true; + + if (keyCode == keyMapping.fire) { + ship.fire(); + } + else if (keyCode == keyMapping.thrust && !thrust_on) { + ship.thrust(true); + thrust_on = true; + } + else if (keyCode == keyMapping.right && + rotation_direction != Ship.COUNTERCLOCKWISE) { + //start rotating clockwise unless already rotating in the + //opposite direction + rotation_direction = Ship.CLOCKWISE; + ship.rotate(Ship.CLOCKWISE); + } + else if (keyCode == keyMapping.left && + rotation_direction != Ship.CLOCKWISE) { + //start rotating counterclockwise unless already rotating in the + //opposite direction + rotation_direction = Ship.COUNTERCLOCKWISE; + ship.rotate(Ship.COUNTERCLOCKWISE); + } + else { + consumed = false; + } + + if (consumed) e.consume(); + } + + public void keyReleased(KeyEvent e) { + int keyCode = e.getKeyCode(); + + if (keyCode == keyMapping.thrust) { + ship.thrust(false); //engine off + thrust_on = false; + } + else if (keyCode == keyMapping.right && + rotation_direction == Ship.CLOCKWISE + || + keyCode == keyMapping.left && + rotation_direction == Ship.COUNTERCLOCKWISE) { + ship.rotate(Ship.STOP); //stop rotation + rotation_direction = Ship.STOP; + } + } + + public void keyTyped(KeyEvent e) { + // have to implement this because it's in KeyListener + } +} + +class KeyMapping { + + static final KeyMapping keyMapping1 = + new KeyMapping(KeyEvent.VK_LEFT, + KeyEvent.VK_RIGHT, + KeyEvent.VK_UP, + KeyEvent.VK_SPACE); + + static final KeyMapping keyMapping2 = + new KeyMapping(KeyEvent.VK_X, + KeyEvent.VK_V, + KeyEvent.VK_D, + KeyEvent.VK_ALT); + + int left, right, thrust, fire; + + KeyMapping(int k_left, int k_right, int k_thrust, int k_fire) { + left = k_left; + right = k_right; + thrust = k_thrust; + fire = k_fire; + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/Registry.java b/tests/ajde/examples/spacewar/spacewar/Registry.java new file mode 100644 index 000000000..b7e3f1a7d --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Registry.java @@ -0,0 +1,105 @@ + +package spacewar; + +import java.util.Vector; +import java.util.Hashtable; +import java.util.Enumeration; + +/** + * The Registry keeps track of all the space objects that are floating around. + * It basically supports register, unregister and contents type operations. + * + * The synchronization is done by the RegistrySynchronization aspect. + */ + +class Registry { + + private Hashtable table; + private Game game; + + Game getGame() { return game; } + + Registry (Game theGame) { + game = theGame; + table = new Hashtable(); + } + + + void register(SpaceObject object) { + table.put(object, object); + } + + void unregister(SpaceObject object) { + table.remove(object); + } + + /* + * It is an invariant of the design that only two points in SpaceObject + * should call register and unregister. This aspect enforces that. + * + * Unfortunately, in the current compiler, we get a static warning when + * there are no illegal calls that this advice has no targets. That will + * be fixed in a future release. For the time being the dummy method + * just below this fixes that. + */ + static aspect RegistrationProtection { + after() returning(): + (call(void Registry.register(SpaceObject)) || + call(void Registry.unregister(SpaceObject))) && + !(within(SpaceObject) && (withincode(new(..)) || + withincode(void die()))) { + throw new IllegalAccessError( + "This is an illegal call to " + thisJoinPoint + "\n" + + "Only the constructor and the die() on SpaceObject\n" + + "should call the primitive registry operations."); + } + } + + void dummy() { // see comment above + register(getObjects()[0]); + unregister(getObjects()[0]); + } + + + SpaceObject[] getObjects() { + SpaceObject[] allObjects = new SpaceObject[table.size()]; + Enumeration elements = table.elements(); + for(int i = 0; elements.hasMoreElements(); i++) { + allObjects[i] = (SpaceObject)(elements.nextElement()); + } + return allObjects; + } + + Ship[] getShips() { + // + // First we have to put just the Ships into a vector, then we can put + // them into an array of exactly the right length. + // + Ship[] arrayOfShips; + Vector vectorOfShips = new Vector(); + Enumeration elements = table.elements(); + while (elements.hasMoreElements()) { + Object object = elements.nextElement(); + if (object instanceof Ship) { + vectorOfShips.addElement(object); + } + } + + arrayOfShips = new Ship[(vectorOfShips.size())]; + vectorOfShips.copyInto(arrayOfShips); + return arrayOfShips; + } + + Hashtable getTable() { return table; } + + // + // The protocol for clockTick is that it automatically cascades. + // + void clockTick() { + Enumeration elements = table.elements(); + while (elements.hasMoreElements()) { + ((SpaceObject)elements.nextElement()).clockTick(); + } + } +} + diff --git a/tests/ajde/examples/spacewar/spacewar/RegistrySynchronization.java b/tests/ajde/examples/spacewar/spacewar/RegistrySynchronization.java new file mode 100644 index 000000000..0612bd672 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/RegistrySynchronization.java @@ -0,0 +1,37 @@ + +package spacewar; + +import coordination.Coordinator; + + +/** + * This aspect ensures synchronized access to methods of the Registry in + * the presence of several threads. + * + * It uses the Coordinator class, from the AspectJ coordination library. + * + * It uses a per-Registry coordination scheme, so there is one instance of + * this class for each instance of the Registry class. When this class is + * constructed, it registers appropriate mutexes and selfexes using the + * behavior inherited from Coordinator. + * + * The mutating methods (register and unregister) should be self-exclusive. + * Each reader method should be mutually exclusive with the mutating + * methods. But the readers can run concurrently. */ +aspect RegistrySynchronization extends Coordinator perthis(this(Registry)) { + + protected pointcut synchronizationPoint(): + call(void Registry.register(..)) || + call(void Registry.unregister(..)) || + call(SpaceObject[] Registry.getObjects(..)) || + call(Ship[] Registry.getShips(..)); + + public RegistrySynchronization() { + addSelfex("register"); + addSelfex("unregister"); + + addMutex(new String[] {"register", "unregister", "getObjects"}); + addMutex(new String[] {"register", "unregister", "getShips"}); + } + +} diff --git a/tests/ajde/examples/spacewar/spacewar/Robot.java b/tests/ajde/examples/spacewar/spacewar/Robot.java new file mode 100644 index 000000000..5a4901f10 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Robot.java @@ -0,0 +1,179 @@ +package spacewar; + +import java.util.Random; + +/** + * Robot is an automatic pilot that now has quite a bit of intelligence. + * So, beware ! + */ +class Robot extends Pilot implements Runnable { + + private static final int FIRE_INTERVAL = 60; + private static final int REBIRTH_DELAY = 900; + + private final Random random = new Random(); + + private Thread runner; + private boolean runnable = true; + + Robot(Game theGame, int number) { + super(theGame, number); + } + + void start() { + if (runner == null) { + runner = new Thread(this); + runner.start(); + } + } + + void destroy() { + if (runner != null) { + runnable = false; + runner = null; + } + } + + + // A Robot tracks User-controlled ships and fires at them + public void run() { + Ship target = null; + + while(runnable) { + // find target ship + do { + Ship[] potentials = getGame().getRegistry().getShips(); + if(potentials.length != 0) + target = potentials[Math.abs(random.nextInt() % potentials.length)]; + sleepForABit(25); + } while (target == ship); + // main loop + int currentRotation = Ship.STOP; + int time; + boolean currentlyAccelerating = false; + double dx, dy, angleA, angleB, theta, dtheta, d, + targetVel, a, b, c, targetXVel, targetYVel; + + while(true) { + sleepForABit(FIRE_INTERVAL); + + // if my ship is destroyed, give me a new one + if (!ship.isAlive()) { + sleepForABit(REBIRTH_DELAY); + getGame().newShip(this); + } + + // find direction and distance from target to me + dx = ship.getXPos() - target.getXPos(); + if (dx < - getGame().getWidth() / 2) + dx += getGame().getWidth(); + if (dx > getGame().getWidth() / 2) + dx -= getGame().getWidth(); + dy = ship.getYPos() - target.getYPos(); + if (dy < - getGame().getHeight() / 2) + dy += getGame().getHeight(); + if (dy > getGame().getHeight() / 2) + dy -= getGame().getHeight(); + d = Math.sqrt(dx * dx + dy * dy); + angleA = Math.atan(dy / dx); + if (dx < 0) + angleA += Math.PI; + + // find relative velocity and trajectory of target + targetXVel = target.getXVel() - ship.getXVel(); + targetYVel = target.getYVel() - ship.getYVel(); + targetVel = Math.sqrt(targetXVel * targetXVel + + targetYVel * targetYVel); + angleB = Math.atan(targetYVel / targetXVel); + if (targetXVel < 0) + angleB+=Math.PI; + + // find angle between line to target and taget's direction of travel + theta = (angleA - angleB) % (2 * Math.PI); + if (theta < -Math.PI) + theta += 2 * Math.PI; + if (theta > Math.PI) + theta -= 2 * Math.PI; + + // calculate time to bullet impact using law of cosines + a = targetVel * targetVel + Ship.BULLET_SPEED * Ship.BULLET_SPEED; + b = d * targetVel * Math.cos(theta); + c = - d * d; + time = (int)((-b + Math.sqrt(b * b - 4 * a * c)) / 2 / a); + + // calculate angle and distance to bullet impact location + dx = targetXVel * time - dx; + dy = targetYVel * time - dy; + theta = Math.atan(dy / dx); + if(dx < 0) + theta += Math.PI; + + // find desired change in rotation + dtheta = (theta - ship.getOrientation()) % (2 * Math.PI); + // find the shortest path to the desired orientation; + if(dtheta < - Math.PI) + dtheta += 2 * Math.PI; + if(dtheta > Math.PI) + dtheta -= 2 * Math.PI; + + // turn if nessecary + if (dtheta > Ship.DEFAULT_ANGULAR_VELOCITY / 2) { + if (currentRotation != Ship.CLOCKWISE) + ship.rotate(currentRotation = Ship.CLOCKWISE); + } + else if (dtheta < -Ship.DEFAULT_ANGULAR_VELOCITY / 2) { + if (currentRotation != Ship.COUNTERCLOCKWISE) + ship.rotate(currentRotation = Ship.COUNTERCLOCKWISE); + } // otherwise, fire, maybe even a burst + else { + if(currentRotation != Ship.STOP) + ship.rotate(currentRotation = Ship.STOP); + if (random.nextInt() % 40 == 0) { + ship.fire(); + } + } + + // randomly accelerate + if (currentlyAccelerating && random.nextInt() % 2 == 0) + ship.thrust(currentlyAccelerating = false); + else { + if (ship.getXVel() == 0) + angleA = 0; + else + angleA = Math.atan(ship.getYVel() / ship.getXVel()); + + if (ship.getXVel() < 0) + angleA+=Math.PI; + angleB = (angleA - ship.getOrientation()) % (2 * Math.PI); + if (angleB < -Math.PI) + angleB += 2 * Math.PI; + if (angleB > Math.PI) + angleB -= 2 * Math.PI; + angleB = Math.abs(angleB); + + // angleB now represents the angle between the ship's + // orientation and velocity vector. This will be used to + // determine the probably that the ship will thrust to + // prevent ships from accelerating too much in one direction + if (random.nextInt() % (int)(12 * (Math.PI - angleB) + 1) == 0) + ship.thrust(currentlyAccelerating = true); + } + + // switch targets if current one has been destroyed + if (target.getDamage() == 100) + break; + + // randomly switch targets + if (random.nextInt() % 4000 == 0) + break; + } + } + } + + void sleepForABit (int time) { + try { + runner.sleep(time); + } + catch (InterruptedException e) {} + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/SWFrame.java b/tests/ajde/examples/spacewar/spacewar/SWFrame.java new file mode 100644 index 000000000..7161aa6b8 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/SWFrame.java @@ -0,0 +1,71 @@ + +package spacewar; + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Dimension; +import java.awt.Insets; + +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +class SWFrame extends Frame implements ActionListener { + private Game game; + private Display display; + private Menu menu; + + Game getGame() { return game; } + Display getDisplay() { return display; } + Menu getMenu() { return menu; } + + SWFrame(Game theGame, Display d) { + super("Space War!"); + + game = theGame; + + display = d; + add(display); + + // create menu + menu = new Menu("Game"); + MenuItem item1 = new MenuItem("Add Robot", new MenuShortcut('a')); + MenuItem item2 = new MenuItem("Reset Ships", new MenuShortcut('r')); + MenuItem item3 = new MenuItem("Quit", new MenuShortcut('q')); + item1.setActionCommand("Add Robot"); + item2.setActionCommand("Reset Ships"); + item3.setActionCommand("Quit"); + menu.add(item1); + menu.add(item2); + menu.add(item3); + menu.addActionListener(this); + + setMenuBar(new MenuBar()); + getMenuBar().add(menu); + + Dimension screenSize = new Dimension(500, 500); + setSize(screenSize); + setVisible(true); + toFront(); + + Insets inset = getInsets(); + int displayWidth = screenSize.width - inset.left - inset.right; + int displayHeight = screenSize.height - inset.top - inset.bottom; + display.setSize(displayWidth, displayHeight); + } + + public void actionPerformed(ActionEvent e) { + String s = e.getActionCommand(); + if (s.equals("Add Robot")) { + getGame().addRobot(); + } + else if (s.equals("Reset Ships")) { + getGame().resetShips(); + } + else if (s.equals("Quit")) { + getGame().quit(); + } + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/Ship.java b/tests/ajde/examples/spacewar/spacewar/Ship.java new file mode 100644 index 000000000..3f22b0949 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Ship.java @@ -0,0 +1,260 @@ + +package spacewar; + +class Ship extends SpaceObject { + + pointcut helmCommandsCut(Ship ship): + target(ship) && ( call(void rotate(int)) || + call(void thrust(boolean)) || + call(void fire()) ); + + + /** + * Energy and Damage are key values in the state of a ship. Energy is + * basically about fuel, and damage is about how bad a shape we are in. + * + * The energy related values are: + * MAX_ENERGY + * BULLET_ENERGY + * ACCELERATION_ENERGY_FACTOR + * energy + * + * The damage related values are: + * MAX_DAMAGE + * BULLET_DAMAGE + * COLLISION_DAMAGE_FACTOR + * damage + * + * Finally, REPAIR_RATE is the rate at which energy is consumed to fix + * damage. + * + */ + private static final int MAX_ENERGY = 100; + private static final int BULLET_ENERGY= 2; + private static final double ACCELERATION_COST_FACTOR = 0.05; + + //XXX was private + static final int MAX_DAMAGE = 100; + private static final int BULLET_DAMAGE = 15; + private static final double COLLISION_DAMAGE_FACTOR = 0.1; + + private static final double REPAIR_RATE = 0.08; + + + private static final int EXPLOSION_LENGTH = 10; + + static final int BULLET_SPEED = 10; + + static final int CLOCKWISE = 1; + static final int STOP = 0; + static final int COUNTERCLOCKWISE = (-1); + + static final double DEFAULT_ANGULAR_VELOCITY = 0.2; + static final double DEFAULT_ACCELERATION = .4; + + static private final int SIZE = 30; //Can't be changed for now!!! + + private double energy; // range: 0 to MAX_ENERGY + private double damage; // range: 0 to MAX_DAMAGE + private double orientation; // in degrees + private double angularVel; // in ??? + private double xAcc, yAcc, rAcc; // + private int countdown; // remaining explosion time + + private Pilot pilot; + + Ship(Game theGame, double xPos, double yPos, double orientation) { + super(theGame, xPos, yPos, 0, 0); + xAcc = 0; + yAcc = 0; + this.orientation = orientation; + angularVel = 0; + + energy = MAX_ENERGY; + damage = 0; + countdown = EXPLOSION_LENGTH; + } + + + int getSize() { return SIZE; } + + double getEnergy() { return energy; } + double getDamage() { return damage; } + double getOrientation() { return orientation; } + double getRAcc() { return rAcc; } + + Pilot getPilot() { return pilot; } + void setPilot (Pilot p) { pilot = p; } + + float getEnergyLevel() { + return (float)energy / (float)MAX_ENERGY; + } + float getDamageLevel() { + return (float)damage / (float)MAX_DAMAGE; + } + + // returns false if energy is out, otherwise decrements energy by amount + // and returns true + boolean expendEnergy(double amount) { + if (amount <= energy) { + energy -= amount; + return true; + } + else + return false; + } + + // increments damage by amount and handles the destruction of a ship if + // damage reaches MAX_DAMAGE. + void inflictDamage(double amount) { + if (amount < 0) // shouldn't happen + return; + damage = Math.min(MAX_DAMAGE, damage + amount); + if (damage == MAX_DAMAGE) + setIsAlive(false); + } + + void repairDamage(double amount) { + if (amount < 0) // shouldn't happen + return; + if (damage == 0) + return; + damage = Math.max(0, damage - amount); + } + + public void clockTick() { + if (! isAlive()) { + // + // If we aren't alive, but we are still in the registry, it means + // we are exploding. countdown counts the length of the explosion. + // + if (--countdown == 0) + die(); + } + else { + if (angularVel != 0) { + orientation += angularVel; + xAcc = rAcc * Math.cos(orientation); + yAcc = rAcc * Math.sin(orientation); + } + setXVel(getXVel() + xAcc); + setYVel(getYVel() + yAcc); + + //expend energy + if (!expendEnergy(rAcc * ACCELERATION_COST_FACTOR)) + rAcc = xAcc = yAcc = 0; + + // fix damage + if (energy > 10 && damage > REPAIR_RATE) { + expendEnergy(REPAIR_RATE); + repairDamage(REPAIR_RATE); + } + } + super.clockTick(); + } + + /** + * First check to make sure we have enough energy to accelerate. If + * we do, then go ahead and do so. Acceleration is in the direction + * we are already facing (i.e. orientation). + */ + void setAcceleration(double acc) { + if (acc * ACCELERATION_COST_FACTOR <= energy) { + rAcc = acc; + xAcc = rAcc * Math.cos(orientation); + yAcc = rAcc * Math.sin(orientation); + } + } + + void setAngularVelocity(double omega) { + // changing direction of rotation takes energy + if (!expendEnergy(Math.abs(omega - angularVel) / 2)) + return; + //sets amount of degree rotation per clock tick, in radians; + //clockwise is positive + angularVel = omega; + } + + void rotate(int direction) { + setAngularVelocity( + direction == CLOCKWISE ? DEFAULT_ANGULAR_VELOCITY : + direction == COUNTERCLOCKWISE ? -DEFAULT_ANGULAR_VELOCITY : + 0); + } + + void thrust(boolean onOff) { + setAcceleration(onOff ? DEFAULT_ACCELERATION : 0); + } + + void fire() { + // firing a shot takes energy + if (!expendEnergy(BULLET_ENERGY)) + return; + + //create a bullet object so it doesn't hit the ship that's firing it + double xV = getXVel() + BULLET_SPEED * (Math.cos(orientation)); + double yV = getYVel() + BULLET_SPEED * (Math.sin(orientation)); + + // create the actual bullet + new Bullet( + getGame(), + (getXPos() + ((getSize()/2 + 2) * (Math.cos(orientation))) + xV), + (getYPos() + ((getSize()/2 + 2) * (Math.sin(orientation))) + yV), + xV, + yV); + } + + + void handleCollision(SpaceObject obj) { + if (obj instanceof Ship) { + // should never be called. ship - ship collisions are handled in + // Ship.bounce(Ship shipA, Ship shipB) + } + else if (obj instanceof Bullet) { + inflictDamage(BULLET_DAMAGE); + } + else if (obj instanceof EnergyPacket) { + double packetEnergy = ((EnergyPacket)obj).getEnergy(); + energy = Math.max(0, Math.min(energy + packetEnergy, MAX_ENERGY)); + } + else { + System.err.println("collision with UFO!"); + } + } + + static void bounce(Ship shipA, Ship shipB) { + double dx, dy, denominator, + xAccA, yAccA, xAccB, yAccB, damage, + xComp, yComp, dvx, dvy; + + dx = Math.abs(shipA.getXPos() - shipB.getXPos()); + dy = Math.abs(shipA.getYPos() - shipB.getYPos()); + denominator = Math.sqrt(dx * dx + dy * dy); + xComp = dx / denominator; + yComp = dy / denominator; + xAccA = shipB.getXVel() * xComp + shipA.getXVel() * (1 - xComp) - + shipA.getXVel(); + yAccA = shipB.getYVel() * yComp + shipA.getYVel() * (1 - yComp) - + shipA.getYVel(); + xAccB = shipA.getXVel() * xComp + shipB.getXVel() * (1 - xComp) - + shipB.getXVel(); + yAccB = shipA.getYVel() * yComp + shipB.getYVel() * (1 - yComp) - + shipB.getYVel(); + shipA.accelerate(xAccA, yAccA); + shipB.accelerate(xAccB, yAccB); + dvx = shipA.getXVel() - shipB.getXVel(); + dvy = shipA.getYVel() - shipA.getYVel(); + damage = COLLISION_DAMAGE_FACTOR * (dvx * dvx + dvy * dvy); + shipA.inflictDamage(damage); + shipB.inflictDamage(damage); + + // !!! + // !!! poopers! this does a local time warp. this has to be a + // !!! violation of the clockTick protocol + // !!! + while (Game.isCollision(shipA, shipB)) { + shipA.clockTick(); + shipB.clockTick(); + } + } +} diff --git a/tests/ajde/examples/spacewar/spacewar/SpaceObject.java b/tests/ajde/examples/spacewar/spacewar/SpaceObject.java new file mode 100644 index 000000000..b02b219d9 --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/SpaceObject.java @@ -0,0 +1,81 @@ + +package spacewar; + + +/** + * SpaceObjects are objects that float around in space. They support the + * minimal SpaceObject protocol, having to do with position, velocity, + * size and liveness. They are constructed with game, position, velocity + * and size. When constructed, a spaceobject adds itself to the registry. + * + * When it dies, a spaceobject removes itself from the registry. But note + * that it doesn't decide when to die, subclasses do that. + * + * The display aspects actually draw the space object on the screen and say + * how much space it takes up there. + */ +abstract class SpaceObject { + + private Game game; + private double xPos, yPos, oldXPos, oldYPos, xVel, yVel; + private boolean alive; + + SpaceObject (Game theGame, double xP, double yP, double xV, double yV) { + game = theGame; + xPos = xP; + yPos = yP; + oldXPos = xP; + oldYPos = yP; + xVel = xV; + yVel = yV; + + alive = true; + getGame().getRegistry().register(this); + } + + Game getGame() { return game; } + + double getXPos() { return xPos; } + double getYPos() { return yPos; } + + double getOldXPos() { return oldXPos; } + double getOldYPos() { return oldYPos; } + + double getXVel() { return xVel; } + double getYVel() { return yVel; } + + void setXVel (double n) { xVel = n; } + void setYVel (double n) { yVel = n; } + + boolean isAlive() { return alive; } + void setIsAlive(boolean n) { alive = n; } + + + /** + * Move 1 unit of time's worth of distance. I.e. increment xPos by xVel + * and yPos by yVel. If we move off an edge of the screen move us back + * in the opposite edge. + */ + void clockTick() { + oldXPos = xPos; + oldYPos = yPos; + xPos = (xPos + xVel) % getGame().getWidth(); + if(xPos < 0) + xPos += getGame().getWidth(); + yPos = (yPos + yVel) % getGame().getHeight(); + if(yPos < 0) + yPos += getGame().getHeight(); + } + + void accelerate(double dXVel, double dYVel) { + xVel += dXVel; + yVel += dYVel; + } + + void die() { + getGame().getRegistry().unregister(this); + } + + abstract int getSize(); + abstract void handleCollision(SpaceObject obj); +} diff --git a/tests/ajde/examples/spacewar/spacewar/Timer.java b/tests/ajde/examples/spacewar/spacewar/Timer.java new file mode 100644 index 000000000..63b9eab1b --- /dev/null +++ b/tests/ajde/examples/spacewar/spacewar/Timer.java @@ -0,0 +1,32 @@ + +package spacewar; + + +class Timer extends Thread { + + private final static int TICK_PERIOD = 40; // time between ticks in millis + + private Game game; + + Game getGame() { return game; } + + Timer (Game theGame) { + super("Timer"); + game = theGame; + } + + public void run() { + long t1, tdiff; + while (true) { + t1 = System.currentTimeMillis(); + getGame().clockTick(); + tdiff = System.currentTimeMillis() - t1; + if (tdiff < TICK_PERIOD) { + try { + sleep (Math.max(0 , TICK_PERIOD - tdiff)); + } + catch (InterruptedException e) { } + } + } + } +} diff --git a/tests/ajde/script.html b/tests/ajde/script.html new file mode 100644 index 000000000..edc42b815 --- /dev/null +++ b/tests/ajde/script.html @@ -0,0 +1,291 @@ +<html> + +<head> +<meta http-equiv="Content-Language" content="en-us"> +<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> +<meta name="GENERATOR" content="Microsoft FrontPage 5.0"> +<meta name="ProgId" content="FrontPage.Editor.Document"> +<title>AJDE Browser</title> +<STYLE TYPE="text/css"> +<!-- + + /* FOR THE SDA PAGE */ + + /* + BODY {margin-top: 15px; margin-left: 15px; margin-right: 15px;} + */ + + A:link { + color:#4756AC; + } + A:visited { + color:#60657B; + } + A:hover { + color:red + } + + INPUT {font:12px "Courier New", sans-serif;} + + H2 { + font:18px/18px Verdana, Arial, Helvetica, sans-serif; + color:black; + font-weight:bold; + margin-left: 10px; + line-height:110%; + } + H3 { + font:18px/18px Verdana, Arial, Helvetica, sans-serif; + color:black; + font-weight:bold; + margin-left: 10px; + line-height:110%; + } + H4 { + font:15px/16px Verdana, Arial, Helvetica, sans-serif; + color:black; + font-weight:bold; + margin-left: 10px; + line-height:140%; + } + P { + font:13px/13px Verdana, Arial, Helvetica, sans-serif; + margin-right: 10px; + margin-left: 10px; + line-height:130%; + } + .paragraph { + font:13px/13px Verdana, Arial, Helvetica, sans-serif; + margin-right: 10px; + margin-left: 10px; + line-height:130%; + } + .smallParagraph { + font:11px/11px Verdana, Arial, Helvetica, sans-serif; + margin-right: 10px; + margin-left: 10px; + line-height:130%; + } + LI { + font:13px/13px Verdana, Arial, Helvetica, sans-serif; + text-align:justify; + margin-right: 10px; + margin-left: 15px; + line-height:120%; + } + /* + UL { + font:13px/13px Verdana, Arial, Helvetica, sans-serif; + text-align:justify; + margin-right: 10px; + margin-left: 15px; + line-height:120%; + }*/ + CODE { + font:11px/11px Courier New, Courier, sans-serif; + text-align:justify; + margin-right: 10px; + margin-left: 15px; + line-height:120%; + } + + DL { + font:13px/13px Verdana, Arial, Helvetica, sans-serif; + text-align:justify; + margin-right: 10px; + margin-left: 15px; + line-height:120%; + } + .footer { + font:10px/10px Verdana, Arial, Helvetica, sans-serif; + color:#888888; + text-align:left + } + .figureTitle { + font:13px/13px Verdana, Arial, Helvetica, sans-serif; + text-align:justify; + text-align:center + } + .copyrightNotice { + font:10px/10px Verdana, Arial, Helvetica, sans-serif; + color:#999999; + line-height:110%; + } + .smallHeading { + font:13px/13px Verdana, Arial, Helvetica, sans-serif; + font-weight:bold; + line-height:110%; + } + .tinyHeading { + font:11px/11px Verdana, Arial, Helvetica, sans-serif; + font-weight:bold; + line-height:120%; + } + .newsText { + font:11px/11px Verdana, Arial, Helvetica, sans-serif; + line-height:130%; + } + .smallParagraph { + font:11px/11px Verdana, Arial, Helvetica, sans-serif; + line-height:130%; + } + .fancyHeading { + font:20px/20px Chantilly, Arial, Helvetica, sans-serif; + margin-right: 10px; + color:#6f7a92; + margin-left: 10px; + line-height:130%; + } + +--> +</STYLE> +</head> + +<BODY BGCOLOR="white"> + +<h3 align="center">AJDE Test Script</h3> + +<p><b>AJBrowser Script</b></p> + + +<p>Steps 3-6 apply should be re-tested in JBuilder and Forte seperately. </p> + + +<ol> + <li>launch browser & manipulate config file set<ul> + <li>with no config file passed as command line parameter: error message</li> + <li>open config file by browsing filesystem<ul> + <li>browse and add</li> + <li>close config</li> + <li>close config: silent fail</li> + <li>compile: error message</li> + </ul> + </li> + <li>with multiple config files passed as command line parameters<ul> + <li>a file specified by its full path</li> + <li>a file specified by its relative path</li> + <li>non ".lst" file: file not added to configs list</li> + <li>a file with an incorrect suffix: not added to list</li> + </ul> + </li> + </ul> + </li> + <li><font color="#000080">run</font><ul> + <li><font color="#000080">with no class selected: error dialog</font></li> + <li><font color="#000080">with a non-main class selected: error dialog</font></li> + <li><font color="#000080">with a correct main class selected</font></li> + </ul> + </li> + <li><font color="#000080">debug</font><ul> + <li><font color="#000080">with no class selected: error dialog</font></li> + <li><font color="#000080">with a non-main class selected: error dialog</font></li> + <li><font color="#000080">with a correct main class selected</font></li> + </ul> + </li> + <li>compile<ul> + <li>no config file present: error message</li> + <li>non-existing config file: error message</li> + <li>invalid config file: error dialog<ul> + <li><font color="#008080">incorrect entry: error message seeks to + corresponding line</font></li> + <li><font color="#008080">non-existing file: error message seeks to + corresponding line</font></li> + </ul> + </li> + <li>compile error-generating code: compiler error, failed build reported<ul> + <li>seek to compiler message</li> + <li>recompile: messages pane disappears</li> + </ul> + </li> + <li>compile warning-generating code: compiler warning, successful build + reported</li> + <li><font color="#008080">compile and generate compiler error: error message</font></li> + <li><font color="#008080">compile and generate OutOfMemoryError: error + message</font></li> + <li><font color="#008080">compile and abort: aborted build reported</font></li> + <li>compile valid code: successful build reported</li> + </ul> + </li> + <li>browse structure (expand this section)<ul> + <li>test modes<ul> + <li>global view</li> + <li>file view</li> + <li>split views</li> + </ul> + </li> + <li>expand/collapse tree levels using slider</li> + <li>close and re-launch browser: previously saved structure tree should be + present</li> + </ul> + </li> + <li><font color="#008080">edit ".lst" file</font><ul> + <li><font color="#008080">select for editing and verify integrity of package/file structure</font></li> + <li><font color="#008080">select/deselect nodes and save</font></li> + <li><font color="#008080">verify saves committed to disk</font></li> + <li><font color="#008080">break ".lst" file on disk: error dialog</font></li> + <li><font color="#008080">coverage: when compilation breaks</font></li> + <li><font color="#008080">coverage: when aspectjrt.jar not present on + classpath</font></li> + </ul> + </li> + <li>user preferences<ul> + <li>set options in "Properties" window</li> + <li>close and re-launch browser</li> + <li>verify properties<ul> + <li>Build Options<ul> + <li>non-standard options</li> + </ul> + </li> + </ul> + </li> + </ul> + </li> + <li>error handler<ul> + <li>verify that the error handler shows stack trace</li> + </ul> + </li> +</ol> + + +<p><b>AJDE/JBuilder</b></p> +<ol> + <li>launch<ul> + <li>AJDE startup message appears</li> + <li>no AJDE listeners are enabled until AJDE started (whitebox)</li> + </ul> + </li> + <li>make new project<ul> + <li>*any* combination of parameters to the new project wizard should work</li> + <li>add packages</li> + <li>add single files</li> + </ul> + </li> + <li>start AJDE</li> + <li>repeat AJBrowser tests</li> + <li>inline annotations<ul> + <li>line with a single annotation</li> + <li>line with multiple annotations</li> + </ul> + </li> +</ol> +<p><b>AJDE/Forte</b></p> +<ol> + <li>launch<ul> + <li>AJDE startup message appears</li> + <li>no AJDE listeners are enabled until AJDE started (whitebox)</li> + </ul> + </li> + <li>make new project<ul> + <li>*any* combination of parameters to the new project wizard should work</li> + <li>add packages</li> + <li>add single files</li> + </ul> + </li> + <li>start AJDE</li> + <li>repeat AJBrowser tests</li> +</ol> + + +</body> + +</html>
\ No newline at end of file |