aboutsummaryrefslogtreecommitdiffstats
path: root/tests/ajde
diff options
context:
space:
mode:
authorwisberg <wisberg>2002-12-16 18:51:06 +0000
committerwisberg <wisberg>2002-12-16 18:51:06 +0000
commit144143c2970a1e874d74cdbd0f8c622d4282a3c3 (patch)
treeb12383d3d9e76c7e1f25f7fbec83051ef17f81fb /tests/ajde
parentfafae443719b26159ab2d7dac1c9b46b5e00b671 (diff)
downloadaspectj-144143c2970a1e874d74cdbd0f8c622d4282a3c3.tar.gz
aspectj-144143c2970a1e874d74cdbd0f8c622d4282a3c3.zip
initial version
Diffstat (limited to 'tests/ajde')
-rw-r--r--tests/ajde/examples/figures-cacm/Test_Figures_CACM.jpx26
-rw-r--r--tests/ajde/examples/figures-cacm/figures/Display.java9
-rw-r--r--tests/ajde/examples/figures-cacm/figures/DisplayUpdating.java15
-rw-r--r--tests/ajde/examples/figures-cacm/figures/FactoryEnforcement.java12
-rw-r--r--tests/ajde/examples/figures-cacm/figures/Figure.java23
-rw-r--r--tests/ajde/examples/figures-cacm/figures/FigureElement.java8
-rw-r--r--tests/ajde/examples/figures-cacm/figures/Line.java23
-rw-r--r--tests/ajde/examples/figures-cacm/figures/Main.java17
-rw-r--r--tests/ajde/examples/figures-cacm/figures/Point.java33
-rw-r--r--tests/ajde/examples/figures-cacm/figures/PointBoundsChecking.java13
-rw-r--r--tests/ajde/examples/figures-cacm/figures/SimpleTracing.java13
-rw-r--r--tests/ajde/examples/figures-coverage/Test_Figures_Coverage.jpr25
-rw-r--r--tests/ajde/examples/figures-coverage/Test_Figures_Coverage.jpx37
-rw-r--r--tests/ajde/examples/figures-coverage/Trace.aj4
-rw-r--r--tests/ajde/examples/figures-coverage/_JoinpointProbe.java3
-rw-r--r--tests/ajde/examples/figures-coverage/editor/Editor.java4
-rw-r--r--tests/ajde/examples/figures-coverage/figures/Debug.java7
-rw-r--r--tests/ajde/examples/figures-coverage/figures/Figure.java78
-rw-r--r--tests/ajde/examples/figures-coverage/figures/FigureElement.java9
-rw-r--r--tests/ajde/examples/figures-coverage/figures/Main.java48
-rw-r--r--tests/ajde/examples/figures-coverage/figures/Trace.aj4
-rw-r--r--tests/ajde/examples/figures-coverage/figures/composites/Line.java6
-rw-r--r--tests/ajde/examples/figures-coverage/figures/composites/Square.java6
-rw-r--r--tests/ajde/examples/figures-coverage/figures/primitives/planar/Point.java65
-rw-r--r--tests/ajde/examples/figures-coverage/figures/primitives/solid/SolidPoint.java24
-rw-r--r--tests/ajde/examples/observer-gof/Test_Observer.jpx25
-rw-r--r--tests/ajde/examples/observer-gof/clock/AnalogClock.java12
-rw-r--r--tests/ajde/examples/observer-gof/clock/Clock.java5
-rw-r--r--tests/ajde/examples/observer-gof/clock/ClockTimer.java33
-rw-r--r--tests/ajde/examples/observer-gof/clock/DigitalClock.java26
-rw-r--r--tests/ajde/examples/observer-gof/clock/Main.java14
-rw-r--r--tests/ajde/examples/observer-gof/clock/MonitorObservation.java9
-rw-r--r--tests/ajde/examples/observer/Test_Observer.jpx23
-rw-r--r--tests/ajde/examples/observer/clock/AnalogueClock.java21
-rw-r--r--tests/ajde/examples/observer/clock/ClockTimer.java23
-rw-r--r--tests/ajde/examples/observer/clock/DigitalClock.java30
-rw-r--r--tests/ajde/examples/observer/clock/Main.java15
-rw-r--r--tests/ajde/examples/observer/clock/MonitorObservation.java14
-rw-r--r--tests/ajde/examples/spacewar/Test_Spacewar.jpx28
-rw-r--r--tests/ajde/examples/spacewar/coordination/Condition.java20
-rw-r--r--tests/ajde/examples/spacewar/coordination/CoordinationAction.java20
-rw-r--r--tests/ajde/examples/spacewar/coordination/Coordinator.java432
-rw-r--r--tests/ajde/examples/spacewar/coordination/Exclusion.java16
-rw-r--r--tests/ajde/examples/spacewar/coordination/MethodState.java28
-rw-r--r--tests/ajde/examples/spacewar/coordination/Mutex.java69
-rw-r--r--tests/ajde/examples/spacewar/coordination/Selfex.java38
-rw-r--r--tests/ajde/examples/spacewar/coordination/TimeoutException.java10
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Bullet.java27
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Debug.java199
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Display.java146
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Display1.java183
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Display2.java118
-rw-r--r--tests/ajde/examples/spacewar/spacewar/EnergyPacket.java23
-rw-r--r--tests/ajde/examples/spacewar/spacewar/EnergyPacketProducer.java40
-rw-r--r--tests/ajde/examples/spacewar/spacewar/EnsureShipIsAlive.java15
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Game.java172
-rw-r--r--tests/ajde/examples/spacewar/spacewar/GameSynchronization.java33
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Pilot.java26
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Player.java101
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Registry.java105
-rw-r--r--tests/ajde/examples/spacewar/spacewar/RegistrySynchronization.java37
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Robot.java179
-rw-r--r--tests/ajde/examples/spacewar/spacewar/SWFrame.java71
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Ship.java260
-rw-r--r--tests/ajde/examples/spacewar/spacewar/SpaceObject.java81
-rw-r--r--tests/ajde/examples/spacewar/spacewar/Timer.java32
-rw-r--r--tests/ajde/script.html291
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 &amp; 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 &quot;.lst&quot; 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 &quot;.lst&quot; 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 &quot;.lst&quot; 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 &quot;Properties&quot; 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