001: /*
002: * <copyright>
003: *
004: * Copyright 2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.util;
028:
029: import java.util.HashSet;
030:
031: /**
032: * A set of utilities for tracking method invocations by stack.
033: * Typically used to reduce repetitive warnings by only emitting
034: * one complaint per caller.
035: *
036: * @note These are typically expensive operations, so do not use lightly.
037: */
038:
039: public abstract class CallerTracker {
040: protected CallerTracker() {
041: }
042:
043: protected final HashSet set = new HashSet(11);
044:
045: public boolean isNew() {
046: return (checkFrame(new Throwable()) != null);
047: }
048:
049: public Object isNewFrame() {
050: return checkFrame(new Throwable());
051: }
052:
053: protected Object checkFrame(Throwable t) {
054: Object key = getKey(t);
055: if (key == null)
056: return null;
057: synchronized (set) {
058: if (set.contains(key)) {
059: return null;
060: } else {
061: set.add(key);
062: return key;
063: }
064: }
065: }
066:
067: /** compute a set object from the throwable's stack.
068: * May return null if it cannot compute a useful key.
069: **/
070: protected abstract Object getKey(Throwable t);
071:
072: /** Alias for getShallowTracker(1) */
073: public static CallerTracker getShallowTracker() {
074: return new ShallowTracker(1);
075: }
076:
077: /** Construct a CallerTracker which discriminates between contexts based only
078: * on the stack frame the specified number of frames above the frame which invokes
079: * #isNew().<p>
080: * A typical use would be to track callers of a particular method foo(). In the
081: * class foo, define a static member which has a ShallowTracker(1) and then
082: * modify the foo() method to emit a log message IFF tracker.isNew() is true.
083: **/
084: public static CallerTracker getShallowTracker(int i) {
085: return new ShallowTracker(i);
086: }
087:
088: protected static class ShallowTracker extends CallerTracker {
089: private int depth;
090:
091: protected ShallowTracker(int n) {
092: depth = n + 1;
093: }
094:
095: public Object getKey(Throwable t) {
096: StackTraceElement[] stack = t.getStackTrace();
097: return (stack.length > depth) ? stack[depth] : null;
098: }
099: }
100:
101: /** Construct a CallerTracker which discriminates between contexts based only
102: * on stack frame selected by the predicate. The predicate is invoked on the
103: * class names of frames of the stack (innermost first, skipping the first one that is a CallerTracker
104: * frame), until the predicate returns true. The whole selected frame is the one used as the key.
105: */
106: public static CallerTracker getPredicateTracker(UnaryPredicate p) {
107: return new PredicateTracker(p);
108: }
109:
110: protected static class PredicateTracker extends CallerTracker {
111: private UnaryPredicate p;
112:
113: protected PredicateTracker(UnaryPredicate p) {
114: this .p = p;
115: }
116:
117: public Object getKey(Throwable t) {
118: StackTraceElement[] stack = t.getStackTrace();
119: for (int i = 1; i < stack.length; i++) {
120: if (p.execute(stack[i].getClassName()))
121: return stack[i];
122: }
123: return null;
124: }
125: }
126:
127: /*
128: private static CallerTracker tracker = getShallowTracker();
129:
130: public static void main(String[] args) {
131: foo();
132: foo();
133: a();
134: b();
135: c();
136: foo();
137: }
138: private static void a() {
139: foo();
140: foo();
141: }
142: private static void b() {
143: foo();
144: foo();
145: }
146: private static void c() {
147: a();
148: b();
149: foo();
150: }
151:
152: private static void foo() {
153: Object f = tracker.isNewFrame();
154: if (f != null) {
155: System.out.println("New call to foo() from "+f);
156: }
157: }
158: */
159: }
|