001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.debugger.importd2;
043:
044: import java.util.*;
045: import javax.swing.text.StyledDocument;
046:
047: import org.openide.TopManager;
048: import org.openide.cookies.EditorCookie;
049: import org.openide.debugger.*;
050: import org.openide.text.Line;
051: import org.openide.text.NbDocument;
052: import org.openide.util.MapFormat;
053: import org.openide.util.NbBundle;
054:
055: import org.netbeans.modules.debugger.*;
056: import org.netbeans.modules.debugger.support.DebuggerAnnotation;
057: import org.netbeans.modules.debugger.support.SecondaryDebuggerSupport;
058: import org.netbeans.modules.debugger.support.StateSupport;
059: import org.netbeans.modules.debugger.support.util.Utils;
060: import org.netbeans.modules.debugger.support.util.ValidatorImpl;
061:
062: /**
063: * Example of Debugger Implementation. It "debugs" import statements
064: * in Java files (so it does not need compiled .class files). Step
065: * Into on "import java.awt.Button" opens .java file for Button and
066: * puts current line to the first line of it.
067: *
068: * @author Jan Jancura
069: */
070: public class ImportDebugger extends SecondaryDebuggerSupport {
071:
072: // static ..................................................................
073:
074: /** generated Serialized Version UID */
075: static final long serialVersionUID = 84466455228078708L;
076: /** bundle to obtain text information from */
077: private static ResourceBundle bundle;
078:
079: static String getLocString(String s) {
080: if (bundle == null)
081: bundle = NbBundle.getBundle(ImportDebugger.class);
082: return bundle.getString(s);
083: }
084:
085: /** debugger State constant. */
086: public static final State STATE_STOPPED = new StateSupport(
087: StateSupport.PAUSE | StateSupport.STEP_OVER
088: | StateSupport.STEP_INTO | StateSupport.STEP_OUT);
089: /** debugger State constant. */
090: public static final State STATE_RUNNING = new StateSupport(
091: StateSupport.PAUSE);
092:
093: static DebuggerAnnotation.CurrentPC currentLineAnnotation = new DebuggerAnnotation.CurrentPC();
094:
095: // variables ...............................................................
096:
097: transient private ValidatorImpl validator;
098:
099: // init ....................................................................
100:
101: public ImportDebugger() {
102: validator = new ValidatorImpl();
103: }
104:
105: // Debugger implementation .................................................
106:
107: /** Starts the debugger. The method stops the current debugging (if any)
108: * and takes information from the provided info (containing the class to start and
109: * arguments to pass it and name of class to stop debugging in) and starts
110: * new debugging session.
111: *
112: * @param info debugger info about class to start
113: * @exception DebuggerException if an error occures during the start of the debugger
114: */
115: public void startDebugger(DebuggerInfo info)
116: throws DebuggerException {
117: boolean stopOnMain = info.getStopClassName() != null;
118:
119: super .startDebugger(info);
120: setState(Debugger.DEBUGGER_RUNNING);
121: String stopClassName = info.getClassName();
122: Line l = Utils.getLine(stopClassName, 1);
123: getStack(info).push(l);
124: getIsOnStack().add(l.getDataObject());
125:
126: // stop on main
127: stopOnMain = true;
128: if (stopOnMain) {
129: setState(DEBUGGER_STOPPED);
130: setCurrentLine(l);
131: refreshWatches();
132: } else
133: go();
134: }
135:
136: /**
137: * Finishes debugger.
138: */
139: public void finishDebugger() throws DebuggerException {
140: super .finishDebugger();
141: }
142:
143: /**
144: * Trace into.
145: */
146: synchronized public void traceInto() throws DebuggerException {
147: setState(DEBUGGER_RUNNING);
148: Line l = step();
149: if (l == null) {
150: finishDebugger();
151: refreshWatches();
152: return;
153: }
154: setCurrentLine(l);
155: setState(DEBUGGER_STOPPED);
156: setLastAction(ACTION_TRACE_INTO);
157: refreshWatches();
158: }
159:
160: /**
161: * Trace over.
162: */
163: synchronized public void traceOver() throws DebuggerException {
164: setState(DEBUGGER_RUNNING);
165: Stack stack = getStack();
166: int d = stack.size();
167: Line l = null;
168: do {
169: l = step();
170: if (l == null) {
171: finishDebugger();
172: refreshWatches();
173: return;
174: }
175: } while (stack.size() > d);
176: setCurrentLine(l);
177: setState(DEBUGGER_STOPPED);
178: setLastAction(ACTION_TRACE_OVER);
179: refreshWatches();
180: }
181:
182: /**
183: * Go.
184: */
185: synchronized public void go() throws DebuggerException {
186: setLastAction(ACTION_CONTINUE);
187: setState(DEBUGGER_RUNNING);
188:
189: Line l = null;
190: do {
191: l = step();
192: } while (l != null);
193: finishDebugger();
194: refreshWatches();
195: }
196:
197: /**
198: * Step out.
199: */
200: synchronized public void stepOut() throws DebuggerException {
201: setLastAction(ACTION_STEP_OUT);
202: setState(DEBUGGER_RUNNING);
203:
204: Stack stack = getStack();
205: int d = stack.size() - 1;
206: Line l = null;
207: do {
208: l = step();
209: if (l == null) {
210: finishDebugger();
211: refreshWatches();
212: return;
213: }
214: } while (stack.size() > d);
215: setCurrentLine(l);
216: setState(DEBUGGER_STOPPED);
217: setLastAction(ACTION_TRACE_INTO);
218: refreshWatches();
219: }
220:
221: /**
222: * Jumps to the next call site (towards the top of the call-stack).
223: */
224: public void goToCalledMethod() {
225: }
226:
227: /**
228: * Jumps to the previous call site (towards the bottom of the call-stack).
229: */
230: public void goToCallingMethod() {
231: }
232:
233: /**
234: * Jumps to a given line.
235: *
236: * @param l a line jump to
237: */
238: public void runToCursor(Line l) {
239: }
240:
241: /**
242: * Pauses debugging.
243: */
244: public void pause() {
245: }
246:
247: public void setCurrentLine(Line l) {
248: Line old = getCurrentLine();
249: if (old != null) {
250: // old.unmarkCurrentLine ();
251: currentLineAnnotation.detachLine();
252: }
253: if (l != null) {
254: Utils.showInEditor(l);
255: //l.markCurrentLine ();
256: currentLineAnnotation.attachLine(l);
257: }
258: super .setCurrentLine(l);
259: }
260:
261: protected void setState(int state) {
262: super .setState(state);
263: switch (state) {
264: case DEBUGGER_NOT_RUNNING:
265: setDebuggerState(STATE_NOT_RUNNING);
266: break;
267: case DEBUGGER_RUNNING:
268: setDebuggerState(STATE_RUNNING);
269: break;
270: case DEBUGGER_STOPPED:
271: setDebuggerState(STATE_STOPPED);
272: break;
273: }
274: }
275:
276: /** Creates new uninitialized watch. The watch is visible (not hidden).
277: *
278: * @return new uninitialized watch
279: */
280: public Watch createWatch() {
281: ImportWatch w = new ImportWatch(this , false);
282: addWatch(w);
283: return w;
284: }
285:
286: /** Creates a watch its expression is set to initial value. Also
287: * allows to create a watch not presented to the user, for example
288: * for internal usage in the editor to obtain values of variables
289: * under the mouse pointer.
290: *
291: * @param expr expresion to watch for
292: * @param hidden allows to specify whether the watch should be presented
293: * to the user or not (be only of internal usage of the IDE).
294: * @return new watch
295: */
296: public Watch createWatch(String expr, boolean hidden) {
297: ImportWatch w = new ImportWatch(this , hidden);
298: w.setVariableName(expr);
299: addWatch(w);
300: return w;
301: }
302:
303: // inner debugger implementation ...........................................
304:
305: Validator getValidator() {
306: return validator;
307: }
308:
309: void refreshWatches() {
310: validator.validate();
311: }
312:
313: // inner debugger implementation ...........................................
314:
315: //private HashSet isOnStack = new HashSet ();
316:
317: private HashMap diToStack = new HashMap();
318: private HashMap diToIsOnStack = new HashMap();
319: private CoreDebugger coreDebugger;
320:
321: Stack getStack(DebuggerInfo debuggerInfo) {
322: Stack s = (Stack) diToStack.get(debuggerInfo);
323: if (s == null) {
324: s = new Stack();
325: diToStack.put(debuggerInfo, s);
326: }
327: return s;
328: }
329:
330: HashSet getIsOnStack(DebuggerInfo debuggerInfo) {
331: HashSet s = (HashSet) diToIsOnStack.get(debuggerInfo);
332: if (s == null) {
333: s = new HashSet();
334: diToIsOnStack.put(debuggerInfo, s);
335: }
336: return s;
337: }
338:
339: CoreDebugger getCoreDebugger() {
340: if (coreDebugger == null)
341: try {
342: coreDebugger = (CoreDebugger) TopManager.getDefault()
343: .getDebugger();
344: } catch (DebuggerException e) {
345: }
346: return coreDebugger;
347: }
348:
349: Stack getStack() {
350: return getStack(getInfo());
351: }
352:
353: HashSet getIsOnStack() {
354: return getIsOnStack(getInfo());
355: }
356:
357: DebuggerInfo getInfo() {
358: DebuggerInfo i = null;
359: if (getCoreDebugger().getCurrentDebugger() != null)
360: i = getCoreDebugger().getCurrentDebugger()
361: .getDebuggerInfo();
362: if (i == null)
363: i = getDebuggerInfo();
364: Thread.dumpStack();
365: return i;
366: }
367:
368: Line step() {
369: Stack stack = getStack();
370: HashSet isOnStack = getIsOnStack();
371: Line l = (Line) stack.lastElement();
372: try {
373: // Trace into
374: String str = getText(l);
375: if (str.startsWith("import ")) {
376: str = str.substring(7, str.length() - 1); //.replace ('.', File.separatorChar);
377: Line ll = Utils.getLine(str, 1);
378: if (ll != null)
379: if (!isOnStack.contains(ll.getDataObject())) {
380: stack.push(ll);
381: isOnStack.add(ll.getDataObject());
382: return ll;
383: }
384: }
385: } catch (Exception e) {
386: }
387:
388: stack.pop();
389:
390: // trace over
391: try {
392: if (l.getLineNumber() < 50) {
393: Line ll = Utils.getLine(l.getDataObject()
394: .getPrimaryFile().getPackageName('.'), l
395: .getLineNumber() + 2);
396: if (ll != null) {
397: stack.push(ll);
398: return ll;
399: }
400: }
401: } catch (Exception e) {
402: }
403:
404: // Step out
405: if (stack.empty())
406: return null;
407: Line ll = (Line) stack.pop();
408: if (ll.getLineNumber() < 50)
409: try {
410: ll = Utils.getLine(ll.getDataObject().getPrimaryFile()
411: .getPackageName('.'), ll.getLineNumber() + 2);
412: } catch (Exception e) {
413: }
414: stack.push(ll);
415: return ll;
416: }
417:
418: static String getText(Line l) throws Exception {
419: EditorCookie ec = (EditorCookie) l.getDataObject().getCookie(
420: EditorCookie.class);
421: StyledDocument doc = ec.openDocument();
422: if (doc == null)
423: return "";
424: int off = NbDocument.findLineOffset(doc, l.getLineNumber());
425: int len = NbDocument.findLineOffset(doc, l.getLineNumber() + 1)
426: - off - 1;
427: return doc.getText(off, len);
428: }
429: }
|