diff options
author | Alexander Kriegisch <Alexander@Kriegisch.name> | 2024-02-01 08:57:52 +0700 |
---|---|---|
committer | Alexander Kriegisch <Alexander@Kriegisch.name> | 2024-02-01 08:58:28 +0700 |
commit | 983159c76ca8163b61f0d52c98522e8bc113f585 (patch) | |
tree | 3137bb04a0942b59d7b066912a2fa8fed5601373 /docs/modules/ROOT/examples | |
parent | c99b58736fd7f2952fe9bf787333631a762dcbeb (diff) | |
download | aspectj-983159c76ca8163b61f0d52c98522e8bc113f585.tar.gz aspectj-983159c76ca8163b61f0d52c98522e8bc113f585.zip |
Move source code examples to Antora examples directoryantora
Signed-off-by: Alexander Kriegisch <Alexander@Kriegisch.name>
Diffstat (limited to 'docs/modules/ROOT/examples')
91 files changed, 6329 insertions, 0 deletions
diff --git a/docs/modules/ROOT/examples/bean/BoundPoint.java b/docs/modules/ROOT/examples/bean/BoundPoint.java new file mode 100644 index 000000000..36c85819c --- /dev/null +++ b/docs/modules/ROOT/examples/bean/BoundPoint.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1998-2002 Xerox Corporation, + * 2004 Contributors. 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. + */ + +package bean; + +import java.beans.*; +import java.io.Serializable; + +/** + * Add bound properties and serialization to Point objects + */ +aspect BoundPoint { + /* + * privately declare a field on Point to hold the property + * change support object. `this' is a reference to a Point object. + */ + private PropertyChangeSupport Point.support = new PropertyChangeSupport(this); + + /* + * Declare property change registration methods on Point, + * and introduce implementation of the Serializable interface. + */ + + public void Point.addPropertyChangeListener(PropertyChangeListener listener){ + support.addPropertyChangeListener(listener); + } + + public void Point.addPropertyChangeListener(String propertyName, + PropertyChangeListener listener){ + support.addPropertyChangeListener(propertyName, listener); + } + + public void Point.removePropertyChangeListener(String propertyName, + PropertyChangeListener listener) { + support.removePropertyChangeListener(propertyName, listener); + } + + public void Point.removePropertyChangeListener(PropertyChangeListener listener) { + support.removePropertyChangeListener(listener); + } + + public void Point.hasListeners(String propertyName) { + support.hasListeners(propertyName); + } + + declare parents: Point implements Serializable; + + /** + * Send property change event after X setter completes normally. + * Use around advice to keep the old value on the stack. + */ + void around(Point p): execution(void Point.setX(int)) && target(p) { + int oldValue = p.getX(); + proceed(p); + firePropertyChange(p, "x", oldValue, p.getX()); + } + + /** + * Send property change event after Y setter completes normally. + * Use around advice to keep the old value on the stack. + */ + void around(Point p): execution(void Point.setY(int)) && target(p) { + int oldValue = p.getY(); + proceed(p); + firePropertyChange(p, "y", oldValue, p.getY()); + } + + /* + * Utility to fire the property change event. + */ + void firePropertyChange(Point p, + String property, + double oldval, + double newval) { + p.support.firePropertyChange(property, + new Double(oldval), + new Double(newval)); + } +} diff --git a/docs/modules/ROOT/examples/bean/Demo.java b/docs/modules/ROOT/examples/bean/Demo.java new file mode 100644 index 000000000..e16be245e --- /dev/null +++ b/docs/modules/ROOT/examples/bean/Demo.java @@ -0,0 +1,80 @@ +/* +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. +*/ + +package bean; + +import java.beans.*; +import java.io.*; + +public class Demo implements PropertyChangeListener { + + static final String fileName = "test.tmp"; + + /** + * when Demo is playing the listener role, + * this method reports that a propery has changed + */ + public void propertyChange(PropertyChangeEvent e){ + System.out.println("Property " + e.getPropertyName() + " changed from " + + e.getOldValue() + " to " + e.getNewValue() ); + } + + /** + * main: test the program + */ + public static void main(String[] args){ + Point p1 = new Point(); + p1.addPropertyChangeListener(new Demo()); + System.out.println("p1 =" + p1); + p1.setRectangular(5,2); + System.out.println("p1 =" + p1); + p1.setX( 6 ); + p1.setY( 3 ); + System.out.println("p1 =" + p1); + p1.offset(6,4); + System.out.println("p1 =" + p1); + save(p1, fileName); + Point p2 = (Point) restore(fileName); + System.out.println("Had: " + p1); + System.out.println("Got: " + p2); + } + + /** + * Save a serializable object to a file + */ + static void save(Serializable p, String fn){ + try { + System.out.println("Writing to file: " + p); + FileOutputStream fo = new FileOutputStream(fn); + ObjectOutputStream so = new ObjectOutputStream(fo); + so.writeObject(p); + so.flush(); + } catch (Exception e) { + System.out.println(e); + System.exit(1); + } + } + + /** + * Restore a serializable object from the file + */ + static Object restore(String fn){ + try { + Object result; + System.out.println("Reading from file: " + fn); + FileInputStream fi = new FileInputStream(fn); + ObjectInputStream si = new ObjectInputStream(fi); + return si.readObject(); + } catch (Exception e) { + System.out.println(e); + System.exit(1); + } + return null; + } +} diff --git a/docs/modules/ROOT/examples/bean/Point.java b/docs/modules/ROOT/examples/bean/Point.java new file mode 100644 index 000000000..a6ea703cd --- /dev/null +++ b/docs/modules/ROOT/examples/bean/Point.java @@ -0,0 +1,69 @@ +/* +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. +*/ + +package bean; + +class Point { + + protected int x = 0; + protected int y = 0; + + /** + * Return the X coordinate + */ + public int getX(){ + return x; + } + + /** + * Return the y coordinate + */ + public int getY(){ + return y; + } + + /** + * Set the x and y coordinates + */ + public void setRectangular(int newX, int newY){ + setX(newX); + setY(newY); + } + + /** + * Set the X coordinate + */ + public void setX(int newX) { + x = newX; + } + + /** + * set the y coordinate + */ + public void setY(int newY) { + y = newY; + } + + /** + * Move the point by the specified x and y offset + */ + public void offset(int deltaX, int deltaY){ + setRectangular(x + deltaX, y + deltaY); + } + + /** + * Make a string of this + */ + public String toString(){ + return "(" + getX() + ", " + getY() + ")" ; + } +} diff --git a/docs/modules/ROOT/examples/bean/files.lst b/docs/modules/ROOT/examples/bean/files.lst new file mode 100644 index 000000000..12ac0eb39 --- /dev/null +++ b/docs/modules/ROOT/examples/bean/files.lst @@ -0,0 +1,3 @@ +BoundPoint.java +Point.java +Demo.java diff --git a/docs/modules/ROOT/examples/build.xml b/docs/modules/ROOT/examples/build.xml new file mode 100644 index 000000000..958c72727 --- /dev/null +++ b/docs/modules/ROOT/examples/build.xml @@ -0,0 +1,458 @@ + +<!-- ========================================================================= --> +<!-- Copyright (c) 1999-2001 Xerox Corporation, --> +<!-- 2002 Palo Alto Research Center, Incorporated (PARC). --> +<!-- All rights reserved. --> +<!-- This program and the accompanying materials are made available --> +<!-- under the terms of the Eclipse Public License v 2.0 --> +<!-- which accompanies this distribution and is available at --> +<!-- https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt --> +<!-- --> +<!-- Contributors: --> +<!-- Xerox/PARC initial implementation --> +<!-- ========================================================================= --> + +<project name="aspectj-examples" default="spacewar" basedir="."> + + <target name="info" > + <echo> + This script builds the AspectJ examples. + + Relevant targets: + spacewar build and run spacewar with debugging (default) + all build and run each example + {example} build and run any {example} + (use -projecthelp to list {example} names) + tracing-bc use AspectJ 1.1 bytecode weaving to build tracing example + + Setup: + - Run from the doc/examples directory in your AspectJ distribution. + The tasks in ../../lib/aspectjtools.jar are used automatically. + + Variants: + - To avoid running (i.e., compile only), define variable "norun" + - To define a variable, use the Ant -D option - e.g., on Windows: + + ant -f build.xml -DJAVA_HOME=c:\jdk1.3.1 -Dnorun=skip + + </echo> + </target> + + <!-- ============================================================= --> + <!-- setup and cleanup targets --> + <!-- ============================================================= --> + + <target name="clean" depends="init" + description="clean and create classes/jar dir, .ajesym files"> + <delete quiet="on" dir="${classes.dir}"/> + <delete quiet="on" dir="${jar.dir}"/> + <delete quiet="on"> + <fileset dir="${example.dir}" includes="**/*.ajesym"/> + </delete> + <mkdir dir="${classes.dir}"/> + <mkdir dir="${jar.dir}"/> + </target> + + <target name="init" depends="init.variables,init.taskdefs"/> + + <target name="init.variables" + description="init variables"> + + <!-- build.compiler value to pick up our CompilerAdapter for javac --> + <property name="ajc.adapter" + value="org.aspectj.tools.ant.taskdefs.Ajc11CompilerAdapter"/> + + <!-- required directories - run from examples or predefine --> + <property name="example.dir" + location="${basedir}"/> + <property name="aspectj.lib.dir" + location="${basedir}/../../lib"/> + + <!-- required libraries - install or predefine --> + <property name="aspectjrt.jar" + location="${aspectj.lib.dir}/aspectjrt.jar"/> + <property name="aspectjtools.jar" + location="${aspectj.lib.dir}/aspectjtools.jar"/> + <property name="aspectjweaver.jar" + location="${aspectj.lib.dir}/aspectjweaver.jar"/> + + <!-- created directories --> + <property name="classes.dir" + location="${example.dir}/classes"/> + <property name="jar.dir" + location="${example.dir}/jars"/> + + <!-- checking required libraries --> + <available file="${aspectjtools.jar}" + property="aspectjtools.jar.available"/> + <available file="${aspectjrt.jar}" + property="aspectjrt.jar.available"/> + + <property name="example.packages" + value="bean, coordination, evolution, figures, figures.gui, + helloworld, icount, icount.lib, introduction, + observer, shadow, shadow.version1, shadow.version2, + spacewar, telecom, telecom.version1, timeserver, tjp, + tracing, tracing.lib tracing.version1, tracing.version2, + tracing.version3"/> + </target> + + <target name="init.taskdefs" depends="init.variables, + aspectjtools.jar.available, + aspectjrt.jar.available" + unless="taskdefs.init"> + <!-- sets name of new task to iajc, old task to ajc --> + <taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"> + <classpath> + <pathelement path="${aspectjtools.jar}"/> + </classpath> + </taskdef> + <property name="taskdefs.init" value="true"/> + </target> + + <!-- targets to fail unless required libraries available --> + + <target name="aspectjrt.jar.available" depends="init.variables" + unless="aspectjrt.jar.available" > + <fail message="expecting aspectjrt.jar at ${aspectjrt.jar}"/> + </target> + + <target name="aspectjtools.jar.available" depends="init.variables" + unless="aspectjtools.jar.available" > + <fail message="expecting aspectjtools.jar at ${aspectjtools.jar}"/> + </target> + + <!-- ============================================================= --> + <!-- these targets compile and run any example --> + <!-- ============================================================= --> + <target name="Ajx" depends="init" + description="compile {list} and run {class} of example"> + <echo message="##### Ajx list=${list} class=${class}" /> + <antcall target="clean" /> + <!-- can use ajc or iajc here --> + <iajc destdir="${classes.dir}" argfiles="${list}" + fork="true" + forkclasspath="${aspectjtools.jar}" + classpath="${aspectjrt.jar}"/> + + <antcall target="Ajx-run" > + <param name="class" value="${class}"/> + </antcall> + + </target> + + <target name="Ajx-run" + description="run {class} unless {norun} is set" + unless="norun" > + <echo message="##### Ajx-run list=${list} class=${class}" /> + <java classname="${class}" fork="yes"> + <classpath> + <pathelement path="${classes.dir}"/> + <pathelement path="${aspectjrt.jar}"/> + </classpath> + </java> + </target> + + <!-- ============================================================= --> + <!-- example targets --> + <!-- ============================================================= --> + <target name="all" + description="build and run all examples" + depends="bean,intro,intro-clone,intro-compare,intro-hash, + observer,spacewar,spacewar-demo,telecom, + telecom-timing,tracing-none,tracing-1, + tracing-2,tracing-3,tracing-lt,tjp"/> + + <target name="nonGui" + description="build and run non-GUI examples" + depends="bean,intro,intro-clone,intro-compare,intro-hash, + telecom,telecom-timing,tracing-none,tracing-1, + tracing-2,tracing-3,tracing-lt,tjp"/> + + <target name="bean" + description="build bean example"> + <antcall target="Ajx"> + <param name="list" value="bean/files.lst"/> + <param name="class" value="bean.Demo"/> + </antcall> + </target> + + <target name="intro" + description="build inter-type declaration example"> + <antcall target="Ajx"> + <param name="list" value="introduction/files.lst"/> + <param name="class" value="introduction.Point"/> + </antcall> + </target> + + <target name="intro-clone" + description="build inter-type declaration (clone) example"> + <antcall target="Ajx"> + <param name="list" value="introduction/files.lst"/> + <param name="class" value="introduction.CloneablePoint"/> + </antcall> + </target> + + <target name="intro-compare" + description="build inter-type declaration (Comparable) example"> + <antcall target="Ajx"> + <param name="list" value="introduction/files.lst"/> + <param name="class" value="introduction.ComparablePoint"/> + </antcall> + </target> + + <target name="intro-hash" + description="build inter-type declaration (hashcode) example"> + <antcall target="Ajx"> + <param name="list" value="introduction/files.lst"/> + <param name="class" value="introduction.HashablePoint"/> + </antcall> + </target> + + <target name="observer" + description="build observer example"> + <antcall target="Ajx"> + <param name="list" value="observer/files.lst"/> + <param name="class" value="observer.Demo"/> + </antcall> + </target> + + <target name="spacewar" + description="build spacewar debug example"> + <antcall target="Ajx"> + <param name="list" value="spacewar/debug.lst"/> + <param name="class" value="spacewar.Game"/> + </antcall> + </target> + + <target name="spacewar-demo" + description="build spacewar demo (no debug) example"> + <antcall target="Ajx"> + <param name="list" value="spacewar/demo.lst"/> + <param name="class" value="spacewar.Game"/> + </antcall> + </target> + + <target name="telecom" + description="build telecom basic example"> + <antcall target="Ajx"> + <param name="list" value="telecom/basic.lst"/> + <param name="class" value="telecom.BasicSimulation"/> + </antcall> + </target> + + <target name="telecom-billing" + description="build telecom billing example"> + <antcall target="Ajx"> + <param name="list" value="telecom/billing.lst"/> + <param name="class" value="telecom.BillingSimulation"/> + </antcall> + </target> + + <target name="telecom-timing" + description="build telecome timing example"> + <antcall target="Ajx"> + <param name="list" value="telecom/timing.lst"/> + <param name="class" value="telecom.TimingSimulation"/> + </antcall> + </target> + + <target name="tjp" + description="build thisJoinPoint example"> + <antcall target="Ajx"> + <param name="list" value="tjp/files.lst"/> + <param name="class" value="tjp.Demo"/> + </antcall> + </target> + + <target name="tracing-none" + description="build tracing (base) example"> + <antcall target="Ajx"> + <param name="list" value="tracing/notrace.lst"/> + <param name="class" value="tracing.ExampleMain"/> + </antcall> + </target> + + <target name="tracing-1" + description="build tracing (version 1) example"> + <antcall target="Ajx"> + <param name="list" value="tracing/tracev1.lst"/> + <param name="class" value="tracing.version1.TraceMyClasses"/> + </antcall> + </target> + + <target name="tracing-2" + description="build tracing (version 2) example"> + <antcall target="Ajx"> + <param name="list" value="tracing/tracev2.lst"/> + <param name="class" value="tracing.version2.TraceMyClasses"/> + </antcall> + </target> + + <target name="tracing-3" + description="build tracing (version 3) example"> + <antcall target="Ajx"> + <param name="list" value="tracing/tracev3.lst"/> + <param name="class" value="tracing.version3.TraceMyClasses"/> + </antcall> + </target> + + <!-- ============================================================= --> + <!-- do tracing example using compiler adapter --> + <!-- ============================================================= --> + <target name="tracing-adapter" depends="init" + description="tracing example compiled via javac task"> + <antcall target="clean" /> + <!-- to fork, set adapter.fork=true + and put aspectjtools.jar on ant classpath --> + <javac destdir="${classes.dir}" + fork="${adapter.fork}"> + <src path="${example.dir}"/> + <include name="tracing/*.java"/> + + <!-- compilerarg's ignored unless using our compiler adapter --> + <compilerarg compiler="${ajc.adapter}" + line="-verbose -Xlint -proceedOnError"/> + <!-- use separate values if a path might have spaces --> + <compilerarg compiler="${ajc.adapter}" + value="-classpath"/> + <compilerarg compiler="${ajc.adapter}" + value="${aspectjrt.jar}"/> + <compilerarg compiler="${ajc.adapter}" + path="${example.dir}/tracing/version3/Trace.java"/> + <compilerarg compiler="${ajc.adapter}" + path="${example.dir}/tracing/version3/TraceMyClasses.java"/> + </javac> + </target> + + <target name="tracing-adapter-ajc" depends="init" + description="tracing example compiled using ajc via compiler adapter"> + <!-- aspectjtools.jar must be on system/ant classpath --> + <antcall target="tracing-adapter"> + <param name="build.compiler" value="${ajc.adapter}"/> + </antcall> + </target> + + <!-- ============================================================= --> + <!-- do tracing example with 1.1 bytecode weaving (binary aspects) --> + <!-- (and use fork/forkclasspath to avoid Eclipse 2.x bug) --> + <!-- ============================================================= --> + <target name="tracing-bc" depends="init" + description="tracing example with bytecode weaving (binary aspects)"> + <antcall target="clean" /> + + <!-- build application classes --> + <iajc outjar="${jar.dir}/tracingApp.jar" + classpath="${aspectjrt.jar}" + fork="true" + forkclasspath="${aspectjtools.jar}" + verbose="off"> + <src path="${example.dir}"/> + <include name="tracing/*.java" /> + </iajc> + + <!-- test standalone application by running without tracing --> + <echo message="---------- running without tracing - START"/> + <java classname="tracing.ExampleMain"> + <classpath> + <pathelement path="${aspectjrt.jar}"/> + <pathelement path="${jar.dir}/tracingApp.jar"/> + </classpath> + </java> + <echo message="---------- running without tracing - FINISH "/> + + <!-- Build a read-only tracing library --> + <iajc outjar="${jar.dir}/tracingLib.jar" + classpath="${aspectjrt.jar}" + fork="true" + forkclasspath="${aspectjtools.jar}" + verbose="off"> + <src path="${example.dir}"/> + <include name="tracing/version3/Trace.java" /> + </iajc> + + <!-- weave them --> + <!-- This example uses a concrete aspect in source form, --> + <!-- but the aspects could be written to be binary only. --> + <iajc outjar="${jar.dir}/tracedApp.jar" + inpath="${jar.dir}/tracingApp.jar" + aspectpath="${jar.dir}/tracingLib.jar" + classpath="${aspectjrt.jar}" + fork="true" + forkclasspath="${aspectjtools.jar}" + verbose="off"> + <src path="${example.dir}"/> + <include name="tracing/version3/TraceMyClasses.java" /> + </iajc> + + <!-- run with tracing --> + <echo message="---------- running with tracing - START"/> + <java classname="tracing.version3.TraceMyClasses"> + <classpath> + <pathelement path="${aspectjrt.jar}"/> + <pathelement path="${jar.dir}/tracingLib.jar"/> + <pathelement path="${jar.dir}/tracedApp.jar"/> + </classpath> + </java> + <echo message="---------- running with tracing - FINISH"/> + + </target> + + <!-- ============================================================= --> + <!-- do tracing example with 1.2 load-time weaving --> + <!-- (and use fork/forkclasspath to avoid Eclipse 2.x bug) --> + <!-- ============================================================= --> + <target name="tracing-lt" depends="init" + description="tracing example with load-time aspect weaving"> + <antcall target="clean" /> + + <!-- build application classes --> + <iajc outjar="${jar.dir}/tracingApp.jar" + classpath="${aspectjrt.jar}" + fork="true" + forkclasspath="${aspectjtools.jar}" + verbose="off"> + <src path="${example.dir}"/> + <include name="tracing/*.java" /> + </iajc> + + <!-- Build a read-only tracing library --> + <iajc outjar="${jar.dir}/tracingLib.jar" + classpath="${aspectjrt.jar}:${jar.dir}/tracingApp.jar" + fork="true" + forkclasspath="${aspectjtools.jar}" + verbose="off"> + <src path="${example.dir}"/> + <include name="tracing/version2/Trace.java" /> + <include name="tracing/version2/TraceMyClasses.java" /> + </iajc> + + <!-- test standalone application by running without tracing --> + <echo message="---------- running without tracing - START"/> + <java classname="tracing.ExampleMain"> + <classpath> + <pathelement path="${aspectjrt.jar}"/> + <pathelement path="${jar.dir}/tracingApp.jar"/> + </classpath> + </java> + <echo message="---------- running without tracing - FINISH "/> + + <!-- run application with LTW to add tracing --> + <echo message="---------- running with tracing - START"/> + <java classname="tracing.ExampleMain" + fork="true"> + <classpath> + <pathelement path="${aspectjweaver.jar}"/> + </classpath> + <jvmarg line="-showversion"/> + <sysproperty key="java.system.class.loader" value="org.aspectj.weaver.loadtime.WeavingURLClassLoader"/> + <sysproperty key="aj.weaving.verbose" value="True"/> + <sysproperty key="org.aspectj.weaver.showWeaveInfo" value="True"/> + <sysproperty key="aj.class.path" path="${jar.dir}/tracingLib.jar:${jar.dir}/tracingApp.jar"/> + <sysproperty key="aj.aspect.path" path="${jar.dir}/tracingLib.jar"/> + </java> + <echo message="---------- running with tracing - FINISH"/> + + </target> + +</project> diff --git a/docs/modules/ROOT/examples/coordination/Condition.java b/docs/modules/ROOT/examples/coordination/Condition.java new file mode 100644 index 000000000..18bbafee2 --- /dev/null +++ b/docs/modules/ROOT/examples/coordination/Condition.java @@ -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/modules/ROOT/examples/coordination/CoordinationAction.java b/docs/modules/ROOT/examples/coordination/CoordinationAction.java new file mode 100644 index 000000000..7825b95b7 --- /dev/null +++ b/docs/modules/ROOT/examples/coordination/CoordinationAction.java @@ -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/modules/ROOT/examples/coordination/Coordinator.java b/docs/modules/ROOT/examples/coordination/Coordinator.java new file mode 100644 index 000000000..ea0522d6b --- /dev/null +++ b/docs/modules/ROOT/examples/coordination/Coordinator.java @@ -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/modules/ROOT/examples/coordination/Exclusion.java b/docs/modules/ROOT/examples/coordination/Exclusion.java new file mode 100644 index 000000000..9179cd6e0 --- /dev/null +++ b/docs/modules/ROOT/examples/coordination/Exclusion.java @@ -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/modules/ROOT/examples/coordination/MethodState.java b/docs/modules/ROOT/examples/coordination/MethodState.java new file mode 100644 index 000000000..03a44378a --- /dev/null +++ b/docs/modules/ROOT/examples/coordination/MethodState.java @@ -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/modules/ROOT/examples/coordination/Mutex.java b/docs/modules/ROOT/examples/coordination/Mutex.java new file mode 100644 index 000000000..2472137c6 --- /dev/null +++ b/docs/modules/ROOT/examples/coordination/Mutex.java @@ -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/modules/ROOT/examples/coordination/Selfex.java b/docs/modules/ROOT/examples/coordination/Selfex.java new file mode 100644 index 000000000..ff73afd61 --- /dev/null +++ b/docs/modules/ROOT/examples/coordination/Selfex.java @@ -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/modules/ROOT/examples/coordination/TimeoutException.java b/docs/modules/ROOT/examples/coordination/TimeoutException.java new file mode 100644 index 000000000..e16aa7f09 --- /dev/null +++ b/docs/modules/ROOT/examples/coordination/TimeoutException.java @@ -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/modules/ROOT/examples/coordination/lib.lst b/docs/modules/ROOT/examples/coordination/lib.lst new file mode 100644 index 000000000..2d85cad90 --- /dev/null +++ b/docs/modules/ROOT/examples/coordination/lib.lst @@ -0,0 +1,8 @@ +Condition.java +CoordinationAction.java +Coordinator.java +Exclusion.java +MethodState.java +Mutex.java +Selfex.java +TimeoutException.java diff --git a/docs/modules/ROOT/examples/introduction/CloneablePoint.java b/docs/modules/ROOT/examples/introduction/CloneablePoint.java new file mode 100644 index 000000000..c34509850 --- /dev/null +++ b/docs/modules/ROOT/examples/introduction/CloneablePoint.java @@ -0,0 +1,42 @@ +/* + +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. + +*/ +package introduction; + +public aspect CloneablePoint { + + declare parents: Point implements Cloneable; + + public Object Point.clone() throws CloneNotSupportedException { + // we choose to bring all fields up to date before cloning. + makeRectangular(); + makePolar(); + return super.clone(); + } + + public static void main(String[] args){ + Point p1 = new Point(); + Point p2 = null; + + p1.setPolar(Math.PI, 1.0); + try { + p2 = (Point)p1.clone(); + } catch (CloneNotSupportedException e) {} + System.out.println("p1 =" + p1 ); + System.out.println("p2 =" + p2 ); + + p1.rotate(Math.PI / -2); + System.out.println("p1 =" + p1 ); + System.out.println("p2 =" + p2 ); + } +} diff --git a/docs/modules/ROOT/examples/introduction/ComparablePoint.java b/docs/modules/ROOT/examples/introduction/ComparablePoint.java new file mode 100644 index 000000000..a2893dba0 --- /dev/null +++ b/docs/modules/ROOT/examples/introduction/ComparablePoint.java @@ -0,0 +1,46 @@ +/* +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. +*/ + +package introduction; + +public aspect ComparablePoint { + + declare parents: Point implements Comparable; + + public int Point.compareTo(Object o) { + return (int) (this.getRho() - ((Point)o).getRho()); + } + + public static void main(String[] args){ + Point p1 = new Point(); + Point p2 = new Point(); + + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.setRectangular(2,5); + p2.setRectangular(2,5); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p2.setRectangular(3,6); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.setPolar(Math.PI, 4); + p2.setPolar(Math.PI, 4); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.rotate(Math.PI / 4.0); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + + p1.offset(1,1); + System.out.println("p1 =?= p2 :" + p1.compareTo(p2)); + } +} diff --git a/docs/modules/ROOT/examples/introduction/HashablePoint.java b/docs/modules/ROOT/examples/introduction/HashablePoint.java new file mode 100644 index 000000000..39eb33ba4 --- /dev/null +++ b/docs/modules/ROOT/examples/introduction/HashablePoint.java @@ -0,0 +1,47 @@ +/* +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. +*/ + +package introduction; + +import java.util.Hashtable; + +public aspect HashablePoint { + + public int Point.hashCode() { + return (int) (getX() + getY() % Integer.MAX_VALUE); + } + + public boolean Point.equals(Object o) { + if (o == this) { return true; } + if (!(o instanceof Point)) { return false; } + Point other = (Point)o; + return (getX() == other.getX()) && (getY() == other.getY()); + } + + public static void main(String[] args) { + Hashtable h = new Hashtable(); + Point p1 = new Point(); + + p1.setRectangular(10, 10); + Point p2 = new Point(); + + p2.setRectangular(10, 10); + + System.out.println("p1 = " + p1); + System.out.println("p2 = " + p2); + System.out.println("p1.hashCode() = " + p1.hashCode()); + System.out.println("p2.hashCode() = " + p2.hashCode()); + + h.put(p1, "P1"); + System.out.println("Got: " + h.get(p2)); + } +} diff --git a/docs/modules/ROOT/examples/introduction/Point.java b/docs/modules/ROOT/examples/introduction/Point.java new file mode 100644 index 000000000..4de01359b --- /dev/null +++ b/docs/modules/ROOT/examples/introduction/Point.java @@ -0,0 +1,98 @@ +/* + 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. +*/ + +package introduction; + +public class Point { + + protected double x = 0; + protected double y = 0; + protected double theta = 0; + protected double rho = 0; + + protected boolean polar = true; + protected boolean rectangular = true; + + public double getX(){ + makeRectangular(); + return x; + } + + public double getY(){ + makeRectangular(); + return y; + } + + public double getTheta(){ + makePolar(); + return theta; + } + + public double getRho(){ + makePolar(); + return rho; + } + + public void setRectangular(double newX, double newY){ + x = newX; + y = newY; + rectangular = true; + polar = false; + } + + public void setPolar(double newTheta, double newRho){ + theta = newTheta; + rho = newRho; + rectangular = false; + polar = true; + } + + public void rotate(double angle){ + setPolar(theta + angle, rho); + } + + public void offset(double deltaX, double deltaY){ + setRectangular(x + deltaX, y + deltaY); + } + + protected void makePolar(){ + if (!polar){ + theta = Math.atan2(y,x); + rho = y / Math.sin(theta); + polar = true; + } + } + + protected void makeRectangular(){ + if (!rectangular) { + y = rho * Math.sin(theta); + x = rho * Math.cos(theta); + rectangular = true; + } + } + + public String toString(){ + return "(" + getX() + ", " + getY() + ")[" + + getTheta() + " : " + getRho() + "]"; + } + + public static void main(String[] args){ + Point p1 = new Point(); + System.out.println("p1 =" + p1); + p1.setRectangular(5,2); + System.out.println("p1 =" + p1); + p1.setPolar( Math.PI / 4.0 , 1.0); + System.out.println("p1 =" + p1); + p1.setPolar( 0.3805 , 5.385); + System.out.println("p1 =" + p1); + } +} diff --git a/docs/modules/ROOT/examples/introduction/files.lst b/docs/modules/ROOT/examples/introduction/files.lst new file mode 100644 index 000000000..09a031d4b --- /dev/null +++ b/docs/modules/ROOT/examples/introduction/files.lst @@ -0,0 +1,4 @@ +Point.java +CloneablePoint.java +ComparablePoint.java +HashablePoint.java diff --git a/docs/modules/ROOT/examples/ltw/HelloWorld.java b/docs/modules/ROOT/examples/ltw/HelloWorld.java new file mode 100644 index 000000000..1d44b8b82 --- /dev/null +++ b/docs/modules/ROOT/examples/ltw/HelloWorld.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt + * + * Contributors: + * Matthew Webster initial implementation + */ +public class HelloWorld { + + public static void main (String[] args) { + System.out.println("Hello World!"); + } +} diff --git a/docs/modules/ROOT/examples/ltw/README b/docs/modules/ROOT/examples/ltw/README new file mode 100644 index 000000000..43868a2e2 --- /dev/null +++ b/docs/modules/ROOT/examples/ltw/README @@ -0,0 +1,42 @@ + +For users of JDK 1.4 the bin directory of your AspectJ distribution +contains a script "aj" to perform load-time weaving. Java classes on +the CLASSPATH are loaded and woven with aspects also on the CLASSPATH +which are declared in an aop.xml file. This file is either created by +the user or generated by the compiler. Alternatively aspects can be +loaded from an explicitly defined ASPECTPATH. + +For users of JDK 1.5 the bin directory of your AspectJ distribution +contains a script "aj5" to perform load-time weaving using an agent. +This uses an aop.xml as described above. + +--To compile the HelloWorld program-- + + ajc -outjar hello.jar HelloWorld.java + +--To compile the Tracing aspect-- + + ajc -outjar tracing.jar -outxml Tracing.aj + +--To run the example-- + + set CLASSPATH to include hello.jar + + aj HelloWorld + +--To run the example with tracing-- + + set CLASSPATH to include "tracing.jar" + + aj HelloWorld + +--To run the example with tracing using ASPECTPATH-- + + set ASPECTPATH=tracing.jar + + aj HelloWorld + +--To run the example with tracing using an agent-- + + aj5 HelloWorld + diff --git a/docs/modules/ROOT/examples/ltw/Tracing.aj b/docs/modules/ROOT/examples/ltw/Tracing.aj new file mode 100644 index 000000000..de20c5403 --- /dev/null +++ b/docs/modules/ROOT/examples/ltw/Tracing.aj @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt + * + * Contributors: + * Matthew Webster initial implementation + */ +public aspect Tracing { + + private pointcut mainMethod () : + execution(public static void main(String[])); + + before () : mainMethod() { + System.out.println("> " + thisJoinPoint); + } + + after () : mainMethod() { + System.out.println("< " + thisJoinPoint); + } +} diff --git a/docs/modules/ROOT/examples/observer/Button.java b/docs/modules/ROOT/examples/observer/Button.java new file mode 100644 index 000000000..79b33caa9 --- /dev/null +++ b/docs/modules/ROOT/examples/observer/Button.java @@ -0,0 +1,40 @@ +/* +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. +*/ + + +package observer; + +import java.awt.Color; +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +class Button extends java.awt.Button { + + static final Color defaultBackgroundColor = Color.gray; + static final Color defaultForegroundColor = Color.black; + static final String defaultText = "cycle color"; + + Button(Display display) { + super(); + setLabel(defaultText); + setBackground(defaultBackgroundColor); + setForeground(defaultForegroundColor); + addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Button.this.click(); + } + }); + display.addToFrame(this); + } + + public void click() {} +} diff --git a/docs/modules/ROOT/examples/observer/ColorLabel.java b/docs/modules/ROOT/examples/observer/ColorLabel.java new file mode 100644 index 000000000..5709545f2 --- /dev/null +++ b/docs/modules/ROOT/examples/observer/ColorLabel.java @@ -0,0 +1,34 @@ +/* +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. +*/ + +package observer; +import java.awt.Color; +import java.awt.Label; + +class ColorLabel extends Label { + + ColorLabel(Display display) { + super(); + display.addToFrame(this); + } + + final static Color[] colors = {Color.red, Color.blue, + Color.green, Color.magenta}; + private int colorIndex = 0; + private int cycleCount = 0; + void colorCycle() { + cycleCount++; + colorIndex = (colorIndex + 1) % colors.length; + setBackground(colors[colorIndex]); + setText("" + cycleCount); + } +} diff --git a/docs/modules/ROOT/examples/observer/Demo.java b/docs/modules/ROOT/examples/observer/Demo.java new file mode 100644 index 000000000..03be6a614 --- /dev/null +++ b/docs/modules/ROOT/examples/observer/Demo.java @@ -0,0 +1,29 @@ +/* +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. +*/ + +package observer; + +public class Demo { + public static void main(String[] args) { + + Display display = new Display(); + Button b1 = new Button(display); + Button b2 = new Button(display); + ColorLabel c1 = new ColorLabel(display); + ColorLabel c2 = new ColorLabel(display); + ColorLabel c3 = new ColorLabel(display); + + b1.addObserver(c1); + b1.addObserver(c2); + b2.addObserver(c3); + } +} diff --git a/docs/modules/ROOT/examples/observer/Display.java b/docs/modules/ROOT/examples/observer/Display.java new file mode 100644 index 000000000..67ed2cb5b --- /dev/null +++ b/docs/modules/ROOT/examples/observer/Display.java @@ -0,0 +1,46 @@ +/* +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. +*/ + +package observer; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Container; +import java.awt.Component; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.BorderLayout; + +/* + * Display is the container class that holds all the views of the + * colored number. + * In this demo, it holds buttons. + */ + +class Display extends Panel { + + protected Frame frame = new Frame("Subject/Observer Demo"); + + Display() { + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) {System.exit(0);} + }); + + frame.add(this, BorderLayout.CENTER); + frame.pack(); + frame.setVisible(true); + } + + void addToFrame(Component c) { + add(c); + frame.pack(); + } +} diff --git a/docs/modules/ROOT/examples/observer/Observer.java b/docs/modules/ROOT/examples/observer/Observer.java new file mode 100644 index 000000000..2851ebe17 --- /dev/null +++ b/docs/modules/ROOT/examples/observer/Observer.java @@ -0,0 +1,18 @@ +/* +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. +*/ +package observer; + +interface Observer { + void setSubject(Subject s); + Subject getSubject(); + void update(); +} diff --git a/docs/modules/ROOT/examples/observer/Subject.java b/docs/modules/ROOT/examples/observer/Subject.java new file mode 100644 index 000000000..d6c144e38 --- /dev/null +++ b/docs/modules/ROOT/examples/observer/Subject.java @@ -0,0 +1,21 @@ +/* +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. +*/ + +package observer; +import java.util.Vector; + +interface Subject { + void addObserver(Observer obs); + void removeObserver(Observer obs); + Vector getObservers(); + Object getData(); +} diff --git a/docs/modules/ROOT/examples/observer/SubjectObserverProtocol.java b/docs/modules/ROOT/examples/observer/SubjectObserverProtocol.java new file mode 100644 index 000000000..05e54d76c --- /dev/null +++ b/docs/modules/ROOT/examples/observer/SubjectObserverProtocol.java @@ -0,0 +1,41 @@ +/* +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. +*/ + +package observer; + +import java.util.Vector; + +abstract aspect SubjectObserverProtocol { + + abstract pointcut stateChanges(Subject s); + + after(Subject s): stateChanges(s) { + for (int i = 0; i < s.getObservers().size(); i++) { + ((Observer)s.getObservers().elementAt(i)).update(); + } + } + + private Vector Subject.observers = new Vector(); + public void Subject.addObserver(Observer obs) { + observers.addElement(obs); + obs.setSubject(this); + } + public void Subject.removeObserver(Observer obs) { + observers.removeElement(obs); + obs.setSubject(null); + } + public Vector Subject.getObservers() { return observers; } + + private Subject Observer.subject = null; + public void Observer.setSubject(Subject s) { subject = s; } + public Subject Observer.getSubject() { return subject; } +} diff --git a/docs/modules/ROOT/examples/observer/SubjectObserverProtocolImpl.java b/docs/modules/ROOT/examples/observer/SubjectObserverProtocolImpl.java new file mode 100644 index 000000000..2bc75918c --- /dev/null +++ b/docs/modules/ROOT/examples/observer/SubjectObserverProtocolImpl.java @@ -0,0 +1,31 @@ +/* +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. +*/ + +package observer; + +import java.util.Vector; + +aspect SubjectObserverProtocolImpl extends SubjectObserverProtocol { + + declare parents: Button implements Subject; + public Object Button.getData() { return this; } + + declare parents: ColorLabel implements Observer; + public void ColorLabel.update() { + colorCycle(); + } + + pointcut stateChanges(Subject s): + target(s) && + call(void Button.click()); + +} diff --git a/docs/modules/ROOT/examples/observer/files.lst b/docs/modules/ROOT/examples/observer/files.lst new file mode 100644 index 000000000..9b800286e --- /dev/null +++ b/docs/modules/ROOT/examples/observer/files.lst @@ -0,0 +1,8 @@ +ColorLabel.java +Button.java +Display.java +Subject.java +Observer.java +SubjectObserverProtocol.java +SubjectObserverProtocolImpl.java +Demo.java diff --git a/docs/modules/ROOT/examples/spacewar/Bullet.java b/docs/modules/ROOT/examples/spacewar/Bullet.java new file mode 100644 index 000000000..6581dbbf7 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Bullet.java @@ -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/modules/ROOT/examples/spacewar/Debug.java b/docs/modules/ROOT/examples/spacewar/Debug.java new file mode 100644 index 000000000..a3afb1dda --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Debug.java @@ -0,0 +1,219 @@ +/* + +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 --->| + +Debug.java +Part of the Spacewar system. + +*/ + +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 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/modules/ROOT/examples/spacewar/Display.java b/docs/modules/ROOT/examples/spacewar/Display.java new file mode 100644 index 000000000..4236407ee --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Display.java @@ -0,0 +1,165 @@ +/* + +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; + +/** + * 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/modules/ROOT/examples/spacewar/Display1.java b/docs/modules/ROOT/examples/spacewar/Display1.java new file mode 100644 index 000000000..622f7d051 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Display1.java @@ -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 --->| + + +Display1.java +Part of the Spacewar system. +*/ + +package spacewar; + + +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/modules/ROOT/examples/spacewar/Display2.java b/docs/modules/ROOT/examples/spacewar/Display2.java new file mode 100644 index 000000000..0430a1cc5 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Display2.java @@ -0,0 +1,136 @@ +/* + +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.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/modules/ROOT/examples/spacewar/EnergyPacket.java b/docs/modules/ROOT/examples/spacewar/EnergyPacket.java new file mode 100644 index 000000000..d7bc4f9ec --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/EnergyPacket.java @@ -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/modules/ROOT/examples/spacewar/EnergyPacketProducer.java b/docs/modules/ROOT/examples/spacewar/EnergyPacketProducer.java new file mode 100644 index 000000000..efd276042 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/EnergyPacketProducer.java @@ -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/modules/ROOT/examples/spacewar/EnsureShipIsAlive.java b/docs/modules/ROOT/examples/spacewar/EnsureShipIsAlive.java new file mode 100644 index 000000000..f7b949a92 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/EnsureShipIsAlive.java @@ -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/modules/ROOT/examples/spacewar/Game.java b/docs/modules/ROOT/examples/spacewar/Game.java new file mode 100644 index 000000000..54b1bf2ac --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Game.java @@ -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 mode 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/modules/ROOT/examples/spacewar/GameSynchronization.java b/docs/modules/ROOT/examples/spacewar/GameSynchronization.java new file mode 100644 index 000000000..dcf42e904 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/GameSynchronization.java @@ -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/modules/ROOT/examples/spacewar/Makefile b/docs/modules/ROOT/examples/spacewar/Makefile new file mode 100644 index 000000000..e425dfd55 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Makefile @@ -0,0 +1,12 @@ +SHELL=bash +ACJOPTS=-verbose -nosymbols +AJC=ajc + +.PHONY: demo debug + +demo: + $(AJC) $(ACJOPTS) @demo.lst + +debug: + $(AJC) $(ACJOPTS) @debug.lst + diff --git a/docs/modules/ROOT/examples/spacewar/Pilot.java b/docs/modules/ROOT/examples/spacewar/Pilot.java new file mode 100644 index 000000000..330d860bf --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Pilot.java @@ -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/modules/ROOT/examples/spacewar/Player.java b/docs/modules/ROOT/examples/spacewar/Player.java new file mode 100644 index 000000000..3899c6d52 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Player.java @@ -0,0 +1,121 @@ +/* + +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.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/modules/ROOT/examples/spacewar/README.adoc b/docs/modules/ROOT/examples/spacewar/README.adoc new file mode 100644 index 000000000..d39b9b5fc --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/README.adoc @@ -0,0 +1,56 @@ +[[_5]] += Exploring the Spacewar Example + +_© Copyright 1997-2001 Xerox Corporation. All rights reserved._ + +_Last updated: January 10, 2001_ + +The code in this directory is an implementation of the classic video +game Spacewar. + +The Spacewar game is intended to provide a modest-sized example of a +program that uses aspects. The code for this example is evolving, as we +add new features to AspectJ and come up with a better understanding of +how to use the features. + +In order to compile and run this example, make sure to have the latest +version of AspectJ correctly installed. If you're not sure you do, try +the helloworld example first by following the instructions in +xref:../doc/primer/default.html[Primer] section Getting Started. + +[[_5_1]] +== Compiling Spacewar + +* Change to the `examples` directory. +* Type `ajc -argfile spacewar/demo.lst` to compile the system. + +[[_5_2]] +== Running Spacewar + +* In the examples directory, type `java spacewar.Game` + +When the game starts up you will see two different displays. These are +the two built-in display aspects of the game. In each you will see a +single white ship and two red ships. The white ship is yours to control; +the red ships are an enemy robots. Your ship is controlled with the four +arrow keys to turn, thrust and stop; the spacebar fires. As you play, +the game will be displayed in both windows. + +When running on a 1.4 or later VM, click in the main panel to give it +focus so that your keystrokes are recognized. + +You can quit the game with ctl-Q. + +[[_5_3]] +== Exploring the Code + +There is one other built-in configurations for the Spacewar game. Try it +by typing `ajc @spacewar\debug.lst`. This compiles in an elaborate +debugging aspect for the game. + +We recommend you explore the Spacewar source code and look at the +aspects that it uses. You will find several of them, of different scales +and different degrees of cross-cutting. Remember that these represent +our evolving understanding of how to use AspectJ to implement Spacewar. +If you believe we should be doing something differently, then please let +us know. diff --git a/docs/modules/ROOT/examples/spacewar/Registry.java b/docs/modules/ROOT/examples/spacewar/Registry.java new file mode 100644 index 000000000..a9cec0418 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Registry.java @@ -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/modules/ROOT/examples/spacewar/RegistrySynchronization.java b/docs/modules/ROOT/examples/spacewar/RegistrySynchronization.java new file mode 100644 index 000000000..986e4bd30 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/RegistrySynchronization.java @@ -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/modules/ROOT/examples/spacewar/Robot.java b/docs/modules/ROOT/examples/spacewar/Robot.java new file mode 100644 index 000000000..05f276108 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Robot.java @@ -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/modules/ROOT/examples/spacewar/SWFrame.java b/docs/modules/ROOT/examples/spacewar/SWFrame.java new file mode 100644 index 000000000..6dfb9f6f6 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/SWFrame.java @@ -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/modules/ROOT/examples/spacewar/Ship.java b/docs/modules/ROOT/examples/spacewar/Ship.java new file mode 100644 index 000000000..9978fe694 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Ship.java @@ -0,0 +1,296 @@ +/* + +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()) ); + + + /** + * 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; + + 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(); + } + } +} diff --git a/docs/modules/ROOT/examples/spacewar/SpaceObject.java b/docs/modules/ROOT/examples/spacewar/SpaceObject.java new file mode 100644 index 000000000..ee3afabcc --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/SpaceObject.java @@ -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/modules/ROOT/examples/spacewar/Timer.java b/docs/modules/ROOT/examples/spacewar/Timer.java new file mode 100644 index 000000000..1f4a992a7 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/Timer.java @@ -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) { } + } + } + } +} diff --git a/docs/modules/ROOT/examples/spacewar/debug.lst b/docs/modules/ROOT/examples/spacewar/debug.lst new file mode 100644 index 000000000..3de8ddafe --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/debug.lst @@ -0,0 +1,2 @@ +@demo.lst +Debug.java diff --git a/docs/modules/ROOT/examples/spacewar/demo.lst b/docs/modules/ROOT/examples/spacewar/demo.lst new file mode 100644 index 000000000..dd188af83 --- /dev/null +++ b/docs/modules/ROOT/examples/spacewar/demo.lst @@ -0,0 +1,19 @@ +@../coordination/lib.lst +Bullet.java +EnergyPacket.java +EnergyPacketProducer.java +Game.java +GameSynchronization.java +Pilot.java +Registry.java +RegistrySynchronization.java +Robot.java +Ship.java +EnsureShipIsAlive.java +SpaceObject.java +Timer.java +SWFrame.java +Display.java +Display1.java +Display2.java +Player.java diff --git a/docs/modules/ROOT/examples/telecom/AbstractSimulation.java b/docs/modules/ROOT/examples/telecom/AbstractSimulation.java new file mode 100644 index 000000000..1c44af7a7 --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/AbstractSimulation.java @@ -0,0 +1,80 @@ +/* + +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 telecom; + +public abstract class AbstractSimulation { + + public static AbstractSimulation simulation; + + /** + * Creates objects and puts them to work. + */ + public void run() { + Customer jim = new Customer("Jim", 650); + Customer mik = new Customer("Mik", 650); + Customer crista = new Customer("Crista", 415); + + say("jim calls mik..."); + Call c1 = jim.call(mik); + wait(1.0); + say("mik accepts..."); + mik.pickup(c1); + wait(2.0); + say("jim hangs up..."); + jim.hangup(c1); + report(jim); + report(mik); + report(crista); + + say("mik calls crista..."); + Call c2 = mik.call(crista); + say("crista accepts..."); + crista.pickup(c2); + wait(1.5); + say("crista hangs up..."); + crista.hangup(c2); + report(jim); + report(mik); + report(crista); + } + + /** + * Print a report of the connection time for customer + */ + abstract protected void report(Customer c); + + /** + * Wait 0.1 seconds per "second" for simulation + */ + protected static void wait(double seconds) { + Object dummy = new Object(); + synchronized (dummy) { + //XXX cheat and only wait 0.1 seconds per second + try {dummy.wait((long)(seconds*100)); } + catch (Exception e) {} + } + } + + /** + * Put a message on standard output + */ + protected static void say(String s){ + System.out.println(s); + } + +} diff --git a/docs/modules/ROOT/examples/telecom/BasicSimulation.java b/docs/modules/ROOT/examples/telecom/BasicSimulation.java new file mode 100644 index 000000000..ab7426376 --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/BasicSimulation.java @@ -0,0 +1,34 @@ +/* + +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 telecom; + +/** + * This simulation subclass implements AbstractSimulation.run(..) + * with a test script for the telecom system with only the + * basic objects. + */ +public class BasicSimulation extends AbstractSimulation { + + public static void main(String[] args){ + simulation = new BasicSimulation(); + simulation.run(); + } + + protected void report(Customer c) { } + +} diff --git a/docs/modules/ROOT/examples/telecom/Billing.java b/docs/modules/ROOT/examples/telecom/Billing.java new file mode 100644 index 000000000..651d64b36 --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/Billing.java @@ -0,0 +1,73 @@ +/* +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. +*/ + +package telecom; +/** + * The Billing aspect deals with... billing. + * How much money did each connection cost? + * How much money did each call cost? + * How much money is being debited to a customer? + * This aspect can be used by other parts of the system. (not in this example) + * + * Billing can depend many things, such as timing, the type of the connection, + * some special discounts the customer has, special features, etc. In here, + * it depends only on timing and on the type of the connection. + */ +public aspect Billing { + // precedence required to get advice on endtiming in the right order + declare precedence: Billing, Timing; + + public static final long LOCAL_RATE = 3; + public static final long LONG_DISTANCE_RATE = 10; + + public Customer Connection.payer; + public Customer getPayer(Connection conn) { return conn.payer; } + /** + * Caller pays for the call + */ + after(Customer cust) returning (Connection conn): + args(cust, ..) && call(Connection+.new(..)) { + conn.payer = cust; + } + + /** + * Connections give the appropriate call rate + */ + public abstract long Connection.callRate(); + + + public long LongDistance.callRate() { return LONG_DISTANCE_RATE; } + public long Local.callRate() { return LOCAL_RATE; } + + + /** + * When timing stops, calculate and add the charge from the + * connection time + */ + after(Connection conn): Timing.endTiming(conn) { + long time = Timing.aspectOf().getTimer(conn).getTime(); + long rate = conn.callRate(); + long cost = rate * time; + getPayer(conn).addCharge(cost); + } + + + /** + * Customers have a bill paying aspect with state + */ + public long Customer.totalCharge = 0; + public long getTotalCharge(Customer cust) { return cust.totalCharge; } + + public void Customer.addCharge(long charge){ + totalCharge += charge; + } +} diff --git a/docs/modules/ROOT/examples/telecom/BillingSimulation.java b/docs/modules/ROOT/examples/telecom/BillingSimulation.java new file mode 100644 index 000000000..09f273ff6 --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/BillingSimulation.java @@ -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 telecom; + +/** + * This simulation subclass implements AbstractSimulation.report(..) + * + */ +public class BillingSimulation extends AbstractSimulation { + + public static void main(String[] args){ + System.out.println("\n... Billing simulation 2 ...\n"); + simulation = new BillingSimulation(); + simulation.run(); + } + + /** + * Print a report of the connection time and the bill for customer + */ + protected void report(Customer c){ + Timing t = Timing.aspectOf(); + Billing b = Billing.aspectOf(); + System.out.println(c + " has been connected for " + + t.getTotalConnectTime(c) + + " seconds and has a bill of " + + b.getTotalCharge(c)); + } +} + diff --git a/docs/modules/ROOT/examples/telecom/Call.java b/docs/modules/ROOT/examples/telecom/Call.java new file mode 100644 index 000000000..3d3489e86 --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/Call.java @@ -0,0 +1,97 @@ +/* + +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 telecom; +import java.util.Vector; +import java.util.Enumeration; + +/** + * A call supports the process of a customer trying to + * connect to others. + */ +public class Call { + + private Customer caller, receiver; + private Vector connections = new Vector(); + + /** + * Create a new call connecting caller to receiver + * with a new connection. This should really only be + * called by Customer.call(..) + */ + public Call(Customer caller, Customer receiver) { + this.caller = caller; + this.receiver = receiver; + Connection c; + if (receiver.localTo(caller)) { + c = new Local(caller, receiver); + } else { + c = new LongDistance(caller, receiver); + } + connections.addElement(c); + } + + /** + * picking up a call completes the current connection + * (this means that you shouldnt merge calls until + * they are completed) + */ + public void pickup() { + Connection connection = (Connection)connections.lastElement(); + connection.complete(); + } + + + /** + * Is the call in a connected state? + */ + public boolean isConnected(){ + return ((Connection)connections.lastElement()).getState() + == Connection.COMPLETE; + } + + /** + * hanging up a call drops the connection + */ + public void hangup(Customer c) { + for(Enumeration e = connections.elements(); e.hasMoreElements();) { + ((Connection)e.nextElement()).drop(); + } + } + + /** + * is Customer c one of the customers in this call? + */ + public boolean includes(Customer c){ + boolean result = false; + for(Enumeration e = connections.elements(); e.hasMoreElements();) { + result = result || ((Connection)e.nextElement()).connects(c); + } + return result; + } + + /** + * Merge all connections from call 'other' into 'this' + */ + public void merge(Call other){ + for(Enumeration e = other.connections.elements(); e.hasMoreElements();){ + Connection conn = (Connection)e.nextElement(); + other.connections.removeElement(conn); + connections.addElement(conn); + } + } +} diff --git a/docs/modules/ROOT/examples/telecom/Connection.java b/docs/modules/ROOT/examples/telecom/Connection.java new file mode 100644 index 000000000..7d54ec843 --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/Connection.java @@ -0,0 +1,87 @@ +/* + +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 telecom; + +/** + * Connections are circuits between customers + * There are two kinds: local and long distance + * see subclasses at the end of this file. + */ +public abstract class Connection { + + public static final int PENDING = 0; + public static final int COMPLETE = 1; + public static final int DROPPED = 2; + + Customer caller, receiver; + private int state = PENDING; + + /** + * Creatte a new Connection between a and b + */ + Connection(Customer a, Customer b) { + this.caller = a; + this.receiver = b; + } + + /** + * what is the state of the connection? + */ + public int getState(){ + return state; + } + + /** + * get the customer who initiated this connection + */ + public Customer getCaller() { return caller; } + + /** + * get the customer who received this connection + */ + public Customer getReceiver() { return receiver; } + + /** + * Called when a call is picked up. This means the b side has picked up + * and the connection should now complete itself and start passing data. + */ + void complete() { + state = COMPLETE; + System.out.println("connection completed"); + } + + /** + * Called when the connection is dropped from a call. Is intended to + * free up any resources the connection was consuming. + */ + void drop() { + state = DROPPED; + System.out.println("connection dropped"); + } + + /** + * Is customer c connected by this connection? + */ + public boolean connects(Customer c){ + return (caller == c || receiver == c); + } + +} + + + diff --git a/docs/modules/ROOT/examples/telecom/Customer.java b/docs/modules/ROOT/examples/telecom/Customer.java new file mode 100644 index 000000000..1e099984c --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/Customer.java @@ -0,0 +1,112 @@ +/* + +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 telecom; +import java.util.Vector; + +/** + * Customers have a unique id (name in this case for didactic purposes + * but it could be telephone number) and area code. + * They also have protocol for managing calls: call, pickup, etc. + */ +public class Customer { + + private String name; + private int areacode; + private Vector calls = new Vector(); + + /** + * unregister a call + */ + protected void removeCall(Call c){ + calls.removeElement(c); + } + + /** + * register a call + */ + protected void addCall(Call c){ + calls.addElement(c); + } + + /** + * Make a new customer with given name + */ + public Customer(String name, int areacode) { + this.name = name; + this.areacode = areacode; + } + + /** + * String rendition of customer + */ + public String toString() { + return name + "(" + areacode + ")"; + } + + /** + * what area is the customer in? + */ + public int getAreacode(){ + return areacode; + } + + /** + * Is the other customer in the same area? + */ + public boolean localTo(Customer other){ + return areacode == other.areacode; + } + + /** + * Make a new call to receiver + */ + public Call call(Customer receiver) { + Call call = new Call(this, receiver); + addCall(call); + return call; + } + + /** + * pick up a call + */ + public void pickup(Call call) { + call.pickup(); + addCall(call); + } + + /** + * hang up a call + */ + public void hangup(Call call) { + call.hangup(this); + removeCall(call); + } + + /** + * Merge a pair of calls -- conference them + * PRE: call1.includes(this) + * call2.includes(this) + * call1.connected() + * call2.connected() + * POST: call1 includes all customers connected by call1@pre and call2@pre + */ + public void merge(Call call1, Call call2){ + call1.merge(call2); + removeCall(call2); + } +} diff --git a/docs/modules/ROOT/examples/telecom/Local.java b/docs/modules/ROOT/examples/telecom/Local.java new file mode 100644 index 000000000..e0bc02679 --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/Local.java @@ -0,0 +1,26 @@ +/* + +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 telecom; + +public class Local extends Connection { + Local(Customer a, Customer b) { + super(a, b); + System.out.println("[new local connection from " + + a + " to " + b + "]"); + } +} diff --git a/docs/modules/ROOT/examples/telecom/LongDistance.java b/docs/modules/ROOT/examples/telecom/LongDistance.java new file mode 100644 index 000000000..b2ed6eb7d --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/LongDistance.java @@ -0,0 +1,26 @@ +/* + +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 telecom; + +public class LongDistance extends Connection { + LongDistance(Customer a, Customer b) { + super(a, b); + System.out.println("[new long distance connection from " + + a + " to " + b + "]"); + } +} diff --git a/docs/modules/ROOT/examples/telecom/Timer.java b/docs/modules/ROOT/examples/telecom/Timer.java new file mode 100644 index 000000000..813ae3a0d --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/Timer.java @@ -0,0 +1,50 @@ +/* + +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 telecom; + + +/** + * Simple timer machine used to record elapsed time + */ +public class Timer { + public long startTime, stopTime; + + /** + * set the start time + */ + public void start() { + startTime = System.currentTimeMillis(); + stopTime = startTime; + } + + /** + * set the end time + */ + public void stop() { + stopTime = System.currentTimeMillis(); + } + + /** + * set how much time passed between last start and stop? + */ + public long getTime() { + return stopTime - startTime; + } +} + + diff --git a/docs/modules/ROOT/examples/telecom/TimerLog.java b/docs/modules/ROOT/examples/telecom/TimerLog.java new file mode 100644 index 000000000..c736625b5 --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/TimerLog.java @@ -0,0 +1,23 @@ +/* +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. +*/ +package telecom; + +public aspect TimerLog { + + after(Timer t): target(t) && call(* Timer.start()) { + System.err.println("Timer started: " + t.startTime); + } + + after(Timer t): target(t) && call(* Timer.stop()) { + System.err.println("Timer stopped: " + t.stopTime); + } +} diff --git a/docs/modules/ROOT/examples/telecom/Timing.java b/docs/modules/ROOT/examples/telecom/Timing.java new file mode 100644 index 000000000..29eba02ea --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/Timing.java @@ -0,0 +1,57 @@ +/* +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. +*/ + +package telecom; + +/** + * The Timing aspect is concerned with the duration + * of connections and with customer's cumulative + * connection time. + */ +public aspect Timing { + + /** + * Every Customer has a total connection time + */ + public long Customer.totalConnectTime = 0; + + public long getTotalConnectTime(Customer cust) { + return cust.totalConnectTime; + } + /** + * Every connection has a timer + */ + private Timer Connection.timer = new Timer(); + public Timer getTimer(Connection conn) { return conn.timer; } + + /** + * Start the timer when call completed + */ + after (Connection c): target(c) && call(void Connection.complete()) { + getTimer(c).start(); + } + + /** + * When to stop the timer + */ + pointcut endTiming(Connection c): target(c) && + call(void Connection.drop()); + + /** + * Stop the timer when call dropped and update the involved parties + */ + after(Connection c): endTiming(c) { + getTimer(c).stop(); + c.getCaller().totalConnectTime += getTimer(c).getTime(); + c.getReceiver().totalConnectTime += getTimer(c).getTime(); + } +} diff --git a/docs/modules/ROOT/examples/telecom/TimingSimulation.java b/docs/modules/ROOT/examples/telecom/TimingSimulation.java new file mode 100644 index 000000000..309563769 --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/TimingSimulation.java @@ -0,0 +1,40 @@ +/* + +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 telecom; + +/** + * This simulation subclass implements AbstractSimulation.report(..) + * + */ +public class TimingSimulation extends AbstractSimulation { + + public static void main(String[] args){ + System.out.println("\n... Timing simulation 2 ...\n"); + simulation = new TimingSimulation(); + simulation.run(); + } + + /** + * Print a report of the connection time for customer + */ + protected void report(Customer c){ + Timing t = Timing.aspectOf(); + System.out.println(c + " spent " + t.getTotalConnectTime(c)); + } + +} diff --git a/docs/modules/ROOT/examples/telecom/basic.lst b/docs/modules/ROOT/examples/telecom/basic.lst new file mode 100644 index 000000000..018a679ac --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/basic.lst @@ -0,0 +1,7 @@ +AbstractSimulation.java +BasicSimulation.java +Call.java +Connection.java +Local.java +LongDistance.java +Customer.java diff --git a/docs/modules/ROOT/examples/telecom/billing.lst b/docs/modules/ROOT/examples/telecom/billing.lst new file mode 100644 index 000000000..7b2cf087c --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/billing.lst @@ -0,0 +1,10 @@ +AbstractSimulation.java +BillingSimulation.java +Call.java +Connection.java +Local.java +LongDistance.java +Customer.java +Timer.java +Billing.java +Timing.java diff --git a/docs/modules/ROOT/examples/telecom/timing.lst b/docs/modules/ROOT/examples/telecom/timing.lst new file mode 100644 index 000000000..3ca514f85 --- /dev/null +++ b/docs/modules/ROOT/examples/telecom/timing.lst @@ -0,0 +1,10 @@ +AbstractSimulation.java +TimingSimulation.java +Call.java +Connection.java +Local.java +LongDistance.java +Customer.java +Timer.java +TimerLog.java +Timing.java diff --git a/docs/modules/ROOT/examples/tjp/Demo.java b/docs/modules/ROOT/examples/tjp/Demo.java new file mode 100644 index 000000000..64d249c82 --- /dev/null +++ b/docs/modules/ROOT/examples/tjp/Demo.java @@ -0,0 +1,37 @@ +/* + +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. + +*/ +package tjp; + +public class Demo { + static Demo d; + + public static void main(String[] args){ + new Demo().go(); + } + + void go(){ + d = new Demo(); + d.foo(1,d); + System.out.println(d.bar(new Integer(3))); + } + + void foo(int i, Object o){ + System.out.println("Demo.foo(" + i + ", " + o + ")\n"); + } + + String bar (Integer j){ + System.out.println("Demo.bar(" + j + ")\n"); + return "Demo.bar(" + j + ")"; + } +} diff --git a/docs/modules/ROOT/examples/tjp/GetInfo.java b/docs/modules/ROOT/examples/tjp/GetInfo.java new file mode 100644 index 000000000..0d38a3766 --- /dev/null +++ b/docs/modules/ROOT/examples/tjp/GetInfo.java @@ -0,0 +1,49 @@ +/* +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. +*/ + +package tjp; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.reflect.CodeSignature; + +aspect GetInfo { + + static final void println(String s){ System.out.println(s); } + + pointcut goCut(): cflow(this(Demo) && execution(void go())); + + pointcut demoExecs(): within(Demo) && execution(* *(..)); + + Object around(): demoExecs() && !execution(* go()) && goCut() { + println("Intercepted message: " + + thisJoinPointStaticPart.getSignature().getName()); + println("in class: " + + thisJoinPointStaticPart.getSignature().getDeclaringType().getName()); + printParameters(thisJoinPoint); + println("Running original method: \n" ); + Object result = proceed(); + println(" result: " + result ); + return result; + } + + static private void printParameters(JoinPoint jp) { + println("Arguments: " ); + Object[] args = jp.getArgs(); + String[] names = ((CodeSignature)jp.getSignature()).getParameterNames(); + Class[] types = ((CodeSignature)jp.getSignature()).getParameterTypes(); + for (int i = 0; i < args.length; i++) { + println(" " + i + ". " + names[i] + + " : " + types[i].getName() + + " = " + args[i]); + } + } +} diff --git a/docs/modules/ROOT/examples/tjp/files.lst b/docs/modules/ROOT/examples/tjp/files.lst new file mode 100644 index 000000000..0cfc34bdf --- /dev/null +++ b/docs/modules/ROOT/examples/tjp/files.lst @@ -0,0 +1,2 @@ +Demo.java +GetInfo.java diff --git a/docs/modules/ROOT/examples/tracing/Circle.java b/docs/modules/ROOT/examples/tracing/Circle.java new file mode 100644 index 000000000..76b73e20a --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/Circle.java @@ -0,0 +1,71 @@ +/* + +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 tracing; + +/** + * + * Circle is a 2D shape. It extends the TwoDShape class with the radius + * variable, and it implements TwoDShape's abstract methods for + * correctly computing a circle's area and distance. + * + */ +public class Circle extends TwoDShape { + protected double r; // radius + + /* + * All sorts of constructors + */ + public Circle(double x, double y, double r) { + super(x, y); this.r = r; + } + + public Circle(double x, double y) { + this(x, y, 1.0); + } + + public Circle(double r) { + this(0.0, 0.0, r); + } + + public Circle() { + this(0.0, 0.0, 1.0); + } + + /** + * Returns the perimeter of this circle + */ + public double perimeter() { + return 2 * Math.PI * r; + } + + /** + * Returns the area of this circle + */ + public double area() { + return Math.PI * r*r; + } + + /** + * This method overrides the one in the superclass. It adds some + * circle-specific information. + */ + public String toString() { + return ("Circle radius = " + String.valueOf(r) + super.toString()); + } +} diff --git a/docs/modules/ROOT/examples/tracing/ExampleMain.java b/docs/modules/ROOT/examples/tracing/ExampleMain.java new file mode 100644 index 000000000..93cc465b7 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/ExampleMain.java @@ -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 tracing; + +/** + * + * A main function for testing 2D shapes. + * + */ +public class ExampleMain { + public static void main(String[] args) { + Circle c1 = new Circle(3.0, 3.0, 2.0); + Circle c2 = new Circle(4.0); + + Square s1 = new Square(1.0, 2.0); + + System.out.println("c1.perimeter() = " + c1.perimeter()); + System.out.println("c1.area() = " + c1.area()); + + System.out.println("s1.perimeter() = " + s1.perimeter()); + System.out.println("s1.area() = " + s1.area()); + + System.out.println("c2.distance(c1) = " + c2.distance(c1)); + System.out.println("s1.distance(c1) = " + s1.distance(c1)); + + System.out.println("s1.toString(): " + s1.toString()); + } +} diff --git a/docs/modules/ROOT/examples/tracing/README b/docs/modules/ROOT/examples/tracing/README new file mode 100644 index 000000000..bf8e70390 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/README @@ -0,0 +1,32 @@ + +This directory contains several examples of tracing aspects, +including a reusable tracing library and examples of +using that library. + +A lesson in the AspectJ Primer explains all of this code. + +To work with these (or any other examples), first be sure .../examples +is on your classpath, where ... is where you have installed AspectJ. + + +--To compile and run the example without tracing-- + + ajc @.../examples/tracing/notrace.lst + + java tracing.ExampleMain + + +--To compile and run the example with tracing version<N>-- + + ajc @.../examples/tracing/tracev<N>.lst + + java tracing.version<N>.TraceMyClasses + +where <N> is 1, 2, 3 or 4 + +--To use the tracing.lib.AbstractTrace aspect-- + + Make sure .../examples is in your classpath. + + In order to use this aspect, please read the documentation under + tracing/doc diff --git a/docs/modules/ROOT/examples/tracing/Square.java b/docs/modules/ROOT/examples/tracing/Square.java new file mode 100644 index 000000000..78b36882d --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/Square.java @@ -0,0 +1,71 @@ +/* + +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 tracing; + +/** + * + * Square is a 2D shape. It extends the TwoDShape class with the side + * variable, and it implements TwoDShape's abstract methods for + * correctly computing a square's area and distance. + * + */ +public class Square extends TwoDShape { + protected double s; // side + + /* + * All sorts of constructors + */ + public Square(double x, double y, double s) { + super(x, y); this.s = s; + } + + public Square(double x, double y) { + this(x, y, 1.0); + } + + public Square(double s) { + this(0.0, 0.0, s); + } + + public Square() { + this(0.0, 0.0, 1.0); + } + + /** + * Returns the perimeter of this square + */ + public double perimeter() { + return 4 * s; + } + + /** + * Returns the area of this square + */ + public double area() { + return s*s; + } + + /** + * This method overrides the one in the superclass. It adds some + * circle-specific information. + */ + public String toString() { + return ("Square side = " + String.valueOf(s) + super.toString()); + } +} diff --git a/docs/modules/ROOT/examples/tracing/TwoDShape.java b/docs/modules/ROOT/examples/tracing/TwoDShape.java new file mode 100644 index 000000000..531b6f120 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/TwoDShape.java @@ -0,0 +1,69 @@ +/* +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. +*/ + +package tracing; + +/** + * TwoDShape is an abstract class that defines generic functionality + * for 2D shapes. + */ +public abstract class TwoDShape { + /** + * Coordinates of the center of the shape. + */ + protected double x, y; + + protected TwoDShape(double x, double y) { + this.x = x; this.y = y; + } + + /** + * Returns the x coordinate of the shape. + */ + public double getX() { return x; } + + /** + * Returns the y coordinate of the shape. + */ + public double getY() { return y; } + + /** + * Returns the distance between this shape and the shape given as + * parameter. + */ + public double distance(TwoDShape s) { + double dx = Math.abs(s.getX() - x); + double dy = Math.abs(s.getY() - y); + return Math.sqrt(dx*dx + dy*dy); + } + + /** + * Returns the perimeter of this shape. Must be defined in + * subclasses. + */ + public abstract double perimeter(); + + /** + * Returns the area of this shape. Must be defined in + * subclasses. + */ + public abstract double area(); + + /** + * Returns a string representation of 2D shapes -- simply its + * coordinates. + */ + public String toString() { + return (" @ (" + String.valueOf(x) + ", " + String.valueOf(y) + ") "); + } +} + diff --git a/docs/modules/ROOT/examples/tracing/lib/AbstractTrace.java b/docs/modules/ROOT/examples/tracing/lib/AbstractTrace.java new file mode 100644 index 000000000..8c67b12c3 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/lib/AbstractTrace.java @@ -0,0 +1,185 @@ +/* + +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 tracing.lib; + +import java.io.PrintStream; +import org.aspectj.lang.JoinPoint; + + +/** + * This class provides support for printing trace messages into a stream. + * The trace messages consist of the class name, method name (if method) + * and the list of parameter types.<P> + * The class is thread-safe. Different threads may use different output streams + * by simply calling the method initStream(myStream).<P> + * This class should be extended. + * It defines 3 abstract crosscuts for injecting the tracing functionality + * into any constructors and methods of any application classes.<P> + * + * One example of using this class might be + * <PRE> + * import tracing.lib.AbstractTrace; + * aspect TraceMyClasses extends AbstractTrace of eachJVM() { + * pointcut classes(): within(TwoDShape) | within(Circle) | within(Square); + * pointcut constructors(): executions(new(..)); + * pointcut methods(): executions(!abstract * *(..)) + * } + * </PRE> + * (Make sure .../aspectj/examples is in your classpath) + */ +public abstract aspect AbstractTrace { + + /** + * Application classes - left unspecified. + * Subclasses should concretize this crosscut with class names. + */ + abstract pointcut classes(); + /** + * Constructors - left unspecified. + * Subclasses should concretize this crosscut with constructors. + */ + abstract pointcut constructors(); + /** + * Methods - left unspecified. + * Subclasses should concretize this crosscut with method names. + */ + abstract pointcut methods(); + + before(): classes() && constructors() { + doTraceEntry(thisJoinPoint, true); + } + after(): classes() && constructors() { + doTraceExit(thisJoinPoint, true); + } + + before(): classes() && methods() { + doTraceEntry(thisJoinPoint, false); + } + after(): classes() && methods() { + doTraceExit(thisJoinPoint, false); + } + + /* + * From here on, it's an ordinary class implementation. + * The static state is thread-safe by using ThreadLocal variables. + */ + + /** + * This method initializes this thread's trace output stream. + * By default, the output stream is System.err, and it is the same for + * all threads. In multithreaded applications, you may want to define + * different output streams for the different threads. For doing it, + * simply call this method in the beginning of each thread's main loop, + * giving it different output streams. + */ + public void initStream(PrintStream _stream) { + setStream(_stream); + } + + + private ThreadLocal stream = new ThreadLocal() { + protected Object initialValue() { + return System.err; + } + }; + private ThreadLocal callDepth = new ThreadLocal() { + protected Object initialValue() { + return new Integer(0); + } + }; + + private PrintStream getStream() { + return (PrintStream)stream.get(); + } + private void setStream(PrintStream s) { + stream.set(s); + } + private int getCallDepth() { + return ((Integer)(callDepth.get())).intValue(); + } + private void setCallDepth(int n) { + callDepth.set(new Integer(n)); + } + + private void doTraceEntry (JoinPoint jp, boolean isConstructor) { + setCallDepth(getCallDepth() + 1); + printEntering(jp, isConstructor); + } + + private void doTraceExit (JoinPoint jp, boolean isConstructor) { + printExiting(jp, isConstructor); + setCallDepth(getCallDepth() - 1); + } + + private void printEntering (JoinPoint jp, boolean isConstructor) { + printIndent(); + getStream().print("--> "); + getStream().print(jp); + // printParameterTypes(jp); + getStream().println(); + } + + private void printExiting (JoinPoint jp, boolean isConstructor) { + printIndent(); + getStream().print("<-- "); + getStream().print(jp); + // printParameterTypes(jp); + getStream().println(); + } + +// private void printParameterTypes(JoinPoint jp) { +// Class[] ptypes = jp.parameterTypes; + +// getStream().print("("); +// for (int i = 0; i < ptypes.length; i++) { +// getStream().print(ptypes[i].getName()); +// if (i < ptypes.length - 1) getStream().print(", "); +// } +// getStream().print(")"); +// } + + private void printIndent() { + for (int i = 0; i < getCallDepth(); i++) + getStream().print(" "); + } + + /** + * This method is not being used. + * It's being included solely for illustrating how to access and use + * the information in JoinPoint. + * If you want, you can replace the calls to printParameterTypes (above) + * by calls to this method. + */ +// private void printParameters(JoinPoint jp) { +// Class[] ptypes = jp.parameterTypes; +// String[] pnames = jp.parameterNames; +// Object[] params = jp.parameters; + +// getStream().print("("); +// for (int i = 0; i < ptypes.length; i++) { +// getStream().print(ptypes[i].getName() + " " + +// pnames[i] + "=" + +// params[i]); +// if (i < ptypes.length - 1) getStream().print(", "); +// } +// getStream().print(")"); +// } + +} + diff --git a/docs/modules/ROOT/examples/tracing/lib/TraceMyClasses.java b/docs/modules/ROOT/examples/tracing/lib/TraceMyClasses.java new file mode 100644 index 000000000..95c3a859c --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/lib/TraceMyClasses.java @@ -0,0 +1,67 @@ +/* + +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 tracing.lib; + +import tracing.TwoDShape; +import tracing.Circle; +import tracing.Square; +import tracing.ExampleMain; + +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.io.FileNotFoundException; + +aspect TraceMyClasses extends AbstractTrace { + /** + * The application classes + */ + pointcut classes(): within(TwoDShape) || within(Circle) || within(Square); + /** + * The constructors in those classes - but only the ones with 3 + * arguments. + */ + pointcut constructors(): execution(new(double, double, double)); + /** + * This specifies all the message executions. + */ + pointcut methods(): execution(* *(..)); + + /** + * A main function for testing the trace aspect. + */ + public static void main(String[] _args) { + final String[] args = _args; + new Thread() { + public void run() { + TraceMyClasses.aspectOf().initStream(System.err); + ExampleMain.main(args); + } + }.start(); + + new Thread() { + public void run() { + try { + TraceMyClasses.aspectOf().initStream(new PrintStream(new FileOutputStream("AJTRACETEST"))); + } + catch (FileNotFoundException e) {} + ExampleMain.main(args); + } + }.start(); + } +} diff --git a/docs/modules/ROOT/examples/tracing/notrace.lst b/docs/modules/ROOT/examples/tracing/notrace.lst new file mode 100644 index 000000000..ebd820352 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/notrace.lst @@ -0,0 +1,4 @@ +TwoDShape.java +Circle.java +Square.java +ExampleMain.java diff --git a/docs/modules/ROOT/examples/tracing/tracelib.lst b/docs/modules/ROOT/examples/tracing/tracelib.lst new file mode 100644 index 000000000..a9a494d10 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/tracelib.lst @@ -0,0 +1,6 @@ +TwoDShape.java +Circle.java +Square.java +ExampleMain.java +lib/AbstractTrace.java +lib/TraceMyClasses.java diff --git a/docs/modules/ROOT/examples/tracing/tracev1.lst b/docs/modules/ROOT/examples/tracing/tracev1.lst new file mode 100644 index 000000000..35a95c46f --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/tracev1.lst @@ -0,0 +1,6 @@ +TwoDShape.java +Circle.java +Square.java +ExampleMain.java +version1/Trace.java +version1/TraceMyClasses.java diff --git a/docs/modules/ROOT/examples/tracing/tracev2.lst b/docs/modules/ROOT/examples/tracing/tracev2.lst new file mode 100644 index 000000000..e37fe1a11 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/tracev2.lst @@ -0,0 +1,6 @@ +TwoDShape.java +Circle.java +Square.java +ExampleMain.java +version2/Trace.java +version2/TraceMyClasses.java diff --git a/docs/modules/ROOT/examples/tracing/tracev3.lst b/docs/modules/ROOT/examples/tracing/tracev3.lst new file mode 100644 index 000000000..2804f306d --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/tracev3.lst @@ -0,0 +1,6 @@ +TwoDShape.java +Circle.java +Square.java +ExampleMain.java +version3/Trace.java +version3/TraceMyClasses.java diff --git a/docs/modules/ROOT/examples/tracing/version1/Trace.java b/docs/modules/ROOT/examples/tracing/version1/Trace.java new file mode 100644 index 000000000..97b5edb3f --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/version1/Trace.java @@ -0,0 +1,77 @@ +/* +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. +*/ + +package tracing.version1; + +import java.io.PrintStream; + +/** + * + * This class provides some basic functionality for printing trace messages + * into a stream. + * + */ +public class Trace { + /** + * There are 3 trace levels (values of TRACELEVEL): + * 0 - No messages are printed + * 1 - Trace messages are printed, but there is no indentation + * according to the call stack + * 2 - Trace messages are printed, and they are indented + * according to the call stack + */ + public static int TRACELEVEL = 0; + protected static PrintStream stream = null; + protected static int callDepth = 0; + + /** + * Initialization. + */ + public static void initStream(PrintStream s) { + stream = s; + } + + /** + * Prints an "entering" message. It is intended to be called in the + * beginning of the blocks to be traced. + */ + public static void traceEntry(String str) { + if (TRACELEVEL == 0) return; + if (TRACELEVEL == 2) callDepth++; + printEntering(str); + } + + /** + * Prints an "exiting" message. It is intended to be called in the + * end of the blocks to be traced. + */ + public static void traceExit(String str) { + if (TRACELEVEL == 0) return; + printExiting(str); + if (TRACELEVEL == 2) callDepth--; + } + + private static void printEntering(String str) { + printIndent(); + stream.println("--> " + str); + } + + private static void printExiting(String str) { + printIndent(); + stream.println("<-- " + str); + } + + private static void printIndent() { + for (int i = 0; i < callDepth; i++) + stream.print(" "); + } +} diff --git a/docs/modules/ROOT/examples/tracing/version1/TraceMyClasses.java b/docs/modules/ROOT/examples/tracing/version1/TraceMyClasses.java new file mode 100644 index 000000000..736e96413 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/version1/TraceMyClasses.java @@ -0,0 +1,69 @@ +/* +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. +*/ + +package tracing.version1; + +/** + * + * This class connects the tracing functions in the Trace class with + * the constructors and methods in the application classes. + * + */ +import tracing.TwoDShape; +import tracing.Circle; +import tracing.Square; +import tracing.ExampleMain; + +aspect TraceMyClasses { + /** + * Application classes. + */ + pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); + /** + * The constructors in those classes. + */ + pointcut myConstructor(): myClass() && execution(new(..)); + /** + * The methods of those classes. + */ + pointcut myMethod(): myClass() && execution(* *(..)); + + /** + * Prints trace messages before and after executing constructors. + */ + before (): myConstructor() { + Trace.traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myConstructor() { + Trace.traceExit("" + thisJoinPointStaticPart.getSignature()); + } + + /** + * Prints trace messages before and after executing methods. + */ + before (): myMethod() { + Trace.traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myMethod() { + Trace.traceExit("" + thisJoinPointStaticPart.getSignature()); + } + + /** + * A main function for testing the trace aspect. + */ + public static void main(String[] args) { + Trace.TRACELEVEL = 2; + Trace.initStream(System.err); + ExampleMain.main(args); + } +} + diff --git a/docs/modules/ROOT/examples/tracing/version2/Trace.java b/docs/modules/ROOT/examples/tracing/version2/Trace.java new file mode 100644 index 000000000..6c43d60f8 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/version2/Trace.java @@ -0,0 +1,117 @@ +/* +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. +*/ + +package tracing.version2; + +import java.io.PrintStream; + +/** + * + * This class provides support for printing trace messages into a stream. + * Trace messages are printed before and after constructors and methods + * are executed. + * It defines one abstract crosscut for injecting that tracing functionality + * into any application classes. + * To use it, provide a subclass that concretizes the abstract crosscut. + */ +abstract aspect Trace { + + /* + * Functional part + */ + + /** + * There are 3 trace levels (values of TRACELEVEL): + * 0 - No messages are printed + * 1 - Trace messages are printed, but there is no indentation + * according to the call stack + * 2 - Trace messages are printed, and they are indented + * according to the call stack + */ + public static int TRACELEVEL = 2; + protected static PrintStream stream = System.err; + protected static int callDepth = 0; + + /** + * Initialization. + */ + public static void initStream(PrintStream s) { + stream = s; + } + + protected static void traceEntry(String str) { + if (TRACELEVEL == 0) return; + if (TRACELEVEL == 2) callDepth++; + printEntering(str); + } + + protected static void traceExit(String str) { + if (TRACELEVEL == 0) return; + printExiting(str); + if (TRACELEVEL == 2) callDepth--; + } + + private static void printEntering(String str) { + printIndent(); + stream.println("--> " + str); + } + + private static void printExiting(String str) { + printIndent(); + stream.println("<-- " + str); + } + + + private static void printIndent() { + for (int i = 0; i < callDepth; i++) + stream.print(" "); + } + + + /* + * Crosscut part + */ + + /** + * Application classes - left unspecified. + * Subclasses should concretize this pointcut with class names. + */ + abstract pointcut myClass(); + /** + * The constructors in those classes. + */ + pointcut myConstructor(): myClass() && execution(new(..)); + /** + * The methods of those classes. + */ + pointcut myMethod(): myClass() && execution(* *(..)); + + /** + * Prints trace messages before and after executing constructors. + */ + before(): myConstructor() { + traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myConstructor() { + traceExit("" + thisJoinPointStaticPart.getSignature()); + } + + /** + * Prints trace messages before and after executing methods. + */ + before(): myMethod() { + traceEntry("" + thisJoinPointStaticPart.getSignature()); + } + after(): myMethod() { + traceExit("" + thisJoinPointStaticPart.getSignature()); + } +} diff --git a/docs/modules/ROOT/examples/tracing/version2/TraceMyClasses.java b/docs/modules/ROOT/examples/tracing/version2/TraceMyClasses.java new file mode 100644 index 000000000..d9ba21c54 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/version2/TraceMyClasses.java @@ -0,0 +1,37 @@ +/* +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. +*/ + +package tracing.version2; + +import tracing.TwoDShape; +import tracing.Circle; +import tracing.Square; +import tracing.ExampleMain; + +/** + * + * This class concretizes the abstract crosscut in Trace, + * applying the trace facility to these application classes. + * + */ +public aspect TraceMyClasses extends Trace { + pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); + + /** + * A main function for testing the trace aspect. + */ + public static void main(String[] args) { + Trace.TRACELEVEL = 2; + Trace.initStream(System.err); + ExampleMain.main(args); + } +} diff --git a/docs/modules/ROOT/examples/tracing/version3/Trace.java b/docs/modules/ROOT/examples/tracing/version3/Trace.java new file mode 100644 index 000000000..8fc9d8613 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/version3/Trace.java @@ -0,0 +1,123 @@ +/* + +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 tracing.version3; + +import java.io.PrintStream; + +/** + * + * This class provides support for printing trace messages into a stream. + * Trace messages are printed before and after constructors and methods + * are executed. + * The messages are appended with the string representation of the objects + * whose constructors and methods are being traced. + * It defines one abstract pointcut for injecting that tracing functionality + * into any application classes. + * + */ +abstract aspect Trace { + + /* + * Functional part + */ + + /** + * There are 3 trace levels (values of TRACELEVEL): + * 0 - No messages are printed + * 1 - Trace messages are printed, but there is no indentation + * according to the call stack + * 2 - Trace messages are printed, and they are indented + * according to the call stack + */ + public static int TRACELEVEL = 0; + protected static PrintStream stream = null; + protected static int callDepth = 0; + + /** + * Initialization. + */ + public static void initStream(PrintStream s) { + stream = s; + } + + protected static void traceEntry(String str, Object o) { + if (TRACELEVEL == 0) return; + if (TRACELEVEL == 2) callDepth++; + printEntering(str + ": " + o.toString()); + } + + protected static void traceExit(String str, Object o) { + if (TRACELEVEL == 0) return; + printExiting(str + ": " + o.toString()); + if (TRACELEVEL == 2) callDepth--; + } + + private static void printEntering(String str) { + printIndent(); + stream.println("--> " + str); + } + + private static void printExiting(String str) { + printIndent(); + stream.println("<-- " + str); + } + + + private static void printIndent() { + for (int i = 0; i < callDepth; i++) + stream.print(" "); + } + + + /* + * Crosscut part + */ + + /** + * Application classes - left unspecified. + */ + abstract pointcut myClass(Object obj); + /** + * The constructors in those classes. + */ + pointcut myConstructor(Object obj): myClass(obj) && execution(new(..)); + /** + * The methods of those classes. + */ + // toString is called from within our advice, so we shouldn't + // advise its executions. But if toString is overridden, even + // this might not be enough, so we might want + // && !cflow(execution(String toString())) + pointcut myMethod(Object obj): myClass(obj) && + execution(* *(..)) && !execution(String toString()); + + before(Object obj): myConstructor(obj) { + traceEntry("" + thisJoinPointStaticPart.getSignature(), obj); + } + after(Object obj): myConstructor(obj) { + traceExit("" + thisJoinPointStaticPart.getSignature(), obj); + } + + before(Object obj): myMethod(obj) { + traceEntry("" + thisJoinPointStaticPart.getSignature(), obj); + } + after(Object obj): myMethod(obj) { + traceExit("" + thisJoinPointStaticPart.getSignature(), obj); + } +} diff --git a/docs/modules/ROOT/examples/tracing/version3/TraceMyClasses.java b/docs/modules/ROOT/examples/tracing/version3/TraceMyClasses.java new file mode 100644 index 000000000..c986d2615 --- /dev/null +++ b/docs/modules/ROOT/examples/tracing/version3/TraceMyClasses.java @@ -0,0 +1,46 @@ +/* + +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 tracing.version3; + +import tracing.TwoDShape; +import tracing.Circle; +import tracing.Square; +import tracing.ExampleMain; + +/** + * + * This class concretizes the abstract crosscut in Trace, + * applying the trace facility to these application classes. + * + */ +public aspect TraceMyClasses extends Trace { + pointcut myClass(Object obj): + this(obj) && + (within(TwoDShape) || within(Circle) || within(Square)); + + /** + * A main function for testing the trace aspect. + */ + public static void main(String[] args) { + Trace.TRACELEVEL = 2; + Trace.initStream(System.err); + ExampleMain.main(args); + } +} + |