KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > debugger > jpda > ui > CurrentThreadAnnotationListener


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Micro//S ystems, Inc. Portions Copyright 1997-2006 Sun
17  * Micro//S ystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.debugger.jpda.ui;
20
21 import com.sun.jdi.AbsentInformationException;
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import javax.swing.SwingUtilities JavaDoc;
27
28 import org.netbeans.api.debugger.*;
29 import org.netbeans.api.debugger.jpda.CallStackFrame;
30 import org.netbeans.api.debugger.jpda.JPDADebugger;
31 import org.netbeans.api.debugger.jpda.JPDAThread;
32 import org.netbeans.api.debugger.jpda.LineBreakpoint;
33 import org.openide.ErrorManager;
34
35 import org.openide.util.RequestProcessor;
36
37
38 /**
39  * Listens on {@link org.netbeans.api.debugger.DebuggerManager} on
40  * {@link JPDADebugger#PROP_CURRENT_THREAD}
41  * property and annotates current line and call stack for
42  * {@link org.netbeans.api.debugger.jpda.JPDAThread}s in NetBeans editor.
43  *
44  * @author Jan Jancura
45  */

46 public class CurrentThreadAnnotationListener extends DebuggerManagerAdapter {
47
48     // annotation for current line
49
private transient Object JavaDoc currentPC;
50     private transient Object JavaDoc currentPCLock = new Object JavaDoc();
51     private transient boolean currentPCSet = false;
52     private JPDAThread currentThread;
53     private JPDADebugger currentDebugger;
54
55
56
57     public String JavaDoc[] getProperties () {
58         return new String JavaDoc[] {DebuggerManager.PROP_CURRENT_ENGINE};
59     }
60
61     /**
62      * Listens JPDADebuggerEngineImpl and DebuggerManager.
63      */

64     public void propertyChange (PropertyChangeEvent JavaDoc e) {
65         if (e.getPropertyName () == DebuggerManager.PROP_CURRENT_ENGINE) {
66             updateCurrentDebugger ();
67             updateCurrentThread ();
68             annotate ();
69         } else
70         if (e.getPropertyName () == JPDADebugger.PROP_CURRENT_THREAD) {
71             updateCurrentThread ();
72             annotate ();
73         } else
74         if (e.getPropertyName () == JPDADebugger.PROP_CURRENT_CALL_STACK_FRAME) {
75             updateCurrentThread ();
76             annotate ();
77         } else
78         if (e.getPropertyName () == JPDADebugger.PROP_STATE) {
79             annotate ();
80         }
81     }
82
83
84     // helper methods ..........................................................
85

86     private void updateCurrentDebugger () {
87         JPDADebugger newDebugger = getCurrentDebugger ();
88         if (currentDebugger == newDebugger) return;
89         if (currentDebugger != null)
90             currentDebugger.removePropertyChangeListener (this);
91         if (newDebugger != null)
92             newDebugger.addPropertyChangeListener (this);
93         currentDebugger = newDebugger;
94     }
95     
96     private static JPDADebugger getCurrentDebugger () {
97         DebuggerEngine currentEngine = DebuggerManager.
98             getDebuggerManager ().getCurrentEngine ();
99         if (currentEngine == null) return null;
100         return (JPDADebugger) currentEngine.lookupFirst
101             (null, JPDADebugger.class);
102     }
103
104     private void updateCurrentThread () {
105         // get current thread
106
if (currentDebugger != null)
107             currentThread = currentDebugger.getCurrentThread ();
108         else
109             currentThread = null;
110     }
111
112     /**
113      * Annotates current thread or removes annotations.
114      */

115     private void annotate () {
116         // 1) no current thread => remove annotations
117
if ( (currentThread == null) ||
118              (currentDebugger.getState () != JPDADebugger.STATE_STOPPED) ) {
119             synchronized (currentPCLock) {
120                 currentPCSet = false; // The annotation is goint to be removed
121
}
122             removeAnnotations ();
123             return;
124         }
125         
126         // 2) get call stack & Line
127
CallStackFrame[] stack;
128         try {
129             stack = currentThread.getCallStack ();
130         } catch (AbsentInformationException ex) {
131             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
132             synchronized (currentPCLock) {
133                 currentPCSet = false; // The annotation is goint to be removed
134
}
135             removeAnnotations ();
136             return;
137         }
138         final CallStackFrame csf = currentDebugger.getCurrentCallStackFrame ();
139         Session currentSession = null;
140         Session[] sessions = DebuggerManager.getDebuggerManager().getSessions();
141         for (int i = 0; i < sessions.length; i++) {
142             if (sessions[i].lookupFirst(null, JPDADebugger.class) == currentDebugger) {
143                 currentSession = sessions[i];
144                 break;
145             }
146         }
147         final String JavaDoc language = currentSession == null ?
148             null : currentSession.getCurrentLanguage ();
149         DebuggerEngine currentEngine = (currentSession == null) ?
150             null : currentSession.getCurrentEngine();
151         final SourcePath sourcePath = (currentEngine == null) ?
152             null : (SourcePath) currentEngine.lookupFirst(null, SourcePath.class);
153
154         // 3) annotate current line & stack
155
synchronized (currentPCLock) {
156             currentPCSet = true; // The annotation is goint to be set
157
}
158         SwingUtilities.invokeLater (new Runnable JavaDoc () {
159             public void run () {
160                 // show current line
161
synchronized (currentPCLock) {
162                     if (currentPC != null)
163                         EditorContextBridge.removeAnnotation (currentPC);
164                     if (csf != null && sourcePath != null && currentThread != null) {
165
166                         sourcePath.showSource (csf, language);
167                         // annotate current line
168
currentPC = sourcePath.annotate (currentThread, language);
169                     }
170                 }
171             }
172         });
173         annotateCallStack (stack, sourcePath);
174     }
175
176
177     // do not need synchronization, called in a 1-way RP
178
private HashMap JavaDoc stackAnnotations = new HashMap JavaDoc ();
179     
180     private RequestProcessor rp = new RequestProcessor("Debugger Thread Annotation Refresher");
181
182     // currently waiting / running refresh task
183
// there is at most one
184
private RequestProcessor.Task taskRemove;
185     private RequestProcessor.Task taskAnnotate;
186     private CallStackFrame[] stackToAnnotate;
187     private SourcePath sourcePathToAnnotate;
188
189     private void removeAnnotations () {
190         synchronized (rp) {
191             if (taskRemove == null) {
192                 taskRemove = rp.create (new Runnable JavaDoc () {
193                     public void run () {
194                         synchronized (currentPCLock) {
195                             if (currentPCSet) {
196                                 // Keep the set PC
197
return ;
198                             }
199                             if (currentPC != null)
200                                 EditorContextBridge.removeAnnotation (currentPC);
201                             currentPC = null;
202                         }
203                         Iterator JavaDoc i = stackAnnotations.values ().iterator ();
204                         while (i.hasNext ())
205                             EditorContextBridge.removeAnnotation (i.next ());
206                         stackAnnotations.clear ();
207                     }
208                 });
209             }
210         }
211         taskRemove.schedule(500);
212     }
213
214     private void annotateCallStack (
215         CallStackFrame[] stack,
216         SourcePath sourcePath
217     ) {
218         synchronized (rp) {
219             if (taskRemove != null) {
220                 taskRemove.cancel();
221             }
222             this.stackToAnnotate = stack;
223             this.sourcePathToAnnotate = sourcePath;
224             if (taskAnnotate == null) {
225                 taskAnnotate = rp.post (new Runnable JavaDoc () {
226                     public void run () {
227                         CallStackFrame[] stack;
228                         SourcePath sourcePath;
229                         synchronized (rp) {
230                             if (stackToAnnotate == null) {
231                                 return ; // Nothing to do
232
}
233                             stack = stackToAnnotate;
234                             sourcePath = sourcePathToAnnotate;
235                             stackToAnnotate = null;
236                             sourcePathToAnnotate = null;
237                         }
238                         HashMap JavaDoc newAnnotations = new HashMap JavaDoc ();
239                         int i, k = stack.length;
240                         for (i = 1; i < k; i++) {
241
242                             // 1) check Line
243
String JavaDoc language = stack[i].getDefaultStratum();
244                             String JavaDoc resourceName = EditorContextBridge.getRelativePath
245                                 (stack[i], language);
246                             int lineNumber = stack[i].getLineNumber (language);
247                             String JavaDoc line = resourceName + lineNumber;
248
249                             // 2) line already annotated?
250
if (newAnnotations.containsKey (line))
251                                 continue;
252
253                             // 3) line has been annotated?
254
Object JavaDoc da = stackAnnotations.remove (line);
255                             if (da == null) {
256                                 // line has not been annotated -> create annotation
257
da = sourcePath.annotate (stack[i], language);
258                             }
259
260                             // 4) add new line to hashMap
261
if (da != null)
262                                 newAnnotations.put (line, da);
263                         } // for
264

265                         // delete old anotations
266
Iterator JavaDoc iter = stackAnnotations.values ().iterator ();
267                         while (iter.hasNext ())
268                             EditorContextBridge.removeAnnotation (
269                                 iter.next ()
270                             );
271                         stackAnnotations = newAnnotations;
272                     }
273                 });
274             }
275         }
276         taskAnnotate.schedule(500);
277     }
278 }
279
Popular Tags