aboutsummaryrefslogtreecommitdiffstats
path: root/docs/dist/doc/examples/tracing/lib/AbstractTrace.java
blob: 8c67b12c3179757d23a878faf28f2881f0811dd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*

Copyright (c) Xerox Corporation 1998-2002.  All rights reserved.

Use and copying of this software and preparation of derivative works based
upon this software are permitted.  Any distribution of this software or
derivative works must comply with all applicable United States export control
laws.

This software is made available AS IS, and Xerox Corporation makes no warranty
about the software, its performance or its conformity to any specification.

|<---            this code is formatted to fit into 80 columns             --->|
|<---            this code is formatted to fit into 80 columns             --->|
|<---            this code is formatted to fit into 80 columns             --->|

*/

package tracing.lib;

import java.io.PrintStream;
import org.aspectj.lang.JoinPoint;


/**
 * This class provides support for printing trace messages into a stream. 
 * The trace messages consist of the class name, method name (if method)
 * and the list of parameter types.<P>
 * The class is thread-safe. Different threads may use different output streams
 * by simply calling the method initStream(myStream).<P>
 * This class should be extended.
 * It defines 3 abstract crosscuts for injecting the tracing functionality 
 * into any constructors and methods of any application classes.<P>
 *
 * One example of using this class might be
 * <PRE>
 * import tracing.lib.AbstractTrace;
 * aspect TraceMyClasses extends AbstractTrace of eachJVM() {
 *   pointcut classes(): within(TwoDShape) | within(Circle) | within(Square);
 *   pointcut constructors(): executions(new(..));
 *   pointcut methods(): executions(!abstract * *(..))
 * }
 * </PRE>
 * (Make sure .../aspectj/examples is in your classpath)
 */
public abstract aspect AbstractTrace {

    /**
     * Application classes - left unspecified.
     * Subclasses should concretize this crosscut with class names.
     */
    abstract pointcut classes();
    /**
     * Constructors - left unspecified.
     * Subclasses should concretize this crosscut with constructors.
     */
    abstract pointcut constructors();
    /**
     * Methods - left unspecified.
     * Subclasses should concretize this crosscut with method names.
     */
    abstract pointcut methods();

    before(): classes() && constructors() {   
	doTraceEntry(thisJoinPoint, true);
    }
    after(): classes() && constructors() {   
	doTraceExit(thisJoinPoint,  true);
    }

    before(): classes() && methods() {
	doTraceEntry(thisJoinPoint, false);
    }
    after(): classes() && methods() {
	doTraceExit(thisJoinPoint,  false);
    }

    /*
     * From here on, it's an ordinary class implementation.
     * The static state is thread-safe by using ThreadLocal variables.
     */

    /**
     * This method initializes this thread's trace output stream.
     * By default, the output stream is System.err, and it is the same for
     * all threads. In multithreaded applications, you may want to define
     * different output streams for the different threads. For doing it,
     * simply call this method in the beginning of each thread's main loop,
     * giving it different output streams.
     */
    public void initStream(PrintStream _stream) {
	setStream(_stream);
    }


    private ThreadLocal stream = new ThreadLocal() {
	    protected Object initialValue() {
		return System.err;
	    }
	};
    private ThreadLocal callDepth = new ThreadLocal() {
	    protected Object initialValue() {
		return new Integer(0);
	    }
	};

    private PrintStream getStream() { 
	return (PrintStream)stream.get(); 
    }
    private void setStream(PrintStream s) { 
	stream.set(s); 
    }
    private int  getCallDepth() { 
	return ((Integer)(callDepth.get())).intValue();
    }
    private void setCallDepth(int n) { 
	callDepth.set(new Integer(n)); 
    }

    private void doTraceEntry (JoinPoint jp, boolean isConstructor) {
	setCallDepth(getCallDepth() + 1);
	printEntering(jp, isConstructor);
    }

    private void doTraceExit (JoinPoint jp,  boolean isConstructor) {
	printExiting(jp, isConstructor);
	setCallDepth(getCallDepth() - 1);
    }

    private void printEntering (JoinPoint jp, boolean isConstructor) {
	printIndent();
	getStream().print("--> ");
	getStream().print(jp);
	//	printParameterTypes(jp);
	getStream().println();
    }

    private void printExiting (JoinPoint jp, boolean isConstructor) {
	printIndent();
	getStream().print("<--  ");
	getStream().print(jp);
	//	printParameterTypes(jp);
	getStream().println();
    }

//      private void printParameterTypes(JoinPoint jp) {
//  	Class[]  ptypes = jp.parameterTypes;

//  	getStream().print("(");
//  	for (int i = 0; i < ptypes.length; i++) {
//  	    getStream().print(ptypes[i].getName());
//  	    if (i < ptypes.length - 1) getStream().print(", ");
//  	}
//  	getStream().print(")");
//      }

    private void printIndent() {
	for (int i = 0; i < getCallDepth(); i++)
	    getStream().print(" ");
    }

    /**
     * This method is not being used.
     * It's being included solely for illustrating how to access and use
     * the information in JoinPoint.
     * If you want, you can replace the calls to printParameterTypes (above)
     * by calls to this method.
     */
//      private void printParameters(JoinPoint jp) {
//  	Class[]  ptypes = jp.parameterTypes;
//  	String[] pnames = jp.parameterNames;
//  	Object[] params = jp.parameters;

//  	getStream().print("(");
//  	for (int i = 0; i < ptypes.length; i++) {
//  	    getStream().print(ptypes[i].getName() + " " +
//  			      pnames[i]           + "=" +
//  			      params[i]);
//  	    if (i < ptypes.length - 1) getStream().print(", ");
//  	}
//  	getStream().print(")");
//      }

}