summaryrefslogtreecommitdiffstats
path: root/docs/sandbox/common
diff options
context:
space:
mode:
Diffstat (limited to 'docs/sandbox/common')
-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
14 files changed, 740 insertions, 0 deletions
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