aboutsummaryrefslogtreecommitdiffstats
path: root/docs/sandbox
diff options
context:
space:
mode:
authorwisberg <wisberg>2003-08-06 02:08:40 +0000
committerwisberg <wisberg>2003-08-06 02:08:40 +0000
commita63bc04fb1cb6e8d6d0bc2a509ab9658e3d78c43 (patch)
treecd4e827c60136df7bf9850591b0c64baff549d20 /docs/sandbox
parentb0d37c4b51a344bee94bb7f7cc1ecef1a233e3ab (diff)
downloadaspectj-a63bc04fb1cb6e8d6d0bc2a509ab9658e3d78c43.tar.gz
aspectj-a63bc04fb1cb6e8d6d0bc2a509ab9658e3d78c43.zip
initial checkin of the sandbox.
The basic structure and examples of each type are there, but I have more examples and the ones there are not altogether validated. I'll make a few more changes before emailing dev and users about usage, etc.
Diffstat (limited to 'docs/sandbox')
-rw-r--r--docs/sandbox/api-clients/org/aspectj/samples/JoinPointCollector.java69
-rw-r--r--docs/sandbox/common/caching/Caching.java0
-rw-r--r--docs/sandbox/common/com/company/app/AppException.java11
-rw-r--r--docs/sandbox/common/com/company/app/Main.java40
-rw-r--r--docs/sandbox/common/com/company/lib/Factory.java14
-rw-r--r--docs/sandbox/common/company.lst2
-rw-r--r--docs/sandbox/common/declares/Declares.java140
-rw-r--r--docs/sandbox/common/language/Context.java70
-rw-r--r--docs/sandbox/common/language/ControlFlow.java43
-rw-r--r--docs/sandbox/common/language/Initialization.java95
-rw-r--r--docs/sandbox/common/libraries/PointcutLibraryTest.java95
-rw-r--r--docs/sandbox/common/tracing/Logging.java28
-rw-r--r--docs/sandbox/common/tracing/TraceJoinPoints.java132
-rw-r--r--docs/sandbox/common/tracing/TraceJoinPointsBase.java53
-rw-r--r--docs/sandbox/common/tracing/TraceMyJoinPoints.java17
-rw-r--r--docs/sandbox/inoculated/buildRun.sh20
-rw-r--r--docs/sandbox/inoculated/readme.internal.txt54
-rw-r--r--docs/sandbox/inoculated/readme.txt36
-rw-r--r--docs/sandbox/inoculated/src/BufferTest.java61
-rw-r--r--docs/sandbox/inoculated/src/Injection.java123
-rw-r--r--docs/sandbox/inoculated/src/MainFailure.java74
-rw-r--r--docs/sandbox/inoculated/src/RunTime.java72
-rw-r--r--docs/sandbox/inoculated/src/RuntimeWrites.java145
-rw-r--r--docs/sandbox/inoculated/src/StubReplace.java64
-rw-r--r--docs/sandbox/inoculated/src/buildRun.sh20
-rw-r--r--docs/sandbox/inoculated/src/com/xerox/printing/CompileTime.java69
-rw-r--r--docs/sandbox/inoculated/src/com/xerox/printing/RecordingInput.java44
-rw-r--r--docs/sandbox/inoculated/src/com/xerox/printing/RoundTrip.java77
-rw-r--r--docs/sandbox/readme-sandbox.html192
-rw-r--r--docs/sandbox/sandbox-test.xml141
-rw-r--r--docs/sandbox/scripts/snippets.sh21
-rw-r--r--docs/sandbox/trails/debugging.html58
-rw-r--r--docs/sandbox/trails/j2ee.txt34
33 files changed, 2114 insertions, 0 deletions
diff --git a/docs/sandbox/api-clients/org/aspectj/samples/JoinPointCollector.java b/docs/sandbox/api-clients/org/aspectj/samples/JoinPointCollector.java
new file mode 100644
index 000000000..66f62386f
--- /dev/null
+++ b/docs/sandbox/api-clients/org/aspectj/samples/JoinPointCollector.java
@@ -0,0 +1,69 @@
+/* @author Mik Kersten */
+
+// START-SAMPLE api-ajde-modelWalker Walk model to collect join point information for advised methods and constructors
+package org.aspectj.samples;
+
+import java.util.*;
+import org.aspectj.tools.ajc.Main;
+
+
+import org.aspectj.asm.*;
+
+/**
+ * Collects join point information for all advised methods and constructors.
+ *
+ * @author Mik Kersten
+ */
+public class JoinPointCollector extends Main {
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ String[] newArgs = new String[args.length +1];
+ newArgs[0] = "-emacssym";
+ for (int i = 0; i < args.length; i++) {
+ newArgs[i+1] = args[i];
+ }
+ new JoinPointCollector().runMain(newArgs, false);
+ }
+
+ public void runMain(String[] args, boolean useSystemExit) {
+ super.runMain(args, useSystemExit);
+
+ ModelWalker walker = new ModelWalker() {
+ public void preProcess(StructureNode node) {
+ ProgramElementNode p = (ProgramElementNode)node;
+
+ // first check if it is a method or constructor
+ if (p.getProgramElementKind().equals(ProgramElementNode.Kind.METHOD)) {
+
+ // now check if it is advsied
+ for (Iterator it = p.getRelations().iterator(); it.hasNext(); ) {
+
+ RelationNode relationNode = (RelationNode)it.next();
+ Relation relation = relationNode.getRelation();
+ if (relation == AdviceAssociation.METHOD_RELATION) {
+ System.out.println("method: " + p.toString() + ", advised by: " + relationNode.getChildren());
+ }
+ }
+ }
+
+ // code around the fact that constructor advice relationship is on the type
+ if (p.getProgramElementKind().equals(ProgramElementNode.Kind.CONSTRUCTOR)) {
+ for (Iterator it = ((ProgramElementNode)p.getParent()).getRelations().iterator(); it.hasNext(); ) {
+ RelationNode relationNode = (RelationNode)it.next();
+ Relation relation = relationNode.getRelation();
+ if (relation == AdviceAssociation.CONSTRUCTOR_RELATION) {
+ System.out.println("constructor: " + p.toString() + ", advised by: " + relationNode.getChildren());
+ }
+ }
+ }
+ }
+ };
+
+ StructureModelManager.getDefault().getStructureModel().getRoot().walk(walker);
+ }
+}
+//END-SAMPLE api-ajde-modelWalker
+
diff --git a/docs/sandbox/common/caching/Caching.java b/docs/sandbox/common/caching/Caching.java
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/docs/sandbox/common/caching/Caching.java
diff --git a/docs/sandbox/common/com/company/app/AppException.java b/docs/sandbox/common/com/company/app/AppException.java
new file mode 100644
index 000000000..aa23eeff8
--- /dev/null
+++ b/docs/sandbox/common/com/company/app/AppException.java
@@ -0,0 +1,11 @@
+
+package com.company.app;
+
+public class AppException extends Exception {
+ public AppException() {
+ super();
+ }
+ public AppException(String s) {
+ super(s);
+ }
+} \ No newline at end of file
diff --git a/docs/sandbox/common/com/company/app/Main.java b/docs/sandbox/common/com/company/app/Main.java
new file mode 100644
index 000000000..8d04c0ec9
--- /dev/null
+++ b/docs/sandbox/common/com/company/app/Main.java
@@ -0,0 +1,40 @@
+
+package com.company.app;
+
+import java.util.Arrays;
+import org.aspectj.lang.SoftException;
+
+public class Main implements Runnable {
+ public static void main(String[] argList) {
+ new Main().runMain(argList);
+ }
+
+ String[] input;
+
+ void spawn() {
+ new Thread(this, toString()).start(); // KEEP CE 15 declares-factory
+ }
+
+ public void runMain(String[] argList) {
+ this.input = argList;
+ run();
+ }
+
+ public void run() {
+ String[] input = this.input;
+ String s = ((null == input) || (0 == input.length))
+ ? "[]"
+ : Arrays.asList(input).toString();
+ System.out.println("input: " + s);
+ try {
+ doDangerousThings(); // KEEP CW 30 declares-exceptionSpelunking
+ } catch (AppException e) { // KEEP CW 31 declares-exceptionSpelunking
+ e.printStackTrace(System.err);
+ }
+ }
+
+ private void doDangerousThings() throws AppException { // KEEP CW 38
+
+ }
+
+} \ No newline at end of file
diff --git a/docs/sandbox/common/com/company/lib/Factory.java b/docs/sandbox/common/com/company/lib/Factory.java
new file mode 100644
index 000000000..3abb207c9
--- /dev/null
+++ b/docs/sandbox/common/com/company/lib/Factory.java
@@ -0,0 +1,14 @@
+
+package com.company.lib;
+
+public class Factory {
+
+ public static Thread makeThread(Runnable runnable, String name) {
+ class MyThread extends Thread {
+ MyThread(Runnable runnable, String name) {
+ super(runnable, name);
+ }
+ }
+ return new MyThread(runnable, name);
+ }
+} \ No newline at end of file
diff --git a/docs/sandbox/common/company.lst b/docs/sandbox/common/company.lst
new file mode 100644
index 000000000..64c4786f7
--- /dev/null
+++ b/docs/sandbox/common/company.lst
@@ -0,0 +1,2 @@
+com/company/app/*.java
+com/company/lib/*.java
diff --git a/docs/sandbox/common/declares/Declares.java b/docs/sandbox/common/declares/Declares.java
new file mode 100644
index 000000000..4f763440b
--- /dev/null
+++ b/docs/sandbox/common/declares/Declares.java
@@ -0,0 +1,140 @@
+
+package declares;
+
+import com.company.app.*;
+import java.rmi.RemoteException;
+import java.io.IOException;
+
+/**
+ * @author Wes Isberg
+ */
+aspect A {
+
+ // START-SAMPLE declares-threadFactoryRequired Error when not using Thread factory
+ /** signal error if Thread constructor called outside our Thread factory */
+ declare error : call(Thread+.new(..)) && within(com.company..*)
+ && !withincode(Thread com.company.lib.Factory.makeThread(..)) :
+ "constructing threads prohibited - use Factory.makeThread(..)";
+ // END-SAMPLE declares-threadFactoryRequired
+
+}
+
+/* @author Wes Isberg */
+
+aspect TypeConstraints {
+
+// START-SAMPLE declares-typeConstraints Using declare to enforce type constraints
+protected interface SoughtException {}
+// XXX ajc broken here?
+/**
+ * Require that any SoughtException implementation be
+ * a subclass of Throwable. This picks out the mistake
+ * of declaring SoughtException a parent of something
+ * that is not an exception at all.
+ */
+declare error : staticinitialization(SoughtException+)
+ && ! staticinitialization(SoughtException)
+ && ! staticinitialization(Throwable+) :
+ "all SoughtException must be subclasses of Throwable";
+// END-SAMPLE declares-typeConstraints Using declare to enforce type constraints
+}
+
+// START-SAMPLE declares-exceptionSpelunking Using declare warning to find Exception-related code
+
+/**
+ * List AppException catch blocks and callers as a way
+ * of investigating a possibly-large code base.
+ */
+aspect SeekAppExceptions {
+ pointcut withinScope() : within(com.company..*);
+
+ /**
+ * Find calls to stuff that throws AppException.
+ */
+ declare warning : withinScope() &&
+ (call(* *(..) throws AppException+)
+ || call(new(..) throws AppException+)) :
+ "fyi, another call to something that can throw IOException";
+
+ /**
+ * Find catch clauses handling AppException
+ */
+ declare warning : withinScope() && handler(AppException+):
+ "fyi, code that handles AppException";
+}
+// END-SAMPLE declares-exceptionSpelunking
+
+
+/** @author Jim Hugunin, Wes Isberg */
+
+class RuntimeRemoteException extends RuntimeException {
+ RuntimeRemoteException(RemoteException e) {}
+}
+
+// XXX untested sample declares-softenRemoteException
+
+// START-SAMPLE declares-softenRemoteException
+
+/**
+ * Convert RemoteExceptions to RuntimeRemoteException
+ * and log them. Enable clients that don't handle
+ * RemoteException.
+ */
+aspect HandleRemoteException {
+ /**
+ * Declare RemoteException soft to enable use by clients
+ * that are not declared to handle RemoteException.
+ */
+ declare soft: RemoteException: throwsRemoteException();
+
+ /**
+ * Pick out join points to convert RemoteException to
+ * RuntimeRemoteException.
+ * This implementation picks out
+ * execution of any method declared to throw RemoteException
+ * in our library.
+ */
+ pointcut throwsRemoteException(): within(com.company.lib..*)
+ && execution(* *(..) throws RemoteException+);
+
+ /**
+ * This around advice converts RemoteException to
+ * RuntimeRemoteException at all join points picked out
+ * by <code>throwsRemoteException()</code>.
+ * That means *no* RemoteException will be thrown from
+ * this join point, and thus that none will be converted
+ * by the AspectJ runtime to <code>SoftException</code>.
+ */
+ Object around(): throwsRemoteException() {
+ try {
+ return proceed();
+ } catch (RemoteException re) {
+ re.printStackTrace(System.err);
+ throw new RuntimeRemoteException(re);
+ }
+ }
+}
+//END-SAMPLE declares-softenRemoteException
+
+/*
+ XXX another declare-soft example from Jim:
+
+aspect A {
+
+pointcut check():
+ within(com.foo.framework.persistence.*) &&
+ executions(* *(..));
+
+declare soft: SQLException: check();
+
+after () throwing (SQLException sqlex): check() {
+ if (sql.getSQLCode().equals("SZ001")) {
+ throw new AppRuntimeException("Non-fatal Database error occurred.",
+ "cache refresh failure", sqlex);
+ } else {
+ throw new AppFatalRuntimeException(
+ "Database error occurred - contact support", sqlex);
+ }
+}
+}
+*/
diff --git a/docs/sandbox/common/language/Context.java b/docs/sandbox/common/language/Context.java
new file mode 100644
index 000000000..f0021a28a
--- /dev/null
+++ b/docs/sandbox/common/language/Context.java
@@ -0,0 +1,70 @@
+
+package language;
+
+public class Context {
+ public static void main(String[] argList) {
+ new C().run();
+ }
+}
+
+class C {
+ static int MAX = 2;
+ int i;
+ C() {
+ i = 1;
+ }
+ public void run() {
+ try {
+ more();
+ } catch (MoreError e) {
+ // log but continue
+ System.out.println(e.getMessage());
+ }
+ }
+
+ private void more() {
+ i++;
+ if (i >= MAX) {
+ i = 0;
+ throw new MoreError();
+ }
+ }
+ static class MoreError extends Error {
+ MoreError() {
+ super("was too much!");
+ }
+ }
+}
+
+/** @author Erik Hilsdale, Wes Isberg */
+aspect A {
+
+ // START-SAMPLE language-fieldSetContext Check input and result for a field set.
+ /**
+ * Check input and result for a field set.
+ */
+ void around(int input, C targ) : set(int C.i)
+ && args(input) && target(targ) {
+ String m = "setting C.i=" + targ.i + " to " + input;
+ System.out.println(m);
+ proceed(input, targ);
+ if (targ.i != input) {
+ throw new Error("expected " + input);
+ }
+ }
+ // END-SAMPLE language-fieldSetContext
+
+ // START-SAMPLE language-handlerContext Log exception being handled
+ /**
+ * Log exception being handled
+ */
+ before (C.MoreError e) : handler(C.MoreError)
+ && args(e) && within(C) {
+ System.out.println("handling " + e);
+ }
+ // END-SAMPLE language-handlerContext
+
+ // See Initialization.java for constructor call,
+ // constructor execution, and {pre}-initialization
+
+} \ No newline at end of file
diff --git a/docs/sandbox/common/language/ControlFlow.java b/docs/sandbox/common/language/ControlFlow.java
new file mode 100644
index 000000000..d832259db
--- /dev/null
+++ b/docs/sandbox/common/language/ControlFlow.java
@@ -0,0 +1,43 @@
+
+package language;
+
+public class ControlFlow {
+ public static void main(String[] argList) {
+ Fact.factorial(6);
+ }
+}
+
+class Fact {
+ static int factorial(int i) {
+ if (i < 0) {
+ throw new IllegalArgumentException("negative: " + i);
+ }
+ if (i > 100) {
+ throw new IllegalArgumentException("big: " + i);
+ }
+ return (i == 0 ? 1 : i * factorial(i-1));
+ }
+}
+
+/**
+ * Demonstrate recursive calls.
+ * @author Erik Hilsdale
+ */
+aspect LogFactorial {
+ // START-SAMPLE language-cflowRecursionBasic Pick out latest and original recursive call
+ /** call to factorial, with argument */
+ pointcut f(int i) : call(int Fact.factorial(int)) && args(i);
+
+ /** print most-recent recursive call */
+ before(int i, final int j) : f(i) && cflowbelow(f(j)) {
+ System.err.println(i + "-" + j);
+ }
+
+ /** print initial/topmost recursive call */
+ before(int i, final int j) : f(i)
+ && cflowbelow(cflow(f(j)) && !cflowbelow(f(int))) {
+ System.err.println(i + "@" + j);
+ }
+ // END-SAMPLE language-cflowRecursionBasic
+}
+
diff --git a/docs/sandbox/common/language/Initialization.java b/docs/sandbox/common/language/Initialization.java
new file mode 100644
index 000000000..46d3ec872
--- /dev/null
+++ b/docs/sandbox/common/language/Initialization.java
@@ -0,0 +1,95 @@
+
+package language;
+
+public class Initialization {
+ public static void main(String[] argList) {
+ Thing thing = new Thing();
+ if (12 != thing.counter) {
+ System.err.println("expected 12, got " + thing.counter);
+ }
+ thing = new Thing(20);
+ if (32 != thing.counter) {
+ System.err.println("expected 32, got " + thing.counter);
+ }
+ thing = new AnotherThing();
+ if (2 != thing.counter) {
+ System.err.println("expected 2, got " + thing.counter);
+ }
+ thing = new AnotherThing(20);
+ if (23 != thing.counter) {
+ System.err.println("expected 23, got " + thing.counter);
+ }
+ }
+}
+/** @author Erik Hilsdale, Wes Isberg */
+
+// START-SAMPLE language-initialization Understanding object creation join points
+/*
+ * To work with an object right when it is constructed,
+ * understand the differences between the join points for
+ * constructor call, constructor execution, and initialization.
+ */
+class Thing {
+ int counter;
+ Thing() {
+ this(1);
+ }
+ Thing(int value) {
+ counter = value;
+ }
+}
+
+class AnotherThing extends Thing {
+ AnotherThing() {
+ super();
+ }
+
+ AnotherThing(int i) {
+ super(++i);
+ }
+}
+
+aspect A {
+ /**
+ * After any call to any constructor, fix up the thing.
+ * In AspectJ 1.1, this only affects callers in the input
+ * classes or source files, but not super calls.
+ */
+ after() returning (Thing thing):
+ call(Thing.new(..)) {
+ postInitialize(thing);
+ }
+
+ /**
+ * After executing the int constructor, fix up the thing.
+ * This works regardless of how the constructor was called
+ * (by outside code or by super), but only for the
+ * specified constructors.
+ */
+ after() returning (Thing thing): execution(Thing.new(int)) {
+ thing.counter++;
+ }
+
+ /**
+ * DANGER -- BAD!! Before executing the int constructor,
+ * this uses the target object, which is not constructed.
+ */
+ before (Thing thing): this(thing) && execution(Thing.new(int)) {
+ // thing.counter++; // DANGER!! thing not constructed yet.
+ }
+
+ /**
+ * This advises all Thing constructors in one join point,
+ * even if they call each other with this().
+ */
+ after(Thing thing) returning: this(thing)
+ && initialization(Thing.new(..)) {
+ thing.counter++;
+ }
+
+ protected void postInitialize(Thing thing) {
+ thing.counter += 10;
+ }
+}
+//END-SAMPLE language-initialization
+
diff --git a/docs/sandbox/common/libraries/PointcutLibraryTest.java b/docs/sandbox/common/libraries/PointcutLibraryTest.java
new file mode 100644
index 000000000..e110c7ced
--- /dev/null
+++ b/docs/sandbox/common/libraries/PointcutLibraryTest.java
@@ -0,0 +1,95 @@
+package libraries;
+
+/** @author Wes Isberg */
+public class PointcutLibraryTest {
+ public static void main(String[] a) {
+ new Test().run();
+ }
+}
+
+class Test {
+ public Test() {}
+ public void run(){ prun(); }
+ private void prun() {
+ System.out.println("Test.prun()");
+ }
+}
+
+// START-SAMPLE library-classPointcutLibrary Defining library pointcuts in a class
+/** private default implementation of library */
+class PrivatePointcutLibrary {
+ pointcut adviceCflow() : cflow(adviceexecution());
+ pointcut publicCalls() : call(public * *(..))
+ && !adviceCflow()
+ ;
+}
+
+/** public interface for library */
+class PointcutLibrary extends PrivatePointcutLibrary {
+}
+
+// ---- different clients of the library
+
+/** client by external reference to library */
+aspect ExternalClientOfLibrary {
+ before() : PointcutLibrary.publicCalls() {
+ System.out.println("XCL: "
+ + thisJoinPointStaticPart);
+ }
+}
+
+/** use library by inheriting scope in aspect */
+aspect AEL extends PointcutLibrary {
+ before() : publicCalls() {
+ System.out.println("AEL: "
+ + thisJoinPointStaticPart);
+ }
+}
+
+/** use library by inheriting scope in class */
+class CEL extends PointcutLibrary {
+ static aspect A {
+ before() : publicCalls() {
+ System.out.println("CEL: "
+ + thisJoinPointStaticPart);
+ }
+ }
+}
+
+/** more clients by inheritance */
+aspect CELSubAspect extends CEL {
+ before() : publicCalls() {
+ System.out.println("CSA: "
+ + thisJoinPointStaticPart);
+ }
+}
+
+
+// ---- redefining library pointcuts
+
+//-- affect all clients of PointcutLibrary
+// test: XCL advises Test()
+class VendorPointcutLibrary extends PrivatePointcutLibrary {
+ /** add calls to public constructors */
+ pointcut publicCalls() : PrivatePointcutLibrary.publicCalls()
+ || (call(public new(..)) && !adviceCflow());
+ static aspect A {
+ declare parents:
+ PointcutLibrary extends VendorPointcutLibrary;
+ }
+}
+
+//-- only affect CEL, subtypes, & references thereto
+// test: CSA does not advise call(* println(String))
+// test: CSA advises call(* prun())
+class CPlus extends PointcutLibrary {
+ /** add calls to private methods, remove calls to java..* */
+ pointcut publicCalls() : (PointcutLibrary.publicCalls()
+ || (call(private * *(..)) && !adviceCflow()))
+ && (!(call(* java..*.*(..)) || call(java..*.new(..))));
+ static aspect A {
+ declare parents: CEL extends CPlus;
+ }
+}
+// END-SAMPLE library-classPointcutLibrary
+
diff --git a/docs/sandbox/common/tracing/Logging.java b/docs/sandbox/common/tracing/Logging.java
new file mode 100644
index 000000000..349abb235
--- /dev/null
+++ b/docs/sandbox/common/tracing/Logging.java
@@ -0,0 +1,28 @@
+
+package tracing;
+
+import org.aspectj.lang.Signature;
+
+/**
+ * @author Wes Isberg
+ */
+aspect A {
+ // START-SAMPLE tracing-simpleTiming Record time to execute public methods
+ /** record time to execute my public methods */
+ Object around() : execution(public * com.company..*.* (..)) {
+ long start = System.currentTimeMillis();
+ try {
+ return proceed();
+ } finally {
+ long end = System.currentTimeMillis();
+ recordTime(start, end,
+ thisJoinPointStaticPart.getSignature());
+ }
+ }
+ // implement recordTime...
+ // END-SAMPLE tracing-simpleTiming
+
+ void recordTime(long start, long end, Signature sig) {
+ // to implement...
+ }
+}
diff --git a/docs/sandbox/common/tracing/TraceJoinPoints.java b/docs/sandbox/common/tracing/TraceJoinPoints.java
new file mode 100644
index 000000000..fd42a0fde
--- /dev/null
+++ b/docs/sandbox/common/tracing/TraceJoinPoints.java
@@ -0,0 +1,132 @@
+
+// START-SAMPLE tracing-traceJoinPoints Trace join points executed to log
+/* TraceJoinPoints.java */
+
+package tracing;
+
+import org.aspectj.lang.*;
+import org.aspectj.lang.reflect.*;
+import java.io.*;
+
+/**
+ * Print join points being executed in context to a log.xml file.
+ * To use this, define the abstract pointcuts in a subaspect.
+ * @author Jim Hugunin, Wes Isberg
+ */
+public abstract aspect TraceJoinPoints
+ extends TraceJoinPointsBase {
+
+ // abstract protected pointcut entry();
+
+ PrintStream out;
+ int logs = 0;
+ int depth = 0;
+ boolean terminal = false;
+
+ /**
+ * Emit a message in the log, e.g.,
+ * <pre>TraceJoinPoints tjp = TraceJoinPoints.aspectOf();
+ * if (null != tjp) tjp.message("Hello, World!");</pre>
+ */
+ public void message(String s) {
+ out.println("<message>" + prepareMessage(s) + "</message>");
+ }
+
+ protected void startLog() {
+ makeLogStream();
+ }
+
+ protected void completeLog() {
+ closeLogStream();
+ }
+
+ protected void logEnter(JoinPoint.StaticPart jp) {
+ if (terminal) out.println(">");
+ indent(depth);
+ out.print("<" + jp.getKind());
+ writeSig(jp);
+ writePos(jp);
+
+ depth += 1;
+ terminal = true;
+ }
+
+ protected void logExit(JoinPoint.StaticPart jp) {
+ depth -= 1;
+ if (terminal) {
+ getOut().println("/>");
+ } else {
+ indent(depth);
+ getOut().println("</" + jp.getKind() + ">");
+ }
+ terminal = false;
+ }
+
+ protected PrintStream getOut() {
+ if (null == out) {
+ String m = "not in the control flow of entry()";
+ throw new IllegalStateException(m);
+ }
+ return out;
+ }
+
+ protected void makeLogStream() {
+ try {
+ String name = "log" + logs++ + ".xml";
+ out = new PrintStream(new FileOutputStream(name));
+ } catch (IOException ioe) {
+ out = System.err;
+ }
+ }
+
+ protected void closeLogStream() {
+ PrintStream out = this.out;
+ if (null != out) {
+ out.close();
+ // this.out = null;
+ }
+ }
+
+ /** @return input String formatted for XML */
+ protected String prepareMessage(String s) { // XXX unimplemented
+ return s;
+ }
+
+ void message(String sink, String s) {
+ if (null == sink) {
+ message(s);
+ } else {
+ getOut().println("<message sink=" + quoteXml(sink)
+ + " >" + prepareMessage(s) + "</message>");
+ }
+ }
+
+ void writeSig(JoinPoint.StaticPart jp) {
+ PrintStream out = getOut();
+ out.print(" sig=");
+ out.print(quoteXml(jp.getSignature().toShortString()));
+ }
+
+ void writePos(JoinPoint.StaticPart jp) {
+ SourceLocation loc = jp.getSourceLocation();
+ if (loc == null) return;
+ PrintStream out = getOut();
+
+ out.print(" pos=");
+ out.print(quoteXml(loc.getFileName() +
+ ":" + loc.getLine() +
+ ":" + loc.getColumn()));
+ }
+
+ protected String quoteXml(String s) { // XXX weak
+ return "\"" + s.replace('<', '_').replace('>', '_') + "\"";
+ }
+
+ protected void indent(int i) {
+ PrintStream out = getOut();
+ while (i-- > 0) out.print(" ");
+ }
+}
+// END-SAMPLE tracing-traceJoinPoints
+
+ \ No newline at end of file
diff --git a/docs/sandbox/common/tracing/TraceJoinPointsBase.java b/docs/sandbox/common/tracing/TraceJoinPointsBase.java
new file mode 100644
index 000000000..d06423001
--- /dev/null
+++ b/docs/sandbox/common/tracing/TraceJoinPointsBase.java
@@ -0,0 +1,53 @@
+
+// START-SAMPLE tracing-traceJoinPoints Trace join points executed
+/* TraceJoinPointsBase.java */
+
+package tracing;
+
+import org.aspectj.lang.JoinPoint;
+
+/**
+ * Trace join points being executed in context.
+ * To use this, define the abstract members in a subaspect.
+ * <b>Warning</b>: this does not trace join points that do not
+ * support after advice.
+ * @author Jim Hugunin, Wes Isberg
+ */
+abstract aspect TraceJoinPointsBase {
+ // this line is for AspectJ 1.1
+ // for Aspectj 1.0, use "TraceJoinPointsBase dominates * {"
+ declare precedence : TraceJoinPointsBase, *;
+
+ abstract protected pointcut entry();
+
+ protected pointcut exit(): call(* java..*.*(..));
+
+ final pointcut start(): entry() && !cflowbelow(entry());
+
+ final pointcut trace(): cflow(entry())
+ && !cflowbelow(exit()) && !within(TraceJoinPointsBase+);
+
+ private pointcut supportsAfterAdvice() : !handler(*)
+ && !preinitialization(new(..));
+
+ before(): start() { startLog(); }
+
+ before(): trace() && supportsAfterAdvice(){
+ logEnter(thisJoinPointStaticPart);
+ }
+
+ after(): trace() && supportsAfterAdvice() {
+ logExit(thisJoinPointStaticPart);
+ }
+
+ after(): start() { completeLog(); }
+
+ abstract protected void logEnter(JoinPoint.StaticPart jp);
+ abstract protected void logExit(JoinPoint.StaticPart jp);
+ abstract protected void startLog();
+ abstract protected void completeLog();
+}
+
+// END-SAMPLE tracing-traceJoinPoints
+
+ \ No newline at end of file
diff --git a/docs/sandbox/common/tracing/TraceMyJoinPoints.java b/docs/sandbox/common/tracing/TraceMyJoinPoints.java
new file mode 100644
index 000000000..a5aa686d6
--- /dev/null
+++ b/docs/sandbox/common/tracing/TraceMyJoinPoints.java
@@ -0,0 +1,17 @@
+
+
+// START-SAMPLE tracing-traceJoinPoints Trace to log join points executed by main method
+/* TraceMyJoinPoints.java */
+
+package tracing;
+
+import com.company.app.Main;
+
+/**
+ * Trace all join points in company application.
+ * @author Jim Hugunin, Wes Isberg
+ */
+aspect TraceMyJoinPoints extends TraceJoinPoints {
+ protected pointcut entry() : execution(void Main.runMain(String[]));
+}
+// END-SAMPLE tracing-traceJoinPoints
diff --git a/docs/sandbox/inoculated/buildRun.sh b/docs/sandbox/inoculated/buildRun.sh
new file mode 100644
index 000000000..8f3c283c3
--- /dev/null
+++ b/docs/sandbox/inoculated/buildRun.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+JDKDIR="${JDKDIR:-${JAVA_HOME:-`setjdk.sh`}}"
+AJ_HOME="${AJ_HOME:-`setajhome.sh`}"
+PS="${PS:-;}"
+ajrt=`pathtojava.sh "$AJ_HOME/lib/aspectjrt.jar"`
+mkdir -p ../classes
+
+for i in *.java; do
+ pack=`sed -n '/package/s|.*package *\([^ ][^ ]*\)[ ;].*|\1|p' "$i"`
+ [ -n "$pack" ] && pack="${pack}."
+ rm -rf classes/*
+ cname=$pack`basename $i .java`
+ echo ""
+ echo "########## $cname"
+ $AJ_HOME/bin/ajc -d ../classes -classpath "$ajrt" "$i"
+ && $JDKDIR/bin/java -classpath "../classes${PS}$ajrt" $cname
+done
+
+rm -rf ../classes
diff --git a/docs/sandbox/inoculated/readme.internal.txt b/docs/sandbox/inoculated/readme.internal.txt
new file mode 100644
index 000000000..61d69591a
--- /dev/null
+++ b/docs/sandbox/inoculated/readme.internal.txt
@@ -0,0 +1,54 @@
+// XXX do not distribute
+
+------ contents
+05sd.Isberg40-43,76.pdf # not for distribution
+BufferTest.java
+CompileTime.java
+Injection.java
+MainFailure.java
+RecordingInput.java
+RoundTrip.java
+RunTime.java
+RuntimeWrites.java
+StubReplace.java
+buildRun.sh
+readme.internal.txt # not for distribution
+readme.txt
+
+------ summary of todo's
+- consider moving to packages, combining PrinterStream, etc.
+- use DOS linefeeds - check throughout (also line length)
+- see XXX
+ - assess handling of one style mistake
+ - see if second mistake was actually in article - corrected in code
+
+------ fyi
+- standard of care: show language, not problem
+- formatting: lineation, line width, DOS linefeeds, etc.
+- organization:
+ - code currently compiles/runs one at a time
+ and does not compile all at once b/c of
+ common fixtures (PrinterStream...)
+ - currently packages (com.xerox.printing) in base dir
+
+- Copyright/license: examples, ,but PARC Inc.
+- article code unit flagged with "article page #"
+
+------ style fyi
+- flagging style mistake in StubReplace.java:
+
+ // XXX style mistake in article code
+ //pointcut printerStreamTestCalls() : call(* PrinterStream+.write());
+
+- leaving CompileTime.java use of + in call for factory pointcut:
+
+ call(Point+ SubPoint+.create(..))
+
+ - for static methods where the method name specification
+ involves no * but does reflect a factory naming convention
+ (and not polymorphism)
+ (though not restricting factory methods to being static)
+
+ - for referring to the return value when I want to pick out
+ the type and all subtypes
+
diff --git a/docs/sandbox/inoculated/readme.txt b/docs/sandbox/inoculated/readme.txt
new file mode 100644
index 000000000..04f05e65a
--- /dev/null
+++ b/docs/sandbox/inoculated/readme.txt
@@ -0,0 +1,36 @@
+
+This contains demonstration source code for the article
+"Get Inoculated!" in the May 2002 issue of Software Development
+magazine.
+
+To use it you will need the AspectJ tools available from
+http://eclipse.org/aspectj. We also recommend you download the
+documentation bundle and support for the IDE of your choice.
+
+Each file has a snippet for a section of the article. To find
+one in particular, see the back-references to "article page #":
+
+ CompileTime.java: // article page 40 - warning
+ CompileTime.java: // article page 41 - error
+ RunTime.java: // article page 41 - runtime NPE
+ RuntimeWrites.java: // article page 42 - field writes
+ RecordingInput.java: // article page 42 - recording input
+ MainFailure.java: // article page 42 - recording failures from main
+ BufferTest.java: // article page 43 - input driver
+ Injection.java: // article page 43 - fault injection
+ StubReplace.java: // article page 76 - stubs
+ RoundTrip.java: // article page 76 - round trip
+
+Compile and run as usual:
+
+ > set AJ_HOME=c:\aspectj1.0
+ > set PATH=%AJ_HOME%\bin;%PATH%
+ > ajc -classpath "$AJ_HOME/lib/aspectjrt.jar" {file}
+ > java -classpath ".;$AJ_HOME/lib/aspectjrt.jar" {class}
+
+For email discussions and support, see http://eclipse.org/aspectj.
+
+
+Enjoy!
+
+the AspectJ team
diff --git a/docs/sandbox/inoculated/src/BufferTest.java b/docs/sandbox/inoculated/src/BufferTest.java
new file mode 100644
index 000000000..f2cc479e8
--- /dev/null
+++ b/docs/sandbox/inoculated/src/BufferTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1998-2002 PARC Inc. 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 PARC Inc. makes no
+ * warranty about the software, its performance or its conformity to any
+ * specification.
+ */
+
+import java.util.*;
+import java.io.*;
+
+import org.aspectj.lang.*;
+
+/** @author Wes Isberg */
+public aspect BufferTest {
+
+ // article page 43 - input driver
+ // START-SAMPLE testing-inoculated-proceedVariants Using around for integration testing
+ /**
+ * When PrinterBuffer.capacity(int) is called,
+ * test it with repeatedly with a set of input
+ * (validating the result) and then continue with
+ * the original call.
+ *
+ * This assumes that the capacity method causes no
+ * relevant state changes in the buffer.
+ */
+ int around(int original, PrinterBuffer buffer) :
+ call(int PrinterBuffer.capacity(int)) && args(original) && target(buffer) {
+ int[] input = new int[] { 0, 1, 10, 1000, -1, 4096 };
+ for (int i = 0; i < input.length; i++) {
+ int result = proceed(input[i], buffer); // invoke test
+ validateResult(buffer, input[i], result);
+ }
+ return proceed(original, buffer); // continue with original processing
+ }
+ // END-SAMPLE testing-inoculated-proceedVariants
+
+ void validateResult(PrinterBuffer buffer, int input, int result) {
+ System.err.println("validating input=" + input + " result=" + result
+ + " buffer=" + buffer);
+ }
+
+ public static void main(String[] args) {
+ PrinterBuffer p = new PrinterBuffer();
+ int i = p.capacity(0);
+ System.err.println("main - result " + i);
+ }
+}
+
+class PrinterBuffer {
+ int capacity(int i) {
+ System.err.println("capacity " + i);
+ return i;
+ }
+}
diff --git a/docs/sandbox/inoculated/src/Injection.java b/docs/sandbox/inoculated/src/Injection.java
new file mode 100644
index 000000000..6a857ef7a
--- /dev/null
+++ b/docs/sandbox/inoculated/src/Injection.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1998-2002 PARC Inc. 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 PARC Inc. makes no
+ * warranty about the software, its performance or its conformity to any
+ * specification.
+ */
+
+import java.io.*;
+
+/**
+ * Demonstrate technique of fault-injection
+ * as coordinated by test driver.
+ * @author Wes Isberg
+ */
+aspect InjectingIOException {
+
+ // article page 43 - fault injection
+ // START-SAMPLE testing-inoculated-injectIOException Inject IOException on test driver command
+ /** the test starts when the driver starts executing */
+ pointcut testEntryPoint(TestDriver driver) :
+ target(driver) && execution(* TestDriver.startTest());
+
+ /**
+ * The fault may be injected at the execution of any
+ * (non-static) PrinterStream method that throws an IOException
+ */
+ pointcut testCheckPoint(PrinterStream stream) : target(stream)
+ && execution(public * PrinterStream+.*(..) throws IOException);
+
+ /**
+ * After the method returns normally, query the
+ * test driver to see if we should instead throw
+ * an exception ("inject" the fault).
+ */
+ after (TestDriver driver, PrinterStream stream) returning
+ throws IOException :
+ cflowbelow(testEntryPoint(driver))
+ && testCheckPoint(stream) {
+ IOException e = driver.createException(stream);
+ if (null != e) {
+ System.out.println("InjectingIOException - injecting " + e);
+ throw e;
+ }
+ }
+ /* Comment on the after advice IOException declaration:
+
+ "throws IOException" is a declaration of the advice,
+ not the pointcut.
+
+ Since the advice might throw the injected fault, it
+ must declare that it throws IOException. When advice declares
+ exceptions thrown, the compiler will emit an error if any
+ join point is not also declared to throw an IOException.
+
+ In this case, the testCheckPoint pointcut only picks out
+ methods that throw IOException, so the compile will not
+ signal any errors.
+ */
+ // END-SAMPLE testing-inoculated-injectIOException
+}
+
+/** this runs the test case */
+public class Injection {
+ /** Run three print jobs, two as a test and one normally */
+ public static void main(String[] args) throws Exception {
+ Runnable r = new Runnable() {
+ public void run() {
+ try { new TestDriver().startTest(); }
+ catch (IOException e) {
+ System.err.println("got expected injected error " + e.getMessage());
+ }
+ }
+ };
+
+ System.out.println("Injection.main() - starting separate test thread");
+ Thread t = new Thread(r);
+ t.start();
+
+ System.out.println("Injection.main() - running test in this thread");
+ r.run();
+ t.join();
+
+ System.out.println("Injection.main() - running job normally, not by TestDriver");
+ new PrintJob().runPrintJob();
+ }
+}
+
+/** handle starting of test and determining whether to inject failure */
+class TestDriver {
+
+ /** start a new test */
+ public void startTest() throws IOException {
+ new PrintJob().runPrintJob();
+ }
+
+ /** this implementation always injects a failure */
+ public IOException createException(PrinterStream p) {
+ return new IOException(""+p);
+ }
+}
+
+//--------------------------------------- target classes
+
+class PrintJob {
+ /** this job writes to the printer stream */
+ void runPrintJob() throws IOException {
+ new PrinterStream().write();
+ }
+}
+
+class PrinterStream {
+ /** this printer stream writes without exception */
+ public void write() throws IOException {
+ System.err.println("PrinterStream.write() - not throwing exception");
+ }
+}
+
diff --git a/docs/sandbox/inoculated/src/MainFailure.java b/docs/sandbox/inoculated/src/MainFailure.java
new file mode 100644
index 000000000..6d5a62a35
--- /dev/null
+++ b/docs/sandbox/inoculated/src/MainFailure.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1998-2002 PARC Inc. 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 PARC Inc. makes no
+ * warranty about the software, its performance or its conformity to any
+ * specification.
+ */
+
+import java.util.*;
+import java.io.*;
+import org.aspectj.lang.*;
+
+/** @author Wes Isberg */
+
+public aspect MainFailure {
+
+ public static void main (String[] args) { TargetClass.main(args); }
+
+ pointcut main(String[] args) :
+ args(args) && execution(public static void main(String[]));
+
+ // article page 42 - recording failures from main
+ // START-SAMPLE testing-inoculated-failureCapture Log failures
+ /** log after failure, but do not affect exception */
+ after(String[] args) throwing (Throwable t) : main(args) {
+ logFailureCase(args, t, thisJoinPoint);
+ }
+ // END-SAMPLE testing-inoculated-failureCapture
+
+ // alternate to swallow exception
+// /** log after failure and swallow exception */
+// Object around() : main(String[]) {
+// try {
+// return proceed();
+// } catch (Error e) { // ignore
+// logFailureCase(args, t, thisJoinPoint);
+// // can log here instead
+// }
+// return null;
+// }
+
+ public static void logFailureCase(String[] args, Throwable t, Object jp) {
+ System.err.println("failure case: args " + Arrays.asList(args));
+ }
+}
+
+class TargetClass {
+ static Thread thread;
+ /** will throw error if exactly one argument */
+ public static void main (String[] args) {
+ // make sure to do at least one failure
+ if (thread == null) {
+ Runnable r = new Runnable() {
+ public void run() {
+ main(new String[] {"throwError" });
+ }
+ };
+ thread = new Thread(r);
+ thread.start();
+ }
+ if (1 == args.length) {
+ throw new Error("hello");
+ }
+ try { thread.join(); }
+ catch (InterruptedException ie) { }
+ }
+}
+
+
diff --git a/docs/sandbox/inoculated/src/RunTime.java b/docs/sandbox/inoculated/src/RunTime.java
new file mode 100644
index 000000000..e3e93e9d0
--- /dev/null
+++ b/docs/sandbox/inoculated/src/RunTime.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1998-2002 PARC Inc. 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 PARC Inc. makes no
+ * warranty about the software, its performance or its conformity to any
+ * specification.
+ */
+
+import java.util.*;
+import java.awt.Point;
+
+import org.aspectj.lang.JoinPoint;
+
+public class RunTime {
+ public static void main(String[] a) {
+ AnotherPoint.create();
+ SubPoint.create();
+ }
+}
+
+/** @author Wes Isberg */
+aspect FactoryValidation {
+
+ // START-SAMPLE declares-inoculated-prohibitNonprivateConstructors Error to have accessible sub-Point constructors
+ /** We make it an error for any Point subclasses to have non-private constructors */
+ declare error : execution(!private Point+.new(..))
+ && !within(java*..*) :
+ "non-private Point subclass constructor";
+ // END-SAMPLE declares-inoculated-prohibitNonprivateConstructors
+
+ // article page 41 - runtime NPE
+ // START-SAMPLE testing-inoculated-runtimeErrorWhenNullReturnedFromFactory Throw Error when factory returns null
+ /** Throw Error if a factory method for creating a Point returns null */
+ after () returning (Point p) :
+ call(Point+ SubPoint+.create(..)) {
+ if (null == p) {
+ String err = "Null Point constructed when this ("
+ + thisJoinPoint.getThis()
+ + ") called target ("
+ + thisJoinPoint.getTarget()
+ + ") at join point ("
+ + thisJoinPoint.getSignature()
+ + ") from source location ("
+ + thisJoinPoint.getSourceLocation()
+ + ") with args ("
+ + Arrays.asList(thisJoinPoint.getArgs())
+ + ")";
+ throw new Error(err);
+ }
+ }
+ // END-SAMPLE testing-inoculated-runtimeErrorWhenNullReturnedFromFactory
+}
+
+class SubPoint extends Point {
+ public static SubPoint create() { return null; } // will cause Error
+ private SubPoint(){}
+}
+
+class AnotherPoint extends Point {
+ public static Point create() { return new Point(); }
+
+ // to see that default constructor is picked out by declare error
+ // comment out this constructor
+ private AnotherPoint(){}
+}
+
+
diff --git a/docs/sandbox/inoculated/src/RuntimeWrites.java b/docs/sandbox/inoculated/src/RuntimeWrites.java
new file mode 100644
index 000000000..0f49247cb
--- /dev/null
+++ b/docs/sandbox/inoculated/src/RuntimeWrites.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1998-2002 PARC Inc. 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 PARC Inc. makes no
+ * warranty about the software, its performance or its conformity to any
+ * specification.
+ */
+
+import org.aspectj.lang.*;
+
+/** test cases for controlling field writes */
+public class RuntimeWrites {
+
+ public static void main(String[] args) {
+ System.err.println("---- setup: valid write");
+ final SubPrinterStream me = new SubPrinterStream();
+
+ System.err.println("---- setup: invalid write, outside initialization - nonstatic");
+ me.setOne(1);
+
+ System.err.println("---- setup: invalid write, outside initialization - static");
+ me.one = 0;
+
+ System.err.println("---- setup: invalid write, caller is not same as target");
+ PrinterStream other = new PrinterStream(me);
+ }
+}
+
+
+/**
+ * Control field writes.
+ * This implementation restricts writes to the same object during initialization.
+ * This is like having field values be final, except that
+ * they may be set set outside the constructor.
+ * @author Wes Isberg
+ */
+aspect ControlFieldWrites {
+ public static boolean throwError;
+
+ // article page 42 - field writes
+
+ // START-SAMPLE testing-inoculated-permitWritesDuringConstruction Constructor execution
+ /** execution of any constructor for PrinterStream */
+ pointcut init() : execution(PrinterStream+.new(..));
+ // END-SAMPLE testing-inoculated-permitWritesDuringConstruction
+
+ // START-SAMPLE testing-inoculated-prohibitWritesExceptWhenConstructing Prohibit field writes after construction
+ /** any write to a non-static field in PrinterStream itself */
+ pointcut fieldWrites() : set(!static * PrinterStream.*);
+
+
+ /**
+ * Handle any situation where fields are written
+ * outside of the control flow of initialization
+ */
+ before() : fieldWrites() && !cflow(init()) {
+ handle("field set outside of init", thisJoinPointStaticPart);
+ }
+ // END-SAMPLE testing-inoculated-prohibitWritesExceptWhenConstructing
+
+ // START-SAMPLE testing-inoculated-prohibitWritesByOthers Prohibit field writes by other instances
+ /**
+ * Handle any situation where fields are written
+ * by another object.
+ */
+ before(Object caller, PrinterStream targ) : this(caller)
+ && target(targ) && fieldWrites() {
+ if (caller != targ) {
+ String err = "variation 1: caller (" + caller
+ + ") setting fields in targ (" + targ + ")";
+ handle(err, thisJoinPointStaticPart);
+ }
+ }
+ // END-SAMPLE testing-inoculated-prohibitWritesByOthers
+
+ //---- variations to pick out subclasses as well
+ // START-SAMPLE testing-inoculated-prohibitWritesEvenBySubclasses Prohibit writes by subclasses
+ /** any write to a non-static field in PrinterStream or any subclasses */
+ //pointcut fieldWrites() : set(!static * PrinterStream+.*);
+
+ /** execution of any constructor for PrinterStream or any subclasses */
+ //pointcut init() : execution(PrinterStream+.new(..));
+ // END-SAMPLE testing-inoculated-prohibitWritesEvenBySubclasses
+
+ //---- variation to pick out static callers as well
+ // START-SAMPLE testing-inoculated-prohibitWritesEvenByStaticOthers Prohibit writes by other instances and static methods
+ /**
+ * Handle any situation where fields are written
+ * other than by the same object.
+ */
+ before(PrinterStream targ) : target(targ) && fieldWrites() {
+ Object caller = thisJoinPoint.getThis();
+ if (targ != caller) {
+ String err = "variation 2: caller (" + caller
+ + ") setting fields in targ (" + targ + ")";
+ handle(err, thisJoinPointStaticPart);
+ }
+ }
+ // END-SAMPLE testing-inoculated-prohibitWritesEvenByStaticOthers
+
+ //-------------- utility method
+ void handle(String error, JoinPoint.StaticPart jpsp) {
+ error += " - " + jpsp;
+ if (throwError) {
+ throw new Error(error);
+ } else {
+ System.err.println(error);
+ }
+ }
+}
+
+
+class PrinterStream {
+ int one;
+ private int another;
+
+ PrinterStream() { setOne(1); }
+
+ PrinterStream(PrinterStream other) {
+ other.another = 3;
+ }
+
+ public void setOne(int i) {
+ one = i;
+ }
+}
+
+class SubPrinterStream extends PrinterStream {
+ private int two;
+
+ SubPrinterStream() {
+ setOne(2);
+ setTwo();
+ }
+
+ public void setTwo() {
+ two = 2;
+ }
+}
+
diff --git a/docs/sandbox/inoculated/src/StubReplace.java b/docs/sandbox/inoculated/src/StubReplace.java
new file mode 100644
index 000000000..56bda0367
--- /dev/null
+++ b/docs/sandbox/inoculated/src/StubReplace.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1998-2002 PARC Inc. 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 PARC Inc. makes no
+ * warranty about the software, its performance or its conformity to any
+ * specification.
+ */
+
+public class StubReplace {
+ public static void main(String[] args) {
+ new PrintJob().run();
+ }
+}
+
+/** @author Wes Isberg */
+aspect Stubs {
+
+ // article page 76 - stubs
+
+ // START-SAMPLE testing-inoculated-replaceWithProxy Replace object with proxy on constructiono
+ /**
+ * Replace all PrintStream with our StubStream
+ * by replacing the call to any constructor of
+ * PrinterStream or any subclasses.
+ */
+ PrinterStream around () : within(PrintJob)
+ && call (PrinterStream+.new(..)) && !call (StubStream+.new(..)) {
+ return new StubStream(thisJoinPoint.getArgs());
+ }
+ // END-SAMPLE testing-inoculated-replaceWithProxy
+
+ // START-SAMPLE testing-inoculated-adviseProxyCallsOnly Advise calls to the proxy object only
+ pointcut stubWrite() : printerStreamTestCalls() && target(StubStream);
+
+ pointcut printerStreamTestCalls() : call(* PrinterStream.write());
+
+ before() : stubWrite() {
+ System.err.println("picking out stubWrite" );
+ }
+ // END-SAMPLE testing-inoculated-adviseProxyCallsOnly
+}
+
+class PrinterStream {
+ public void write() {}
+}
+
+class StubStream extends PrinterStream {
+ public StubStream(Object[] args) {}
+}
+
+class PrintJob {
+ public void run() {
+ PrinterStream p = new PrinterStream();
+ System.err.println("not PrinterStream: " + p);
+ System.err.println("now trying call...");
+ p.write();
+ }
+}
+
diff --git a/docs/sandbox/inoculated/src/buildRun.sh b/docs/sandbox/inoculated/src/buildRun.sh
new file mode 100644
index 000000000..8f3c283c3
--- /dev/null
+++ b/docs/sandbox/inoculated/src/buildRun.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+JDKDIR="${JDKDIR:-${JAVA_HOME:-`setjdk.sh`}}"
+AJ_HOME="${AJ_HOME:-`setajhome.sh`}"
+PS="${PS:-;}"
+ajrt=`pathtojava.sh "$AJ_HOME/lib/aspectjrt.jar"`
+mkdir -p ../classes
+
+for i in *.java; do
+ pack=`sed -n '/package/s|.*package *\([^ ][^ ]*\)[ ;].*|\1|p' "$i"`
+ [ -n "$pack" ] && pack="${pack}."
+ rm -rf classes/*
+ cname=$pack`basename $i .java`
+ echo ""
+ echo "########## $cname"
+ $AJ_HOME/bin/ajc -d ../classes -classpath "$ajrt" "$i"
+ && $JDKDIR/bin/java -classpath "../classes${PS}$ajrt" $cname
+done
+
+rm -rf ../classes
diff --git a/docs/sandbox/inoculated/src/com/xerox/printing/CompileTime.java b/docs/sandbox/inoculated/src/com/xerox/printing/CompileTime.java
new file mode 100644
index 000000000..f7af344e0
--- /dev/null
+++ b/docs/sandbox/inoculated/src/com/xerox/printing/CompileTime.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1998-2002 PARC Inc. 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 PARC Inc. makes no
+ * warranty about the software, its performance or its conformity to any
+ * specification.
+ */
+
+package com.xerox.printing;
+
+import java.awt.Point;
+import java.io.IOException;
+
+class ClassOne {
+ int i = 1 ; // 20 expect warning
+}
+
+class ClassError {
+ int i = 1 ; // 24 expect warning
+}
+
+class PrinterStream {}
+
+class SubPrinterStream extends PrinterStream {
+ public void delegate() {
+ try {
+ throw new IOException("");
+ } catch (IOException e) {} // 33 expect error
+ }
+}
+
+class SubPoint extends Point {
+ Point create() { return new Point(); } // no error
+ Point another() { return new Point(); } // 39 expect error
+}
+
+/** @author Wes Isberg */
+aspect CompileTime {
+
+ // article page 40 - warning
+ // START-SAMPLE declares-inoculated-nonSetterWrites Warn when setting non-public field
+ /** warn if setting non-public field outside a setter */
+ declare warning :
+ within(com.xerox.printing..*)
+ && set(!public * *) && !withincode(* set*(..))
+ : "writing field outside setter" ;
+ // END-SAMPLE declares-inoculated-nonSetterWrites
+
+ // article page 41 - error
+ // START-SAMPLE declares-inoculated-validExceptionHandlingMethod Error when subclass method handles exception
+ declare error : handler(IOException+)
+ && withincode(* PrinterStream+.delegate(..))
+ : "do not handle IOException in this method";
+ // END-SAMPLE declares-inoculated-validExceptionHandlingMethod
+
+ // START-SAMPLE declares-inoculated-validPointConstruction Error when factory not used
+ declare error : !withincode(Point+ SubPoint+.create(..))
+ && within(com.xerox..*)
+ && call(Point+.new(..))
+ : "use SubPoint.create() to create Point";
+ // END-SAMPLE declares-inoculated-validPointConstruction
+}
+
+
diff --git a/docs/sandbox/inoculated/src/com/xerox/printing/RecordingInput.java b/docs/sandbox/inoculated/src/com/xerox/printing/RecordingInput.java
new file mode 100644
index 000000000..aab1d2076
--- /dev/null
+++ b/docs/sandbox/inoculated/src/com/xerox/printing/RecordingInput.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1998-2002 PARC Inc. 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 PARC Inc. makes no
+ * warranty about the software, its performance or its conformity to any
+ * specification.
+ */
+
+package com.xerox.printing;
+
+class PrinterBuffer {
+ public int capacity(int i) { return i; }
+}
+
+public aspect RecordingInput {
+
+ // @author Wes Isberg
+ // article page 42 - recording input
+ pointcut capacityCall (int i) :
+ within(com.xerox..*) && args(i)
+ && call(public * PrinterBuffer.capacity(int)) ;
+ // XXX style error - + not needed
+ // call(public * PrinterBuffer+.capacity(int))
+
+ before (int i) : capacityCall(i) {
+ log.print("<capacityCall tjp=\"" + thisJoinPoint
+ + "\" input=\"" + i + "\"/>");
+ }
+
+ Log log = new Log();
+ class Log {
+ void print(String s) { System.out.println(s); }
+ }
+ public static void main(String[] args) {
+ PrinterBuffer p = new PrinterBuffer();
+ p.capacity(1);
+ p.capacity(2);
+ }
+}
diff --git a/docs/sandbox/inoculated/src/com/xerox/printing/RoundTrip.java b/docs/sandbox/inoculated/src/com/xerox/printing/RoundTrip.java
new file mode 100644
index 000000000..4aeb0892b
--- /dev/null
+++ b/docs/sandbox/inoculated/src/com/xerox/printing/RoundTrip.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1998-2002 PARC Inc. 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 PARC Inc. makes no
+ * warranty about the software, its performance or its conformity to any
+ * specification.
+ */
+
+package com.xerox.printing;
+
+public class RoundTrip {
+ public static void main(String[] args) {
+ PrinterStream p = testing();
+ System.err.println(" got "+ p.number);
+ }
+ static PrinterStream testing() { return new PrinterStream(1); }
+
+}
+
+/** @author Wes Isberg */
+aspect VerifyPrinterStreamIntegrity {
+ // article page 76 - round trip
+ // START-SAMPLE testing-inoculated-roundTrip Round-trip integration testing
+ /**
+ * After returning a PrinterStream from any call in our
+ * packages, verify it by doing a round-trip between
+ * PrinterStream and BufferedPrinterStream.
+ * This uses a round-trip as a way to verify the
+ * integrity of PrinterStream, but one could also use
+ * a self-test (built-in or otherwise) coded specifically
+ * for validating the object (without changing state).
+ */
+ after () returning (PrinterStream stream) :
+ call (PrinterStream+ com.xerox.printing..*(..))
+ && !call (PrinterStream PrinterStream.make(BufferedPrinterStream)) {
+ BufferedPrinterStream bufferStream = new BufferedPrinterStream(stream);
+ PrinterStream newStream = PrinterStream.make(bufferStream);
+ if (!stream.equals(newStream)) {
+ throw new Error("round-trip failed for " + stream);
+ } else {
+ System.err.println("round-trip passed for " + stream);
+ }
+ }
+ // END-SAMPLE testing-inoculated-roundTrip
+}
+
+class BufferedPrinterStream {
+ int num;
+ BufferedPrinterStream(int i) { this.num = i; }
+ BufferedPrinterStream(PrinterStream p) { this(p.number); }
+}
+
+class PrinterStream {
+ int number;
+ static PrinterStream make(BufferedPrinterStream p) {
+ return new PrinterStream(p.num);
+ }
+ PrinterStream(int i) { this.number = i; }
+ void write() {}
+ // XXX hashcode
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (null == o) {
+ return false;
+ } else if (o instanceof PrinterStream) {
+ return ((PrinterStream)o).number == number;
+ } else {
+ return o.equals(this);
+ }
+ }
+}
diff --git a/docs/sandbox/readme-sandbox.html b/docs/sandbox/readme-sandbox.html
new file mode 100644
index 000000000..d8c874399
--- /dev/null
+++ b/docs/sandbox/readme-sandbox.html
@@ -0,0 +1,192 @@
+<html>
+<title>README - AspectJ sandbox for sample code and instructions</title>
+<body>
+<h2>README - AspectJ sandbox for sample code and instructions</h2>
+This directory is a place to put some scraps that might end up in the
+AspectJ documentation or on the web site:
+<ul>
+<li>sample code for AspectJ programs,
+ </li>
+<li>sample code for extensions to AspectJ tools and API's,
+ </li>
+<li>sample scripts for invoking AspectJ tools, and
+ </li>
+<li>documentation trails showing how to do given tasks
+ using AspectJ, AJDT, or various IDE or deployment
+ environments.
+ </li>
+</ul>
+In the past, we found it tedious to keep and verify
+sample code used in documentation because it involves
+copying the code from the documentation
+into a form that can be tested (or vice versa).
+Further, there are a lot of tips and sample code
+contributed on the mailing lists, but they can be
+difficult to find when needed. This aims to be
+a place where such contributions can be gathered,
+kept in good order, and extracted for use in docs,
+without too much overhead.
+
+<p>
+Code in the sandbox is kept in a running state;
+it's tested by running the harness on the sandbox
+test suite file
+ <a href="sandbox-test.xml">sandbox-test.xml</a>.
+To extract the code for documentation, we use a tool
+that recognizes
+a sample within a source file if it has comments
+signalling the start and end of the sample.
+Keeping sample code in sync with the documentation
+and with the test suite specification only takes
+a bit of care with formatting and comments.
+The rest of this document tells how.
+
+<p><code>org.aspectj.internal.tools.build.SampleGatherer</code>
+(in the build module) extracts samples
+of the following form from any "source" file
+(currently source, html, text, and shell scripts):
+
+<pre>
+ ... some text, possibly including @author tags
+ {comment} START-<skipParse/>SAMPLE [anchorName] [anchor title] {end-comment}
+ ... sample code ...
+ {comment} END-<skipParse/>SAMPLE [anchorName] {end-comment}
+ ... more text ...
+</pre>
+
+<p>
+Each sample extracted consists of the code and associated
+attributes: the source location, the anchor name
+and title, any text flagged with XXX,
+and the author pulled from the closest-preceding
+<code>@author</code> tag. (If there is no author,
+the AspectJ team is presumed.)
+
+<code>SampleGatherer</code> can render the collected
+samples back out to HTML (todo: or DocBook) for
+inclusion in the FAQ, the online
+samples, the Programming Guide, etc.
+An editor might reorder or annotate the samples
+but the code should not be edited
+to avoid introducing mistakes.
+
+<p>To help keep the sample code in sync with the docs...
+<ul>
+<li>Use comments in the sample to explain the code,
+ rather than describing it in the documentation.
+ </li>
+<li>Preformat samples to be included without modification
+ in docs:
+ <ul>
+ <li>Use 4 spaces rather than a tab for each indent.
+ </li>
+ <li>Keep lines short - 60 characters or less.
+ </li>
+ <li>Code snippets taken out of context of the defining type
+ can be indented only once in the source code,
+ even though they might normally be indented more.
+ </li>
+ <li>Indent advice pointcuts once beyond the block code:
+<pre>
+ before() : call(!public * com.company.library..*.*(String,..))
+ && within(Runnable+) { // indent once more than code
+ // code here
+ }
+</pre>
+ </li>
+ </ul>
+ </li>
+</ul>
+
+<p>
+Where you put the sample code depends on how big it is
+and what it's for. Any code intended as an extension to
+the AspectJ tools goes in the <a href="api-clients">api-clients/</a>
+directory.
+Most code will instead be samples of AspectJ programs.
+Subdirectories of this directory should be the base directories of
+different source sets.
+
+The <a href="common">common/</a> directory should work for
+most code snippets, but standalone, self-consistent code
+belongs in its own directory,
+as do sets pertaining to particular publications or tutorials.
+An example of this are the sources for the "Test Inoculated"
+article in the <a href="inoculated">inoculated/</a> directory.
+
+<p>
+When adding code, add a corresponding test case in
+<a href="sandbox-test.xml">sandbox-test.xml</a>.
+This file has the same format as other harness test suites;
+for more information,
+see <a href="../../tests/readme-writing-compiler-tests.html">
+../../tests/readme-writing-compiler-tests.html</a>.
+
+The test suite should run and pass after new code is added
+and before samples are extracted.
+
+<p>To keep sample code in sync with the tests:
+<ul>
+<li>The test title should be prefixed with the anchor name and
+ have any suffixes necessary for clarity and to make sure
+ there are unique titles for each test.
+ E.g., for a sample with the anchor
+ "<code>language-initialization</code>",
+ <pre>
+ &lt;ajc-test
+ dir="common"
+ title="language-initialization constructor-call example">
+ ...
+ &lt;/ajc-test>
+ </pre>
+ (Someday we'll be able to compare the test titles with
+ the anchor names to verify that the titles contain
+ all the anchor names.)
+ <p></li>
+<li>Avoid mixing compiler-error tests with ordinary code,
+ so others can reuse the target code in their samples.
+ Most of the sample code should compile.
+ <p></li>
+<li>Any code that is supposed to trigger a compiler error
+ should be tested by verifying that the error message
+ is produced, checking either or both of the line number
+ and the message text. E.g.,
+<pre>
+ &lt;compile files="declares/Declares.java, {others}"
+ &lt;message kind="error" line="15" text="Factory"/>
+ &lt;/compile>
+</pre>
+ Where a test case refers to a line number,
+ we have to keep the expected message
+ and the target code in sync.
+ You can help with this by adding a comment in the target code
+ so people editing the code know not to fix
+ or move the code. E.g.,
+<pre>
+ void spawn() {
+ new Thread(this, toString()).start(); // KEEP CE 15 declares-factory
+ }
+</pre>
+ Any good comment could work, but here are some optional conventions:
+ <p>
+ <ul>
+ <li>Use "CE" or "CW" for compiler error or warning, respectively.
+ <p></li>
+ <li>Specify the line number, if one is expected.
+ <p></li>
+ <li>Specify the affected test title(s) or sample code anchor label
+ to make it easier to find the test that will break if the
+ code is modified. (The editor can also run the tests
+ to find any broken ones.)
+ <p>
+ </li>
+ </ul>
+ </li>
+</ul>
+<p>
+Happy coding!
+<hr>
+
+</body>
+</html>
+
diff --git a/docs/sandbox/sandbox-test.xml b/docs/sandbox/sandbox-test.xml
new file mode 100644
index 000000000..494fa5672
--- /dev/null
+++ b/docs/sandbox/sandbox-test.xml
@@ -0,0 +1,141 @@
+<!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd">
+<!-- ../ path when running, ../../ when editing? -->
+
+
+<!-- Notes
+
+ - test titles should be prefixed with the corresponding
+ sample anchor/label, and suffixed to be unique.
+
+ - take care to keep error line numbers in sync with sources
+
+ TODO
+ - verify that RunTime and RuntimeWrites throw Errors
+ - harness bug: errStreamIsError not false when not forked; fork?
+ - check output/error stream against expected
+ - verify api-clients, using access to aspectjtools.jar...
+
+-->
+<suite>
+
+ <ajc-test dir="common" title="declares-* default declares">
+ <compile
+ argfiles="company.lst"
+ files="declares/Declares.java">
+ <message
+ kind="error"
+ file="Main.java"
+ line="15"
+ text="Factory"/>
+ <message
+ kind="warning"
+ file="Main.java"
+ line="30"
+ text="throw"/>
+ <message
+ kind="warning"
+ file="Main.java"
+ line="31"
+ text="handles"/>
+ </compile>
+ </ajc-test>
+
+ <ajc-test dir="common"
+ title="ensure company compiles and runs without aspects">
+ <compile argfiles="company.lst"/>
+ <run class="com.company.app.Main"/>
+ </ajc-test>
+
+ <ajc-test dir="common" title="language-initialization">
+ <compile files="language/Initialization.java"/>
+ <run class="language.Initialization"
+ errStreamIsError="true"/>
+ </ajc-test>
+
+ <ajc-test dir="common" title="language-*Context">
+ <compile files="language/Context.java"/>
+ <run class="language.Context" />
+ </ajc-test>
+
+ <ajc-test dir="common" title="language-cflowRecursionBasic">
+ <compile files="language/ControlFlow.java"/>
+ <run class="language.ControlFlow"/>
+ </ajc-test>
+
+
+ <ajc-test dir="common" title="tracing-simpleLogging">
+ <compile
+ argfiles="company.lst"
+ files="tracing/Logging.java"/>
+ <run class="com.company.app.Main"/>
+ </ajc-test>
+
+ <ajc-test dir="common" title="tracing-traceJoinPoints">
+ <compile
+ argfiles="company.lst"
+ files="tracing/TraceJoinPoints.java,
+ tracing/TraceJoinPointsBase.java,
+ tracing/TraceMyJoinPoints.java"/>
+ <run class="com.company.app.Main"/>
+ </ajc-test>
+
+ <ajc-test dir="inoculated/src" title="declares-inoculated-*">
+ <compile files="com/xerox/printing/CompileTime.java">
+ <message line="20" kind="warning"/>
+ <message line="24" kind="warning"/>
+ <message line="33" kind="error"/>
+ <message line="39" kind="error"/>
+ </compile>
+ </ajc-test>
+
+ <ajc-test dir="inoculated/src" title="testing-inoculated-roundTrip">
+ <compile files="com/xerox/printing/RoundTrip.java"/>
+ <run class="com.xerox.printing.RoundTrip"/>
+ </ajc-test>
+
+ <ajc-test dir="inoculated/src" title="testing-inoculated-roundTrip">
+ <compile files="BufferTest.java"/>
+ <run class="BufferTest"/>
+ </ajc-test>
+
+ <ajc-test dir="inoculated/src" title="testing-inoculated-roundTrip">
+ <compile files="BufferTest.java"/>
+ <run class="BufferTest"/>
+ </ajc-test>
+
+ <ajc-test dir="inoculated/src" title="testing-inoculated-injectIOException">
+ <compile files="Injection.java"/>
+ <run class="Injection"/>
+ </ajc-test>
+
+ <ajc-test dir="inoculated/src" title="testing-inoculated-injectIOException">
+ <compile files="MainFailure.java"/>
+ <run class="MainFailure"/>
+ </ajc-test>
+
+ <ajc-test dir="inoculated/src" title="testing-inoculated-runtimeFactories">
+ <compile files="RunTime.java"/>
+ </ajc-test>
+
+ <ajc-test dir="inoculated/src" title="testing-inoculated-runtimeWrites">
+ <compile files="RuntimeWrites.java"/>
+ </ajc-test>
+
+ <ajc-test dir="inoculated/src" title="testing-inoculated-{proxies}">
+ <compile files="StubReplace.java"/>
+ <run class="StubReplace"/>
+ </ajc-test>
+
+</suite>
+
+<!--
+ TODO XXX verify api-clients using aspectjtools.jar?
+
+ <ajc-test dir="api-clients" title="api-ajde-modelWalker">
+ <compile files="org/aspectj/samples/JoinPointCollector.java"
+ classpath="../aj-build/dist/tools/lib/aspectjtools.jar;"/>
+ <run ... />
+ </ajc-test>
+
+-->
+ \ No newline at end of file
diff --git a/docs/sandbox/scripts/snippets.sh b/docs/sandbox/scripts/snippets.sh
new file mode 100644
index 000000000..76c60ca94
--- /dev/null
+++ b/docs/sandbox/scripts/snippets.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+# shell script snippets for AspectJ
+
+
+# @author Wes Isberg
+# START-SAMPLE scripts-weaveLibraries
+ASPECTJ_HOME="${ASPECTJ_HOME:-c:/aspectj-1.1.0}"
+ajc="$ASPECTJ_HOME/bin/ajc"
+
+# make system.jar by weaving aspects.jar into lib.jar and app.jar
+$ajc -classpath "$ASPECTJ_HOME/lib/aspectjrt.jar" \
+ -aspectpath aspects.jar" \
+ -injars "app.jar;lib.jar" \
+ -outjar system.jar
+
+# XXX copy any resources from input jars to output jars
+
+# run it
+java -classpath "aspects.jar;system.jar" com.company.app.Main
+
+# END-SAMPLE scripts-weaveLibraries
diff --git a/docs/sandbox/trails/debugging.html b/docs/sandbox/trails/debugging.html
new file mode 100644
index 000000000..3c6bbcfab
--- /dev/null
+++ b/docs/sandbox/trails/debugging.html
@@ -0,0 +1,58 @@
+<html>
+<title>Debugging AspectJ Programs
+</title>
+<body>
+<h2>Debugging AspectJ Programs
+</h2>
+<!-- @author Wes Isberg -->
+<!-- START-SAMPLE trails-debugging-aspectj10 -->
+<h3>Debugging AspectJ 1.0 Programs
+</h3>
+The AspectJ 1.0 compiler produces .class files that have the
+normal source file attribute and line information as well
+as the information specified by JSR-045 required to debug
+.class files composed of multiple source files.
+This permits the compiler to inline advice code
+into the .class files of the target classes;
+the advice code in the target class can have source
+attributes that point back to the aspect file.
+
+<p>
+Support for JSR-45 varies.
+At the time of this writing, Sun's VM supports it,
+but not some others, which means that the Sun VM
+must be used as the runtime VM.
+
+Because the VM does all the work of associating the
+source line with the code being debugged,
+debuggers should be able to operate normally with
+AspectJ 1.0 source files even if they weren't written
+with that in mind, if they use the correct
+API's to the debugger. Unfortunately, some debuggers
+take shortcuts based on the default case of one file
+per class in order to avoid having the VM calculate
+the file suffix or package prefix. These debuggers
+do not support JSR-45 and thus AspectJ.
+
+<!-- END-SAMPLE trails-debugging-aspectj10 -->
+
+<!-- @author Wes Isberg -->
+<!-- START-SAMPLE trails-debugging-aspectj11 -->
+<h3>Debugging AspectJ 1.1 Programs
+</h3>
+The AspectJ 1.1 compiler usually implements advice as
+call-backs to the aspect, which means that most
+AspectJ programs do not require JSR-45 support in
+order to be debugged. However, it does do a limited
+amount of advice inlining; to avoid this, use the
+<code>-XnoInline</code> flag.
+<p>
+Because inlined advice can be more efficient, we
+plan to support JSR-45 as soon as feasible.
+This will require upgrading the BCEL library we
+use to pass around the correct source attributes.
+
+<!-- END-SAMPLE trails-debugging-aspectj11 -->
+
+</body>
+</html>
diff --git a/docs/sandbox/trails/j2ee.txt b/docs/sandbox/trails/j2ee.txt
new file mode 100644
index 000000000..8685939b1
--- /dev/null
+++ b/docs/sandbox/trails/j2ee.txt
@@ -0,0 +1,34 @@
+
+This contains short notes on using AspectJ with various J2EE
+servers and deployment tools.
+
+// @author Wes Isberg
+
+-------- START-SAMPLE j2ee-servlets-generally Using AspectJ in servlets
+AspectJ programs work if run in the same namespace and with aspectjrt.jar.
+Servlet runners and J2EE web containers should run AspectJ programs fine
+if the classes and required libraries are deployed as usual. The runtime
+classes and shared aspects might need to be deployed into a common
+directory to work properly across applications, especially in containers
+that use different class loaders for different applications or use
+different class-loading schemes.
+
+As with any shared library, if more than one application is using AspectJ,
+then the aspectjrt.jar should be deployed where it will be loaded by a
+common classloader.
+
+Aspects which are used by two applications might be independent or shared.
+Independent aspects can be deployed in each application-specific archive.
+Aspects might be shared explicitly or implicitly, as when they are stateful
+or staticly bound (however indirectly) to common classes. When in doubt,
+it is safest to deploy the aspects in the common namespace.
+
+-------- END-SAMPLE j2ee-servlets-generally
+
+-------- START-SAMPLE j2ee-servlets-tomcat4 Running AspectJ servlets in Tomcat 4.x
+To deploy an AspectJ program as a Tomcat servlet,
+place aspectjrt.jar in shared/lib and deploy the required libraries
+and AspectJ-compiled servlet classes as usual.
+
+-------- END-SAMPLE j2ee-servlets-tomcat4
+