]> source.dussan.org Git - aspectj.git/commitdiff
Adding scrubbed demos (figures & spacewar), scripts, slides, and Eclipse project...
authormkersten <mkersten>
Mon, 10 Nov 2003 19:11:18 +0000 (19:11 +0000)
committermkersten <mkersten>
Mon, 10 Nov 2003 19:11:18 +0000 (19:11 +0000)
66 files changed:
docs/teaching/demos/figures/.classpath [new file with mode: 0644]
docs/teaching/demos/figures/.project [new file with mode: 0644]
docs/teaching/demos/figures/build.xml [new file with mode: 0644]
docs/teaching/demos/figures/readme.html [new file with mode: 0644]
docs/teaching/demos/figures/scratch/HistoryUpdating.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/Box.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/Canvas.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/ColorControl.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/FigureElement.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/Group.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/Line.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/Point.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/ShapeFigureElement.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/SlothfulPoint.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/gui/FigurePanel.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/gui/LogAdapter.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/gui/Main.java [new file with mode: 0644]
docs/teaching/demos/figures/src-fresh/figures/support/Log.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/Box.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/Canvas.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/ColorControl.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/FigureElement.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/Group.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/Line.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/Point.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/ShapeFigureElement.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/SlothfulPoint.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/gui/FigurePanel.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/gui/LogAdapter.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/gui/Main.java [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/support/HistoryUpdating.aj [new file with mode: 0644]
docs/teaching/demos/figures/src/figures/support/Log.java [new file with mode: 0644]
docs/teaching/demos/oopsla2003-mik.ppt [new file with mode: 0644]
docs/teaching/demos/readme.txt [new file with mode: 0644]
docs/teaching/demos/spacewar/.classpath [new file with mode: 0644]
docs/teaching/demos/spacewar/.project [new file with mode: 0644]
docs/teaching/demos/spacewar/debug.lst [new file with mode: 0644]
docs/teaching/demos/spacewar/readme.html [new file with mode: 0644]
docs/teaching/demos/spacewar/release.lst [new file with mode: 0644]
docs/teaching/demos/spacewar/src/coordination/Condition.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/coordination/CoordinationAction.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/coordination/Coordinator.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/coordination/Exclusion.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/coordination/MethodState.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/coordination/Mutex.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/coordination/Selfex.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/coordination/TimeoutException.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Bullet.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Debug.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Display.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Display1.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Display2.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/EnergyPacket.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/EnergyPacketProducer.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/EnsureShipIsAlive.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Game.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/GameSynchronization.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Pilot.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Player.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Registry.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/RegistrySynchronization.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Robot.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/SWFrame.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Ship.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/SpaceObject.java [new file with mode: 0644]
docs/teaching/demos/spacewar/src/spacewar/Timer.java [new file with mode: 0644]

diff --git a/docs/teaching/demos/figures/.classpath b/docs/teaching/demos/figures/.classpath
new file mode 100644 (file)
index 0000000..8ae844d
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+    <classpathentry kind="src" path="src"/>
+    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+    <classpathentry kind="lib" path="C:/AspectJ-Demo/apps/eclipse-3.0/plugins/org.aspectj.ajde_1.1.4/aspectjrt.jar"/>
+    <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/docs/teaching/demos/figures/.project b/docs/teaching/demos/figures/.project
new file mode 100644 (file)
index 0000000..ccc6028
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>figures</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.ajdt.ui.ajbuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.ajdt.ui.ajnature</nature>
+               <nature>org.eclipse.ajdt.ui.ajnature</nature>
+       </natures>
+</projectDescription>
diff --git a/docs/teaching/demos/figures/build.xml b/docs/teaching/demos/figures/build.xml
new file mode 100644 (file)
index 0000000..2816008
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" ?>
+<!-- writen for Ant 1.5.1 -->
+<project name="figures" default="reset">
+
+<target name="reset" description="Reset the demonstration system sources">
+ <delete>
+       <fileset dir="src"/>
+ </delete>
+ <copy todir="src">
+   <fileset dir="src-fresh"/>
+ </copy>
+</target>
+
+</project>
\ No newline at end of file
diff --git a/docs/teaching/demos/figures/readme.html b/docs/teaching/demos/figures/readme.html
new file mode 100644 (file)
index 0000000..49e5939
--- /dev/null
@@ -0,0 +1,299 @@
+
+<head>
+<style>
+<!--
+ table.MsoNormalTable
+       {mso-style-parent:"";
+       font-size:10.0pt;
+       font-family:"Times New Roman";
+       }
+-->
+</style>
+<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%; 
+       }*/
+       
+       DL {
+               font:13px/13px Verdana, Arial, Helvetica, sans-serif;
+               text-align:justify; 
+               margin-right: 10px;
+               margin-left: 15px;
+               line-height:120%; 
+       }
+       B { font:13px/13px Verdana, Arial, Helvetica, sans-serif; 
+               font-weight:bold; 
+               line-height:140%;
+       }
+       .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>
+
+<h2 align="center">AspectJ Figures Demo Instructions</h2>
+<h4>Setup</h4>
+<ul>
+       <li>
+       <p style="text-align: left">src: contains the end result of the demo, with the Canvas.updateHistory() 
+       call refactored into the src/figures/support/HistoryUpdating.aj aspect</li>
+       <li>
+       <p style="text-align: left">src-fresh: contains the plain Java sources that the demo starts with</li>
+</ul>
+<h4>Reset </h4>
+<ul>
+       <li>run the &quot;reset&quot; target in build.xml to reset overwrite the sources in 
+       src with those in src-fresh</li>
+</ul>
+<h4>Script</h4>
+<div align="center">
+       <table class="MsoNormalTable" border="0" cellspacing="3" cellpadding="0" style="width: 531.65pt; margin-left: -7.95pt" id="table1">
+               <tr style="height: 33.45pt">
+                       <td style="width: 231px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">Show Figure editor running</span></p>
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">Inspect Point.java</span></p>
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">Use joinpoint probe or Eclipse search to find calls</span></td>
+                       <td style="width: 461px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">call(void 
+                       figures.Canvas.updateHistory())</font></span></td>
+               </tr>
+               <tr style="height: 33.45pt">
+                       <td style="width: 231px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">Describe places that it\92s called</span></p>
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">create aspect (defines a special class that can crosscut other 
+                       classes)</span></p>
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">aspect HistoryUpdating </span></p>
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">write pointcut (has name and parameters)</span></td>
+                       <td style="width: 461px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">pointcut moves(): 
+                       </font> </span></p>
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">&nbsp;&nbsp;&nbsp; execution(void 
+                       Line.setP1(Point)) || </font> </span></p>
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">&nbsp;&nbsp;&nbsp; execution(void 
+                       Line.setP2(Point));</font></span></td>
+               </tr>
+               <tr style="height: 33.45pt">
+                       <td style="width: 231px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">write after advice (runs \93on the way back out\94)</span></td>
+                       <td style="width: 461px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">after() returning: move() { <br>
+                       &nbsp;&nbsp; &lt;runs after each move&gt; }</font></span></td>
+               </tr>
+               <tr style="height: 33.45pt">
+                       <td style="width: 231px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">extend advice to Point setters (multi-class)</span></td>
+                       <td style="width: 461px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">call(void FigureElement+.set*(..))</font></span></td>
+               </tr>
+               <tr style="height: 33.45pt">
+                       <td style="width: 231px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">capture context &amp; use interface</span></td>
+                       <td style="width: 461px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">move(FigureElement fe): 
+                       this(fe) 
+                       &amp;&amp;..</font></span></td>
+               </tr>
+               <tr style="height: 33.45pt">
+                       <td style="width: 231px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">Show structure, note that SlothfulPoint is now included</span></p>
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">Run &amp; show effect</span></td>
+                       <td style="width: 461px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">&nbsp;</font></span></td>
+               </tr>
+               <tr style="height: 33.45pt">
+                       <td style="width: 231px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">Show Point.moveBy history violoation</span></p>
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">Want to make sure that sets of private fields of classes implementing 
+                       FigureElement only happen from within the set methods</span></td>
+                       <td style="width: 461px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">declare warning: 
+                       </font> </span></p>
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">&nbsp;&nbsp;&nbsp; set(private * FigureElement+.*) &nbsp;<br>
+&nbsp;&nbsp;&nbsp; &amp;&amp; !(withincode(* 
+                       FigureElement+.set*(..)) || <br>
+&nbsp;&nbsp;&nbsp; withincode(FigureElement+.new(..))):</font></span></p>
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family: Courier"><font size="1">&nbsp;&nbsp;&nbsp; &quot;should only assign to fields 
+                       from set methods&quot;;</font></span></td>
+               </tr>
+               <tr style="height: 33.45pt">
+                       <td style="width: 231px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="text-indent: -.25in; margin-left: 40.5pt">
+                       <span style="font-size: 10.0pt; font-family: Symbol">·<span style="font:7.0pt &quot;Times New Roman&quot;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                       </span></span><span style="font-size:10.0pt;font-family:
+  Tahoma">Write before advice that does precondition checking on Points.</span></td>
+                       <td style="width: 461px; height: 33.45pt; padding: 1.5pt; background: #F7F7F7">
+                       <p class="MsoNormal" style="margin-left:7.5pt">
+                       <span style="font-family:&quot;Courier New&quot;"><font size="2">before(int</font><font size="2"> 
+                       newValue): <br>
+                       &nbsp;&nbsp;&nbsp; set(int Point.*) &amp;&amp; args(newValue) {<br>
+                       &nbsp;&nbsp;&nbsp; if (newValue &lt; 0) {<br>
+                       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IAE(&quot;too small&quot;);<br>
+                       &nbsp;&nbsp;&nbsp; } <br>
+                       }</font></span></td>
+               </tr>
+       </table>
+</div>
+<p>&nbsp;</p>
diff --git a/docs/teaching/demos/figures/scratch/HistoryUpdating.java b/docs/teaching/demos/figures/scratch/HistoryUpdating.java
new file mode 100644 (file)
index 0000000..f4eff3d
--- /dev/null
@@ -0,0 +1,27 @@
+package figures.support;
+
+import figures.*;
+
+public aspect HistoryUpdating {
+
+       pointcut moves(FigureElement fe):
+               this(fe) &&
+               execution(void FigureElement+.set*(..));
+       
+       after(FigureElement fe) returning: moves(fe) {
+               Canvas.updateHistory(fe);
+       }
+       
+       declare error:
+               set(private * FigureElement+.*) &&
+               !(withincode(void FigureElement+.set*(..)) ||
+                 withincode(FigureElement+.new(..))): 
+               "doh!!!";
+       
+       before(int newValue): 
+               set(int Point.*) && args(newValue) {
+               if (newValue < 0) {
+                       throw new IllegalArgumentException("too small");
+               } 
+       }
+}
diff --git a/docs/teaching/demos/figures/src-fresh/figures/Box.java b/docs/teaching/demos/figures/src-fresh/figures/Box.java
new file mode 100644 (file)
index 0000000..4db7f43
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Box extends ShapeFigureElement {
+    private Point _p0;
+    private Point _p1;
+    private Point _p2;
+    private Point _p3;
+
+    public Box(int x0, int y0, int width, int height) {
+        _p0 = new Point(x0, y0);
+        _p1 = new Point(x0+width, y0);
+        _p2 = new Point(x0+width, y0+height);
+        _p3 = new Point(x0, y0+height);
+    }
+
+    public Point getP0() { return _p0; }
+    public Point getP1() { return _p1; }
+    public Point getP2() { return _p2; }
+    public Point getP3() { return _p3; }
+
+    public void move(int dx, int dy) {
+        _p0.move(dx, dy);
+        _p1.move(dx, dy);
+        _p2.move(dx, dy);
+        _p3.move(dx, dy);
+    }
+
+    public void checkBoxness() {
+        if ((_p0.getX() == _p3.getX()) &&
+            (_p1.getX() == _p2.getX()) &&
+            (_p0.getY() == _p1.getY()) &&
+            (_p2.getY() == _p3.getY()))
+          return;
+        throw new IllegalStateException("This is not a square.");
+    }
+
+    public String toString() {
+        return "Box(" + _p0 + ", " + _p1 + ", " + _p2 + ", " + _p3 + ")";
+    }
+
+    public Shape getShape() {
+        return new Rectangle(getP1().getX(),
+                             getP1().getY(),
+                             getP3().getX() - getP1().getX(),
+                             getP3().getY() - getP1().getY());
+    }
+}
+
diff --git a/docs/teaching/demos/figures/src-fresh/figures/Canvas.java b/docs/teaching/demos/figures/src-fresh/figures/Canvas.java
new file mode 100644 (file)
index 0000000..ef849a5
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+package figures;
+
+import figures.support.Log;
+
+public class Canvas {
+       public static void updateHistory() { }
+
+       public static void updateHistory(FigureElement fe) {
+               System.out.println("> updating history for: " + fe);
+       }  
+}
diff --git a/docs/teaching/demos/figures/src-fresh/figures/ColorControl.java b/docs/teaching/demos/figures/src-fresh/figures/ColorControl.java
new file mode 100644 (file)
index 0000000..46d1ba4
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.Color;
+import figures.FigureElement;
+
+public aspect ColorControl {
+    public static void setFillColor(FigureElement fe, Color color) {
+       // fill in here
+    }
+
+    public static void setLineColor(FigureElement fe, Color color) {
+       // fill in here
+    }
+
+    // fill in here
+}
diff --git a/docs/teaching/demos/figures/src-fresh/figures/FigureElement.java b/docs/teaching/demos/figures/src-fresh/figures/FigureElement.java
new file mode 100644 (file)
index 0000000..ae06c13
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public interface FigureElement {
+    public static final int MIN_VALUE = 0;
+    public static final int MAX_VALUE = 500;
+
+    public abstract void move(int dx, int dy);
+
+    public abstract Rectangle getBounds();
+
+    public abstract boolean contains(Point2D p);
+
+    public abstract void paint(Graphics2D g2);
+}
diff --git a/docs/teaching/demos/figures/src-fresh/figures/Group.java b/docs/teaching/demos/figures/src-fresh/figures/Group.java
new file mode 100644 (file)
index 0000000..59c1a17
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Group implements FigureElement {
+    private Collection _members;
+    private String _identifier;
+
+    public Group(FigureElement first) {
+        this._members = new ArrayList();
+        add(first);
+    }
+
+    public void add(FigureElement fe) {
+        _members.add(fe);
+    }
+
+    public Iterator members() {
+        return _members.iterator();
+    }
+
+    public void move(int dx, int dy) {
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            fe.move(dx, dy);
+        }
+    }
+
+    public void resetIdentifier(String identifier) {
+        resetIdentifier(identifier);
+    }
+
+    public String toString() {
+        if (_identifier != null) {
+            return _identifier;
+        }
+
+        StringBuffer buf = new StringBuffer("Group(");
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            buf.append(i.next().toString());
+            if (i.hasNext()) {
+                buf.append(", ");
+            }
+        }
+        buf.append(")");
+        return buf.toString();
+    }
+
+    public Rectangle getBounds() {
+        Rectangle previous = null;
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            Rectangle rect = fe.getBounds();
+            if (previous != null) {
+                previous = previous.union(rect);
+            } else {
+                previous = rect;
+            }
+        }
+        return previous;
+    }
+
+    public boolean contains(Point2D p) {
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            if (fe.contains(p)) return true;
+        }
+        return false;
+    }
+
+    public void paint(Graphics2D g2) {
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            fe.paint(g2);
+        }
+    }
+
+    public int size() {
+        return _members.size();
+    }
+}
+
diff --git a/docs/teaching/demos/figures/src-fresh/figures/Line.java b/docs/teaching/demos/figures/src-fresh/figures/Line.java
new file mode 100644 (file)
index 0000000..e762066
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Line extends ShapeFigureElement {
+    private Point _p1;
+    private Point _p2;
+
+    public Line(Point p1, Point p2) {
+        _p1 = p1;
+        _p2 = p2;
+    }
+
+    public Point getP1() { 
+       return _p1; 
+    }
+  
+       public void setP1(Point p1) {
+               _p1 = p1;       
+               Canvas.updateHistory();
+       }
+    
+    public Point getP2() { 
+       return _p2; 
+    }
+
+       public void setP2(Point p2) {
+               _p2 = p2;       
+               Canvas.updateHistory();
+       }
+
+    public void move(int dx, int dy) {
+        _p1.move(dx, dy);
+        _p2.move(dx, dy);
+    }
+
+    public String toString() {
+        return "Line(" + _p1 + ", " + _p2 + ")";
+    }
+
+    /**
+     * Used to determine if this line {@link contains(Point2D)} a point.
+     */
+    final static int THRESHHOLD = 5;
+
+    /**
+     * Returns <code>true</code> if the point segment distance is less than
+     * {@link THRESHHOLD}.
+     */
+    public boolean contains(Point2D p) {
+        return getLine2D().ptLineDist(p) < THRESHHOLD;
+    }
+
+    private Line2D getLine2D() {
+       return new Line2D.Float((float)getP1().getX(),
+                                (float)getP1().getY(),
+                                (float)getP2().getX(),
+                                (float)getP2().getY());
+    }
+
+    public Shape getShape() {
+        return getLine2D();
+    }
+}
+
diff --git a/docs/teaching/demos/figures/src-fresh/figures/Point.java b/docs/teaching/demos/figures/src-fresh/figures/Point.java
new file mode 100644 (file)
index 0000000..9699aaf
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Point extends ShapeFigureElement {
+    private int _x;
+    private int _y;
+
+    public Point(int x, int y) {
+        _x = x;
+        _y = y;
+    }
+
+    public int getX() { 
+       return _x; 
+    }
+
+    public void setX(int x) { 
+       _x = x; 
+               Canvas.updateHistory();
+    }
+
+    public int getY() { 
+       return _y; 
+    }
+
+    public void setY(int y) { 
+       _y = y; 
+       Canvas.updateHistory();
+    }
+
+    public void move(int dx, int dy) {
+               _x += dx;
+       _y += dy;        
+    }
+
+    public String toString() {
+        return "Point(" + _x + ", " + _y + ")";
+    }
+
+    /** The height of displayed {@link Point}s. */
+    private final static int HEIGHT = 10;
+
+    /** The width of displayed {@link Point}s. -- same as {@link HEIGHT}. */
+    private final static int WIDTH  = Point.HEIGHT;
+
+    public Shape getShape() {
+       return new Ellipse2D.Float((float)getX()-Point.WIDTH/2,
+                                   (float)getY()-Point.HEIGHT/2,
+                                   (float)Point.HEIGHT,
+                                   (float)Point.WIDTH);
+    }
+}
+
diff --git a/docs/teaching/demos/figures/src-fresh/figures/ShapeFigureElement.java b/docs/teaching/demos/figures/src-fresh/figures/ShapeFigureElement.java
new file mode 100644 (file)
index 0000000..29a4a89
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public abstract class ShapeFigureElement implements FigureElement {
+    public abstract void move(int dx, int dy);
+
+    public abstract Shape getShape();
+
+    public Rectangle getBounds() {
+        return getShape().getBounds();
+    }
+
+    public boolean contains(Point2D p) {
+        return getShape().contains(p);
+    }
+
+    public Color getLineColor() {
+        return Color.black;
+    }
+
+    public Color getFillColor() {
+        return Color.red;
+    }
+
+    public final void paint(Graphics2D g2) {
+        Shape shape = getShape();
+        g2.setPaint(getFillColor());
+        g2.fill(shape);
+        g2.setPaint(getLineColor());
+        g2.draw(shape);
+    }
+}
diff --git a/docs/teaching/demos/figures/src-fresh/figures/SlothfulPoint.java b/docs/teaching/demos/figures/src-fresh/figures/SlothfulPoint.java
new file mode 100644 (file)
index 0000000..6209703
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+/**
+ * This class makes mistakes to be caught by invariant checkers.
+ */
+public class SlothfulPoint extends ShapeFigureElement {
+    private int _x;
+    private int _y;
+
+    public SlothfulPoint(int x, int y) {
+    }
+
+    public void setX(int x) { 
+       _x = x; 
+    }
+    
+    public void setY(int y) { 
+       _y = y; 
+    }
+
+    public void move(int dx, int dy) {
+               setX(_x + dx);
+               setY(_y + dy);
+    }
+
+    public String toString() {
+        return "SlothfulPoint";
+    }
+
+    public Shape getShape() {
+       return new Ellipse2D.Float((float)_x,
+                                   (float)_y, 1.0f, 1.0f);
+    }
+}
+
diff --git a/docs/teaching/demos/figures/src-fresh/figures/gui/FigurePanel.java b/docs/teaching/demos/figures/src-fresh/figures/gui/FigurePanel.java
new file mode 100644 (file)
index 0000000..cac59e8
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures.gui;
+
+import figures.Point;
+import figures.Line;
+import figures.FigureElement;
+import figures.Group;
+
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.border.*;
+
+public class FigurePanel extends JComponent {
+
+    ButtonsPanel bp = new ButtonsPanel();
+    FigureSurface fs = new FigureSurface();
+    ConsolePanel cp = new ConsolePanel();
+
+
+    public FigurePanel() {
+        setLayout(new BorderLayout());
+        JPanel panel = new JPanel();
+        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+        panel.add(fs);
+        panel.add(bp);
+        JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, panel, cp);
+        sp.setPreferredSize(new Dimension(500, 400));
+        sp.setDividerLocation(250);
+        add(BorderLayout.CENTER, sp);
+    }
+
+    class ButtonsPanel extends JPanel {
+        private JLabel msgs = new JLabel("click to add a point or line");
+        public ButtonsPanel() {
+            setLayout(new FlowLayout(FlowLayout.LEFT));
+//            add(new JButton(new AbstractAction("Main") {
+//                    public void actionPerformed(ActionEvent e) {
+//                        Main.main(new String[]{});
+//                        fs.repaint();
+//                    }
+//                }));
+            add(msgs);
+        }
+
+        public void log(String msg) {
+            msgs.setText(msg);
+        }
+    }
+
+    static class ConsolePanel extends JPanel {
+
+        JTextArea text = new JTextArea();
+
+        public ConsolePanel() {
+            super(new BorderLayout());
+            text.setFont(StyleContext.getDefaultStyleContext().getFont("SansSerif", Font.PLAIN, 10));
+            JScrollPane scroller = new JScrollPane(text);
+            scroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+            add(BorderLayout.CENTER, scroller);
+        }
+
+        public void println(String msg) {
+            text.append(msg + '\n');
+        }
+    }
+
+    final static Color BACKGROUND = Color.white;
+
+    static class FigureSurface extends JPanel implements MouseListener, MouseMotionListener {
+        private Group canvas;
+
+        public FigureSurface() {
+            canvas = new Group(new Point(250, 250));
+            addMouseMotionListener(this);
+            addMouseListener(this);
+            setPreferredSize(new Dimension(500,500));
+        }
+
+        private Point addPoint(int x, int y) {
+            Point p = new Point(x, y);
+            canvas.add(p);
+            repaint();
+            return p;
+        }
+
+        private Line addLine(Point p1, Point p2) {
+            if (Math.abs(p1.getX()-p2.getX()) < 5 ||
+                Math.abs(p1.getY()-p2.getY()) < 5) {
+                return null;
+            }
+
+            Line line = null;
+            if (p1 != null && p2 != null) {
+                line = new Line(p1, p2);
+                canvas.add(line);
+            }
+            repaint();
+            return line;
+        }
+
+        public void paint(Graphics g) {
+            Graphics2D g2 = (Graphics2D) g;
+            g2.setPaint(BACKGROUND);
+            g2.fill(new Rectangle2D.Float(0f, 0f, (float)g2.getClipBounds().width, (float)g2.getClipBounds().height));
+            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+            canvas.paint(g2);
+        }
+
+
+        int lastX, lastY;
+        int pressX, pressY;
+
+        FigureElement first = null;
+        Point point1 = null;
+
+        public void mousePressed(MouseEvent e){
+            int x = e.getX(), y = e.getY();
+            pressX = lastX = x; pressY = lastY = y;
+            first = findFigureElement(x, y);
+            if (first == null) {
+                point1 = addPoint(x, y);
+            }
+        }
+
+        public void mouseDragged(MouseEvent e) {
+            int x = e.getX(), y = e.getY(), dx = lastX-x, dy = lastY-y;
+            lastX = x;
+            lastY = y;
+            if (first == null) {
+                Line line = addLine(point1, new Point(x, y));
+                if (line != null) {
+                    canvas.add(line.getP2());
+                    first = line.getP2();
+                    canvas.add(line);
+                }
+            } else {
+                first.move(-dx, -dy);
+            }
+            repaint();
+        }
+
+        public void mouseReleased(MouseEvent e){
+            mouseDragged(e);
+            first = null;
+            point1 = null;
+        }
+
+
+        public void mouseMoved(MouseEvent e){}
+        public void mouseClicked(MouseEvent e){}
+        public void mouseExited(MouseEvent e){}
+        public void mouseEntered(MouseEvent e){}
+
+        private FigureElement findFigureElement(int x, int y) {
+            Point2D p = new Point2D.Float((float)x, (float)y);
+            for (Iterator i = canvas.members(); i.hasNext(); ) {
+                FigureElement fe = (FigureElement)i.next();
+                if (fe.contains(p)) return fe;
+            }
+            return null;
+        }
+    }
+}
diff --git a/docs/teaching/demos/figures/src-fresh/figures/gui/LogAdapter.java b/docs/teaching/demos/figures/src-fresh/figures/gui/LogAdapter.java
new file mode 100644 (file)
index 0000000..92a192f
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures.gui;
+
+import figures.support.Log;
+
+aspect LogAdapter {
+
+    before(String s): call(void Log.log(String)) && args(s) {
+        if (Main.panel != null) {
+            Main.panel.cp.println(s);
+        }
+    }
+}
diff --git a/docs/teaching/demos/figures/src-fresh/figures/gui/Main.java b/docs/teaching/demos/figures/src-fresh/figures/gui/Main.java
new file mode 100644 (file)
index 0000000..da257ae
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures.gui;
+
+import javax.swing.*;
+import figures.support.Log;
+import figures.Point;
+
+public class Main {
+    static FigurePanel panel;
+    public static void main(String[] args) {
+        JFrame figureFrame = new JFrame("Figure Editor");
+        panel = new FigurePanel();
+        figureFrame.setContentPane(panel);
+        figureFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        figureFrame.pack();
+        figureFrame.setVisible(true);
+         
+//        Point p = new Point(0, 0);
+//        p.setX(-10);
+    }
+}
diff --git a/docs/teaching/demos/figures/src-fresh/figures/support/Log.java b/docs/teaching/demos/figures/src-fresh/figures/support/Log.java
new file mode 100644 (file)
index 0000000..1ae18cc
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures.support;
+
+public class Log {
+    private static StringBuffer data = new StringBuffer();
+
+    public static void traceObject(Object o) {
+        throw new UnsupportedOperationException();
+    }
+
+    public static void log(String s) {
+        data.append(s);
+        data.append(';');
+    }
+
+    public static void logClassName(Class _class) {
+        String name = _class.getName();
+        int dot = name.lastIndexOf('.');
+        if (dot == -1) {
+            log(name);
+        } else {
+            log(name.substring(dot+1, name.length()));
+        }
+    }
+
+    public static String getString() {
+        return data.toString();
+    }
+
+    public static void clear() {
+        data.setLength(0);
+    }
+}
diff --git a/docs/teaching/demos/figures/src/figures/Box.java b/docs/teaching/demos/figures/src/figures/Box.java
new file mode 100644 (file)
index 0000000..4db7f43
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Box extends ShapeFigureElement {
+    private Point _p0;
+    private Point _p1;
+    private Point _p2;
+    private Point _p3;
+
+    public Box(int x0, int y0, int width, int height) {
+        _p0 = new Point(x0, y0);
+        _p1 = new Point(x0+width, y0);
+        _p2 = new Point(x0+width, y0+height);
+        _p3 = new Point(x0, y0+height);
+    }
+
+    public Point getP0() { return _p0; }
+    public Point getP1() { return _p1; }
+    public Point getP2() { return _p2; }
+    public Point getP3() { return _p3; }
+
+    public void move(int dx, int dy) {
+        _p0.move(dx, dy);
+        _p1.move(dx, dy);
+        _p2.move(dx, dy);
+        _p3.move(dx, dy);
+    }
+
+    public void checkBoxness() {
+        if ((_p0.getX() == _p3.getX()) &&
+            (_p1.getX() == _p2.getX()) &&
+            (_p0.getY() == _p1.getY()) &&
+            (_p2.getY() == _p3.getY()))
+          return;
+        throw new IllegalStateException("This is not a square.");
+    }
+
+    public String toString() {
+        return "Box(" + _p0 + ", " + _p1 + ", " + _p2 + ", " + _p3 + ")";
+    }
+
+    public Shape getShape() {
+        return new Rectangle(getP1().getX(),
+                             getP1().getY(),
+                             getP3().getX() - getP1().getX(),
+                             getP3().getY() - getP1().getY());
+    }
+}
+
diff --git a/docs/teaching/demos/figures/src/figures/Canvas.java b/docs/teaching/demos/figures/src/figures/Canvas.java
new file mode 100644 (file)
index 0000000..ef849a5
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+package figures;
+
+import figures.support.Log;
+
+public class Canvas {
+       public static void updateHistory() { }
+
+       public static void updateHistory(FigureElement fe) {
+               System.out.println("> updating history for: " + fe);
+       }  
+}
diff --git a/docs/teaching/demos/figures/src/figures/ColorControl.java b/docs/teaching/demos/figures/src/figures/ColorControl.java
new file mode 100644 (file)
index 0000000..f1a7651
--- /dev/null
@@ -0,0 +1,16 @@
+package figures;
+
+import java.awt.Color;
+import figures.FigureElement;
+
+public aspect ColorControl {
+    public static void setFillColor(FigureElement fe, Color color) {
+       // fill in here
+    }
+
+    public static void setLineColor(FigureElement fe, Color color) {
+       // fill in here
+    }
+
+    // fill in here
+}
diff --git a/docs/teaching/demos/figures/src/figures/FigureElement.java b/docs/teaching/demos/figures/src/figures/FigureElement.java
new file mode 100644 (file)
index 0000000..ae06c13
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public interface FigureElement {
+    public static final int MIN_VALUE = 0;
+    public static final int MAX_VALUE = 500;
+
+    public abstract void move(int dx, int dy);
+
+    public abstract Rectangle getBounds();
+
+    public abstract boolean contains(Point2D p);
+
+    public abstract void paint(Graphics2D g2);
+}
diff --git a/docs/teaching/demos/figures/src/figures/Group.java b/docs/teaching/demos/figures/src/figures/Group.java
new file mode 100644 (file)
index 0000000..59c1a17
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Group implements FigureElement {
+    private Collection _members;
+    private String _identifier;
+
+    public Group(FigureElement first) {
+        this._members = new ArrayList();
+        add(first);
+    }
+
+    public void add(FigureElement fe) {
+        _members.add(fe);
+    }
+
+    public Iterator members() {
+        return _members.iterator();
+    }
+
+    public void move(int dx, int dy) {
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            fe.move(dx, dy);
+        }
+    }
+
+    public void resetIdentifier(String identifier) {
+        resetIdentifier(identifier);
+    }
+
+    public String toString() {
+        if (_identifier != null) {
+            return _identifier;
+        }
+
+        StringBuffer buf = new StringBuffer("Group(");
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            buf.append(i.next().toString());
+            if (i.hasNext()) {
+                buf.append(", ");
+            }
+        }
+        buf.append(")");
+        return buf.toString();
+    }
+
+    public Rectangle getBounds() {
+        Rectangle previous = null;
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            Rectangle rect = fe.getBounds();
+            if (previous != null) {
+                previous = previous.union(rect);
+            } else {
+                previous = rect;
+            }
+        }
+        return previous;
+    }
+
+    public boolean contains(Point2D p) {
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            if (fe.contains(p)) return true;
+        }
+        return false;
+    }
+
+    public void paint(Graphics2D g2) {
+        for (Iterator i = _members.iterator(); i.hasNext(); ) {
+            FigureElement fe = (FigureElement)i.next();
+            fe.paint(g2);
+        }
+    }
+
+    public int size() {
+        return _members.size();
+    }
+}
+
diff --git a/docs/teaching/demos/figures/src/figures/Line.java b/docs/teaching/demos/figures/src/figures/Line.java
new file mode 100644 (file)
index 0000000..e9911c6
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Line extends ShapeFigureElement {
+    private Point _p1;
+    private Point _p2;
+
+    public Line(Point p1, Point p2) {
+        _p1 = p1;
+        _p2 = p2;
+    }
+
+    public Point getP1() { 
+       return _p1; 
+    }
+  
+       public void setP1(Point p1) {
+               _p1 = p1;       
+//             Canvas.updateHistory();
+       }
+    
+    public Point getP2() { 
+       return _p2; 
+    }
+
+       public void setP2(Point p2) {
+               _p2 = p2;       
+//             Canvas.updateHistory();
+       }
+
+    public void move(int dx, int dy) {
+        _p1.move(dx, dy);
+        _p2.move(dx, dy);
+    }
+
+    public String toString() {
+        return "Line(" + _p1 + ", " + _p2 + ")";
+    }
+
+    /**
+     * Used to determine if this line {@link contains(Point2D)} a point.
+     */
+    final static int THRESHHOLD = 5;
+
+    /**
+     * Returns <code>true</code> if the point segment distance is less than
+     * {@link THRESHHOLD}.
+     */
+    public boolean contains(Point2D p) {
+        return getLine2D().ptLineDist(p) < THRESHHOLD;
+    }
+
+    private Line2D getLine2D() {
+       return new Line2D.Float((float)getP1().getX(),
+                                (float)getP1().getY(),
+                                (float)getP2().getX(),
+                                (float)getP2().getY());
+    }
+
+    public Shape getShape() {
+        return getLine2D();
+    }
+}
+
diff --git a/docs/teaching/demos/figures/src/figures/Point.java b/docs/teaching/demos/figures/src/figures/Point.java
new file mode 100644 (file)
index 0000000..d832b98
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public class Point extends ShapeFigureElement {
+    private int _x;
+    private int _y;
+
+    public Point(int x, int y) {
+        _x = x;
+        _y = y;
+    }
+
+    public int getX() { 
+       return _x; 
+    }
+
+    public void setX(int x) { 
+       _x = x; 
+//             Canvas.updateHistory();
+    }
+
+    public int getY() { 
+       return _y; 
+    }
+
+    public void setY(int y) { 
+       _y = y; 
+//     Canvas.updateHistory();
+    }
+
+    public void move(int dx, int dy) {
+               setX(_x + dx);
+       setY(_y + dy);        
+    }
+
+    public String toString() {
+        return "Point(" + _x + ", " + _y + ")";
+    }
+
+    /** The height of displayed {@link Point}s. */
+    private final static int HEIGHT = 10;
+
+    /** The width of displayed {@link Point}s. -- same as {@link HEIGHT}. */
+    private final static int WIDTH  = Point.HEIGHT;
+
+    public Shape getShape() {
+       return new Ellipse2D.Float((float)getX()-Point.WIDTH/2,
+                                   (float)getY()-Point.HEIGHT/2,
+                                   (float)Point.HEIGHT,
+                                   (float)Point.WIDTH);
+    }
+}
+
diff --git a/docs/teaching/demos/figures/src/figures/ShapeFigureElement.java b/docs/teaching/demos/figures/src/figures/ShapeFigureElement.java
new file mode 100644 (file)
index 0000000..29a4a89
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+public abstract class ShapeFigureElement implements FigureElement {
+    public abstract void move(int dx, int dy);
+
+    public abstract Shape getShape();
+
+    public Rectangle getBounds() {
+        return getShape().getBounds();
+    }
+
+    public boolean contains(Point2D p) {
+        return getShape().contains(p);
+    }
+
+    public Color getLineColor() {
+        return Color.black;
+    }
+
+    public Color getFillColor() {
+        return Color.red;
+    }
+
+    public final void paint(Graphics2D g2) {
+        Shape shape = getShape();
+        g2.setPaint(getFillColor());
+        g2.fill(shape);
+        g2.setPaint(getLineColor());
+        g2.draw(shape);
+    }
+}
diff --git a/docs/teaching/demos/figures/src/figures/SlothfulPoint.java b/docs/teaching/demos/figures/src/figures/SlothfulPoint.java
new file mode 100644 (file)
index 0000000..6209703
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+/**
+ * This class makes mistakes to be caught by invariant checkers.
+ */
+public class SlothfulPoint extends ShapeFigureElement {
+    private int _x;
+    private int _y;
+
+    public SlothfulPoint(int x, int y) {
+    }
+
+    public void setX(int x) { 
+       _x = x; 
+    }
+    
+    public void setY(int y) { 
+       _y = y; 
+    }
+
+    public void move(int dx, int dy) {
+               setX(_x + dx);
+               setY(_y + dy);
+    }
+
+    public String toString() {
+        return "SlothfulPoint";
+    }
+
+    public Shape getShape() {
+       return new Ellipse2D.Float((float)_x,
+                                   (float)_y, 1.0f, 1.0f);
+    }
+}
+
diff --git a/docs/teaching/demos/figures/src/figures/gui/FigurePanel.java b/docs/teaching/demos/figures/src/figures/gui/FigurePanel.java
new file mode 100644 (file)
index 0000000..cac59e8
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures.gui;
+
+import figures.Point;
+import figures.Line;
+import figures.FigureElement;
+import figures.Group;
+
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.border.*;
+
+public class FigurePanel extends JComponent {
+
+    ButtonsPanel bp = new ButtonsPanel();
+    FigureSurface fs = new FigureSurface();
+    ConsolePanel cp = new ConsolePanel();
+
+
+    public FigurePanel() {
+        setLayout(new BorderLayout());
+        JPanel panel = new JPanel();
+        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+        panel.add(fs);
+        panel.add(bp);
+        JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, panel, cp);
+        sp.setPreferredSize(new Dimension(500, 400));
+        sp.setDividerLocation(250);
+        add(BorderLayout.CENTER, sp);
+    }
+
+    class ButtonsPanel extends JPanel {
+        private JLabel msgs = new JLabel("click to add a point or line");
+        public ButtonsPanel() {
+            setLayout(new FlowLayout(FlowLayout.LEFT));
+//            add(new JButton(new AbstractAction("Main") {
+//                    public void actionPerformed(ActionEvent e) {
+//                        Main.main(new String[]{});
+//                        fs.repaint();
+//                    }
+//                }));
+            add(msgs);
+        }
+
+        public void log(String msg) {
+            msgs.setText(msg);
+        }
+    }
+
+    static class ConsolePanel extends JPanel {
+
+        JTextArea text = new JTextArea();
+
+        public ConsolePanel() {
+            super(new BorderLayout());
+            text.setFont(StyleContext.getDefaultStyleContext().getFont("SansSerif", Font.PLAIN, 10));
+            JScrollPane scroller = new JScrollPane(text);
+            scroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+            add(BorderLayout.CENTER, scroller);
+        }
+
+        public void println(String msg) {
+            text.append(msg + '\n');
+        }
+    }
+
+    final static Color BACKGROUND = Color.white;
+
+    static class FigureSurface extends JPanel implements MouseListener, MouseMotionListener {
+        private Group canvas;
+
+        public FigureSurface() {
+            canvas = new Group(new Point(250, 250));
+            addMouseMotionListener(this);
+            addMouseListener(this);
+            setPreferredSize(new Dimension(500,500));
+        }
+
+        private Point addPoint(int x, int y) {
+            Point p = new Point(x, y);
+            canvas.add(p);
+            repaint();
+            return p;
+        }
+
+        private Line addLine(Point p1, Point p2) {
+            if (Math.abs(p1.getX()-p2.getX()) < 5 ||
+                Math.abs(p1.getY()-p2.getY()) < 5) {
+                return null;
+            }
+
+            Line line = null;
+            if (p1 != null && p2 != null) {
+                line = new Line(p1, p2);
+                canvas.add(line);
+            }
+            repaint();
+            return line;
+        }
+
+        public void paint(Graphics g) {
+            Graphics2D g2 = (Graphics2D) g;
+            g2.setPaint(BACKGROUND);
+            g2.fill(new Rectangle2D.Float(0f, 0f, (float)g2.getClipBounds().width, (float)g2.getClipBounds().height));
+            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+            canvas.paint(g2);
+        }
+
+
+        int lastX, lastY;
+        int pressX, pressY;
+
+        FigureElement first = null;
+        Point point1 = null;
+
+        public void mousePressed(MouseEvent e){
+            int x = e.getX(), y = e.getY();
+            pressX = lastX = x; pressY = lastY = y;
+            first = findFigureElement(x, y);
+            if (first == null) {
+                point1 = addPoint(x, y);
+            }
+        }
+
+        public void mouseDragged(MouseEvent e) {
+            int x = e.getX(), y = e.getY(), dx = lastX-x, dy = lastY-y;
+            lastX = x;
+            lastY = y;
+            if (first == null) {
+                Line line = addLine(point1, new Point(x, y));
+                if (line != null) {
+                    canvas.add(line.getP2());
+                    first = line.getP2();
+                    canvas.add(line);
+                }
+            } else {
+                first.move(-dx, -dy);
+            }
+            repaint();
+        }
+
+        public void mouseReleased(MouseEvent e){
+            mouseDragged(e);
+            first = null;
+            point1 = null;
+        }
+
+
+        public void mouseMoved(MouseEvent e){}
+        public void mouseClicked(MouseEvent e){}
+        public void mouseExited(MouseEvent e){}
+        public void mouseEntered(MouseEvent e){}
+
+        private FigureElement findFigureElement(int x, int y) {
+            Point2D p = new Point2D.Float((float)x, (float)y);
+            for (Iterator i = canvas.members(); i.hasNext(); ) {
+                FigureElement fe = (FigureElement)i.next();
+                if (fe.contains(p)) return fe;
+            }
+            return null;
+        }
+    }
+}
diff --git a/docs/teaching/demos/figures/src/figures/gui/LogAdapter.java b/docs/teaching/demos/figures/src/figures/gui/LogAdapter.java
new file mode 100644 (file)
index 0000000..92a192f
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures.gui;
+
+import figures.support.Log;
+
+aspect LogAdapter {
+
+    before(String s): call(void Log.log(String)) && args(s) {
+        if (Main.panel != null) {
+            Main.panel.cp.println(s);
+        }
+    }
+}
diff --git a/docs/teaching/demos/figures/src/figures/gui/Main.java b/docs/teaching/demos/figures/src/figures/gui/Main.java
new file mode 100644 (file)
index 0000000..d69f903
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+Copyright (c) 2001-2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures.gui;
+
+import javax.swing.*;
+import figures.support.Log;
+import figures.Point;
+
+public class Main {
+    static FigurePanel panel;
+    public static void main(String[] args) {
+        JFrame figureFrame = new JFrame("Figure Editor");
+        panel = new FigurePanel();
+        figureFrame.setContentPane(panel);
+        figureFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        figureFrame.pack();
+        figureFrame.setVisible(true);
+         
+        Point p = new Point(0, 0);
+        p.setX(-10);
+    }
+}
diff --git a/docs/teaching/demos/figures/src/figures/support/HistoryUpdating.aj b/docs/teaching/demos/figures/src/figures/support/HistoryUpdating.aj
new file mode 100644 (file)
index 0000000..9699d03
--- /dev/null
@@ -0,0 +1,27 @@
+package figures.support;\r
+\r
+import figures.*;\r
+\r
+public aspect HistoryUpdating {\r
+\r
+       pointcut moves(FigureElement fe):\r
+               this(fe) &&\r
+               execution(void FigureElement+.set*(..));\r
+       \r
+       after(FigureElement fe) returning: moves(fe) {\r
+               Canvas.updateHistory(fe);\r
+       }\r
+       \r
+       declare error:\r
+               set(private * FigureElement+.*) &&\r
+               !(withincode(void FigureElement+.set*(..)) ||\r
+                 withincode(FigureElement+.new(..))): \r
+               "doh!!!";\r
+       \r
+       before(int newValue): \r
+               set(int Point.*) && args(newValue) {\r
+               if (newValue < 0) {\r
+                       throw new IllegalArgumentException("too small");\r
+               } \r
+       }\r
+}\r
diff --git a/docs/teaching/demos/figures/src/figures/support/Log.java b/docs/teaching/demos/figures/src/figures/support/Log.java
new file mode 100644 (file)
index 0000000..1ae18cc
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2002 Palo Alto Research Center Incorporated. All Rights Reserved.
+ */
+
+package figures.support;
+
+public class Log {
+    private static StringBuffer data = new StringBuffer();
+
+    public static void traceObject(Object o) {
+        throw new UnsupportedOperationException();
+    }
+
+    public static void log(String s) {
+        data.append(s);
+        data.append(';');
+    }
+
+    public static void logClassName(Class _class) {
+        String name = _class.getName();
+        int dot = name.lastIndexOf('.');
+        if (dot == -1) {
+            log(name);
+        } else {
+            log(name.substring(dot+1, name.length()));
+        }
+    }
+
+    public static String getString() {
+        return data.toString();
+    }
+
+    public static void clear() {
+        data.setLength(0);
+    }
+}
diff --git a/docs/teaching/demos/oopsla2003-mik.ppt b/docs/teaching/demos/oopsla2003-mik.ppt
new file mode 100644 (file)
index 0000000..4c89e0a
Binary files /dev/null and b/docs/teaching/demos/oopsla2003-mik.ppt differ
diff --git a/docs/teaching/demos/readme.txt b/docs/teaching/demos/readme.txt
new file mode 100644 (file)
index 0000000..24b267d
--- /dev/null
@@ -0,0 +1,6 @@
+
+The following folders can be checked out as Eclipse projects:
+
+* figures: refactoring a simple modularity problem in a figure editor
+
+* spacewar: pluggable debug aspect is good for showing build configurations
\ No newline at end of file
diff --git a/docs/teaching/demos/spacewar/.classpath b/docs/teaching/demos/spacewar/.classpath
new file mode 100644 (file)
index 0000000..8ae844d
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+    <classpathentry kind="src" path="src"/>
+    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+    <classpathentry kind="lib" path="C:/AspectJ-Demo/apps/eclipse-3.0/plugins/org.aspectj.ajde_1.1.4/aspectjrt.jar"/>
+    <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/docs/teaching/demos/spacewar/.project b/docs/teaching/demos/spacewar/.project
new file mode 100644 (file)
index 0000000..4fbdcbb
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>spacewar</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.ajdt.ui.ajbuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.eclipse.ajdt.ui.ajnature</nature>
+       </natures>
+</projectDescription>
diff --git a/docs/teaching/demos/spacewar/debug.lst b/docs/teaching/demos/spacewar/debug.lst
new file mode 100644 (file)
index 0000000..fc161a7
--- /dev/null
@@ -0,0 +1,27 @@
+src/coordination/Condition.java
+src/coordination/CoordinationAction.java
+src/coordination/Coordinator.java
+src/coordination/Exclusion.java
+src/coordination/MethodState.java
+src/coordination/Mutex.java
+src/coordination/Selfex.java
+src/coordination/TimeoutException.java
+src/spacewar/Bullet.java
+src/spacewar/Debug.java
+src/spacewar/Display.java
+src/spacewar/Display1.java
+src/spacewar/Display2.java
+src/spacewar/EnergyPacket.java
+src/spacewar/EnergyPacketProducer.java
+src/spacewar/EnsureShipIsAlive.java
+src/spacewar/Game.java
+src/spacewar/GameSynchronization.java
+src/spacewar/Pilot.java
+src/spacewar/Player.java
+src/spacewar/Registry.java
+src/spacewar/RegistrySynchronization.java
+src/spacewar/Robot.java
+src/spacewar/SWFrame.java
+src/spacewar/Ship.java
+src/spacewar/SpaceObject.java
+src/spacewar/Timer.java
diff --git a/docs/teaching/demos/spacewar/readme.html b/docs/teaching/demos/spacewar/readme.html
new file mode 100644 (file)
index 0000000..7b1a75e
--- /dev/null
@@ -0,0 +1,157 @@
+
+<head>
+<style>
+<!--
+ table.MsoNormalTable
+       {mso-style-parent:"";
+       font-size:10.0pt;
+       font-family:"Times New Roman";
+       }
+-->
+</style>
+<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%; 
+       }*/
+       
+       DL {
+               font:13px/13px Verdana, Arial, Helvetica, sans-serif;
+               text-align:justify; 
+               margin-right: 10px;
+               margin-left: 15px;
+               line-height:120%; 
+       }
+       B { font:13px/13px Verdana, Arial, Helvetica, sans-serif; 
+               font-weight:bold; 
+               line-height:140%;
+       }
+       .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>
+
+<h2 align="center">AspectJ Spacewar Demo Instructions</h2>
+<h4>Script</h4>
+<p>Many possible things to show here, the following focuses on pluggable aspects 
+and build configurations:</p>
+<ul>
+       <li>World\92s first fully interactive video game, now 41 years old.</li>
+       <li>Explain spacewar </li>
+       <li>Launch with Ship.java and &quot;Release.lst&quot; selected and compiled. </li>
+       <li>Run </li>
+       <li>Show debug configuration in config designer</li>
+       <li>Select &quot;Debug.lst&quot;, compile, and run again </li>
+       <li>Show debug window, menu, and method tracing</li>
+</ul>
+
diff --git a/docs/teaching/demos/spacewar/release.lst b/docs/teaching/demos/spacewar/release.lst
new file mode 100644 (file)
index 0000000..a6b75a0
--- /dev/null
@@ -0,0 +1,26 @@
+src/coordination/Condition.java
+src/coordination/CoordinationAction.java
+src/coordination/Coordinator.java
+src/coordination/Exclusion.java
+src/coordination/MethodState.java
+src/coordination/Mutex.java
+src/coordination/Selfex.java
+src/coordination/TimeoutException.java
+src/spacewar/Bullet.java
+src/spacewar/Display.java
+src/spacewar/Display1.java
+src/spacewar/Display2.java
+src/spacewar/EnergyPacket.java
+src/spacewar/EnergyPacketProducer.java
+src/spacewar/EnsureShipIsAlive.java
+src/spacewar/Game.java
+src/spacewar/GameSynchronization.java
+src/spacewar/Pilot.java
+src/spacewar/Player.java
+src/spacewar/Registry.java
+src/spacewar/RegistrySynchronization.java
+src/spacewar/Robot.java
+src/spacewar/SWFrame.java
+src/spacewar/Ship.java
+src/spacewar/SpaceObject.java
+src/spacewar/Timer.java
diff --git a/docs/teaching/demos/spacewar/src/coordination/Condition.java b/docs/teaching/demos/spacewar/src/coordination/Condition.java
new file mode 100644 (file)
index 0000000..18bbafe
--- /dev/null
@@ -0,0 +1,37 @@
+/* -*- Mode: Java; -*-
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+*/
+
+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/docs/teaching/demos/spacewar/src/coordination/CoordinationAction.java b/docs/teaching/demos/spacewar/src/coordination/CoordinationAction.java
new file mode 100644 (file)
index 0000000..7825b95
--- /dev/null
@@ -0,0 +1,37 @@
+/* -*- Mode: Java; -*-
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+*/
+
+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/docs/teaching/demos/spacewar/src/coordination/Coordinator.java b/docs/teaching/demos/spacewar/src/coordination/Coordinator.java
new file mode 100644 (file)
index 0000000..ea0522d
--- /dev/null
@@ -0,0 +1,449 @@
+/* -*- Mode: Java; -*-
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+*/
+
+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/docs/teaching/demos/spacewar/src/coordination/Exclusion.java b/docs/teaching/demos/spacewar/src/coordination/Exclusion.java
new file mode 100644 (file)
index 0000000..9179cd6
--- /dev/null
@@ -0,0 +1,33 @@
+/* -*- Mode: Java; -*-
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+*/
+
+package coordination;
+
+
+interface Exclusion {
+
+    boolean testExclusion(String methodName);
+
+    void enterExclusion(String methodName);
+
+    void exitExclusion(String methodName);
+
+    // for debug    !!!
+    void printNames();
+}
+
diff --git a/docs/teaching/demos/spacewar/src/coordination/MethodState.java b/docs/teaching/demos/spacewar/src/coordination/MethodState.java
new file mode 100644 (file)
index 0000000..03a4437
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- Mode: Java; -*-
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+*/
+
+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/docs/teaching/demos/spacewar/src/coordination/Mutex.java b/docs/teaching/demos/spacewar/src/coordination/Mutex.java
new file mode 100644 (file)
index 0000000..2472137
--- /dev/null
@@ -0,0 +1,86 @@
+/* -*- Mode: Java; -*-
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+*/
+
+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/docs/teaching/demos/spacewar/src/coordination/Selfex.java b/docs/teaching/demos/spacewar/src/coordination/Selfex.java
new file mode 100644 (file)
index 0000000..ff73afd
--- /dev/null
@@ -0,0 +1,55 @@
+/* -*- Mode: Java; -*-
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+*/
+
+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/docs/teaching/demos/spacewar/src/coordination/TimeoutException.java b/docs/teaching/demos/spacewar/src/coordination/TimeoutException.java
new file mode 100644 (file)
index 0000000..e16aa7f
--- /dev/null
@@ -0,0 +1,27 @@
+/* -*- Mode: Java; -*-
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+*/
+
+package coordination;
+
+
+public class TimeoutException extends Exception {
+    long time;
+    TimeoutException(long _time) {
+       time = _time;
+    }
+}
diff --git a/docs/teaching/demos/spacewar/src/spacewar/Bullet.java b/docs/teaching/demos/spacewar/src/spacewar/Bullet.java
new file mode 100644 (file)
index 0000000..6581dbb
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+Bullet.java
+Part of the Spacewar game.
+
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/Debug.java b/docs/teaching/demos/spacewar/src/spacewar/Debug.java
new file mode 100644 (file)
index 0000000..d22a2f5
--- /dev/null
@@ -0,0 +1,198 @@
+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() returning: 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() returning : 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() returning : allMethodsCut() {
+        if (traceMethods.getState()) {
+            infoWin.println("exiting " + thisJoinPoint.getSignature());
+        }
+    }
+
+    /*
+     * clock ticks
+     */
+    after(Object obj) returning :
+        (target(obj) && (target(Game) ||
+                        target(Registry) ||
+                        target(SpaceObject)))
+        && call(void clockTick()) {
+        if (traceClockTick.getState())
+            infoWin.println("ticking " + obj);
+    }
+
+    /*
+     * registry contents
+     */
+    after(Registry registry) returning :
+        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() returning : call(void Ship.fire()) {
+        if (traceFireCollideDamage.getState())
+            infoWin.println("firing");
+    }
+
+    after(Ship ship, SpaceObject obj) returning :
+       call(void Ship.handleCollision(SpaceObject)) && target(ship) && args(obj) {
+        if (traceFireCollideDamage.getState())
+            infoWin.println(ship + " collides with " + obj);
+    }
+
+    after(Ship shipA, Ship shipB) returning :
+        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/docs/teaching/demos/spacewar/src/spacewar/Display.java b/docs/teaching/demos/spacewar/src/spacewar/Display.java
new file mode 100644 (file)
index 0000000..b5b9c94
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+Display.java
+Part of the Spacewar system.
+*/
+
+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() returning : call(void Game.clockTick()) {
+            Enumeration elements = DISPLAYS.elements();
+            while ( elements.hasMoreElements() ) {
+                Display display = (Display)elements.nextElement();
+                display.repaint();
+            }
+        }
+    }
+}
diff --git a/docs/teaching/demos/spacewar/src/spacewar/Display1.java b/docs/teaching/demos/spacewar/src/spacewar/Display1.java
new file mode 100644 (file)
index 0000000..484a234
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+Display1.java
+Part of the Spacewar system.
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/Display2.java b/docs/teaching/demos/spacewar/src/spacewar/Display2.java
new file mode 100644 (file)
index 0000000..d2dbeb4
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+Display2.java
+Part of the Spacewar system.
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/EnergyPacket.java b/docs/teaching/demos/spacewar/src/spacewar/EnergyPacket.java
new file mode 100644 (file)
index 0000000..d7bc4f9
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+EnergyPacket.java
+Part of the Spacewar system.
+
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/EnergyPacketProducer.java b/docs/teaching/demos/spacewar/src/spacewar/EnergyPacketProducer.java
new file mode 100644 (file)
index 0000000..efd2760
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+EnergyPacketProducer.java
+Part of the Spacewar system.
+
+ This implementation creates booby-trapped packets 20% of the time.
+
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/EnsureShipIsAlive.java b/docs/teaching/demos/spacewar/src/spacewar/EnsureShipIsAlive.java
new file mode 100644 (file)
index 0000000..f7b949a
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+Ship.java
+Part of the Spacewar system.
+
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/Game.java b/docs/teaching/demos/spacewar/src/spacewar/Game.java
new file mode 100644 (file)
index 0000000..da67d7b
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+Game.java
+Part of the Spacewar system.
+
+*/
+
+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; }
+
+    /** returns the width of the screen, delegating to screenSize */
+    int getWidth()  { return screenSize.width;  }
+
+    /** returns the height of the screen, delegating to screenSize */
+    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) {}
+        }
+    }
+
+
+    /**
+     * add a robot to the game.  This is a menu command.
+     */
+    void addRobot() {
+        newRobot(3);
+    }
+
+    /**
+     * resurrect the ships in the game.  This is a menu command.
+     */
+    void resetShips() {
+        Ship[] ships = registry.getShips();
+
+        for (int i = 0; i < ships.length; i++) {
+            Ship ship = ships[i];
+            Pilot pilot = ship.getPilot();
+            newShip(pilot);
+        }
+    }
+
+    /**
+     * leave the game.  This is a menu command.
+     */
+    void quit() {
+        System.exit(0);
+    }
+
+    void error(Object o) {
+        System.err.println(o);
+    }
+
+
+    /**
+     * returns a new player.  With {@link #newRobot} and {@link
+     * #newShip}, 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;
+    }
+
+    /**
+     * returns a new robot.  With {@link #newPlayer} and {@link
+     * #newShip}, 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.
+     */
+    Robot newRobot(int number) {
+        Robot robot = new Robot(this, number);
+        newShip(robot);
+        robot.start();
+        return robot;
+    }
+
+    /**
+     * returns a new ship.  With {@link #newRobot} and {@link
+     * #newPlayer}, 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.
+     */
+    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/docs/teaching/demos/spacewar/src/spacewar/GameSynchronization.java b/docs/teaching/demos/spacewar/src/spacewar/GameSynchronization.java
new file mode 100644 (file)
index 0000000..dcf42e9
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+RegistrySynchronization.java
+Part of the Spacewar system.
+
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/Pilot.java b/docs/teaching/demos/spacewar/src/spacewar/Pilot.java
new file mode 100644 (file)
index 0000000..330d860
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/Player.java b/docs/teaching/demos/spacewar/src/spacewar/Player.java
new file mode 100644 (file)
index 0000000..ebde6d5
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+*/
+
+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;
+
+    /** current rotation key */
+    private int        rotation_direction = Ship.STOP; // current rotation key
+
+    /** current thrust */
+    private boolean    thrust_on = false;
+
+    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/docs/teaching/demos/spacewar/src/spacewar/Registry.java b/docs/teaching/demos/spacewar/src/spacewar/Registry.java
new file mode 100644 (file)
index 0000000..a9cec04
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+Registry.java
+Part of the Spacewar system.
+
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/RegistrySynchronization.java b/docs/teaching/demos/spacewar/src/spacewar/RegistrySynchronization.java
new file mode 100644 (file)
index 0000000..986e4bd
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+RegistrySynchronization.java
+Part of the Spacewar system.
+
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/Robot.java b/docs/teaching/demos/spacewar/src/spacewar/Robot.java
new file mode 100644 (file)
index 0000000..05f2761
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+Robot.java
+Part of the Spacewar system.
+
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/SWFrame.java b/docs/teaching/demos/spacewar/src/spacewar/SWFrame.java
new file mode 100644 (file)
index 0000000..6dfb9f6
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+SWFrame.java
+Part of the Spacewar system.
+
+*/
+
+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/docs/teaching/demos/spacewar/src/spacewar/Ship.java b/docs/teaching/demos/spacewar/src/spacewar/Ship.java
new file mode 100644 (file)
index 0000000..8f016fe
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+Ship.java
+Part of the Spacewar system.
+
+*/
+
+package spacewar;
+
+class Ship extends SpaceObject {
+
+    pointcut helmCommandsCut(Ship ship):
+        target(ship) && ( call(void rotate(int))     ||
+                         call(void thrust(boolean)) ||
+                         call(void fire()) );
+
+    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);
+    }
+
+    /** repairs some damage
+     */
+    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);
+        }
+    }
+
+    /**
+     * First check to make sure we have enough energy to rotate.  If
+     * we do, then go ahead and do so.
+     */
+    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;
+    }
+
+    /** affect rotation thrusters.  Direction can be one of {@link
+     * #CLOCKWISE}, {@link #COUNTERCLOCKWISE}, or zero for turning off
+     * the thrusters.
+     */
+    void rotate(int direction) {
+        setAngularVelocity(
+          direction == CLOCKWISE        ? DEFAULT_ANGULAR_VELOCITY :
+          direction == COUNTERCLOCKWISE ? -DEFAULT_ANGULAR_VELOCITY :
+          0);
+    }
+
+    /** turn on acceleration */
+    void thrust(boolean onOff) {
+        setAcceleration(onOff ? DEFAULT_ACCELERATION : 0);
+    }
+
+    /** create a bullet and fire it */
+    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();
+        }
+    }
+    
+
+
+       /**
+        * 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:
+        * <ul>
+        *   <li>MAX_ENERGY</li>
+        *   <li>BULLET_ENERGY</li>
+        *   <li>ACCELERATION_ENERGY_FACTOR</li>
+        *   <li>energy</li>
+        * </ul>
+        * The damage related values are:
+        * <ul>
+        *   <li>MAX_DAMAGE</li>
+        *   <li>BULLET_DAMAGE</li>
+        *   <li>COLLISION_DAMAGE_FACTOR</li>
+        *   <li>damage</li>
+        * </ul>
+        * 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;
+    
+}
diff --git a/docs/teaching/demos/spacewar/src/spacewar/SpaceObject.java b/docs/teaching/demos/spacewar/src/spacewar/SpaceObject.java
new file mode 100644 (file)
index 0000000..ee3afab
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+SpaceObject.java
+Part of the Spacewar system.
+
+*/
+
+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();
+
+    /** resolve the effects of colliding with a space object.
+     *  @param obj the space object that this object is colliding with.
+     */
+    abstract void handleCollision(SpaceObject obj);
+}
diff --git a/docs/teaching/demos/spacewar/src/spacewar/Timer.java b/docs/teaching/demos/spacewar/src/spacewar/Timer.java
new file mode 100644 (file)
index 0000000..1f4a992
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+
+Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.
+
+Use and copying of this software and preparation of derivative works based
+upon this software are permitted.  Any distribution of this software or
+derivative works must comply with all applicable United States export control
+laws.
+
+This software is made available AS IS, and Xerox Corporation makes no warranty
+about the software, its performance or its conformity to any specification.
+
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+|<---            this code is formatted to fit into 80 columns             --->|
+
+
+Timer.java
+Part of the Spacewar system.
+
+*/
+
+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) { }
+            }
+        }
+    }
+}