/** * Main Corona debugger class * * @author Jan Jancura * @version 0.47, May 26, 1998 */ public class JPDADebugger extends AbstractDebugger implements Executor { // static ........................................................................ static final long serialVersionUID = 2797853329739651906L; /** bundle to obtain text information from */ static ResourceBundle bundle = org.openide.util.NbBundle.getBundle(JPDADebugger.class); private static CoreBreakpoint.Event[] breakpointEvents; private static CoreBreakpoint.Action[] breakpointActions; private static Random random = new Random(); static { breakpointEvents = new CoreBreakpoint.Event[] { // new InstanceCounter (), new LineBreakpoint(), new MethodBreakpoint(), new ExceptionBreakpoint(), new VariableBreakpoint(), new ThreadBreakpoint(), new ClassBreakpoint() }; breakpointActions = new CoreBreakpoint.Action[] {}; } // variables ................................................................. transient VirtualMachine virtualMachine = null; transient EventRequestManager requestManager = null; protected transient ThreadManager threadManager; protected transient Operator operator; private transient Process process; transient StepRequest stepRequest; private transient MethodEntryRequest findSourceMER; private transient StepRequest findSourceSR; private transient int findSourceCounter = 0; private transient Thread debuggerThread; private transient AttachingConnector connector; private transient Map args; private transient String mainClassName; private transient String stopClassName; // threads private transient JPDAThread currentThread = null; protected transient JPDAThreadGroup threadGroup = new JPDAThreadGroup(null); private transient boolean stopOnMain = false; private transient DebuggerInfo debuggerInfo; private static transient String[] stopMethodNames = {"main", "start", "init", "<init>"}; // NOI18N private transient CoreBreakpoint[] breakpointMain = null; // init ....................................................................... public JPDADebugger() { this(false, null); } public JPDADebugger(boolean multisession, Validator validator) { super(multisession, validator); } /** Deserializes debugger. */ protected void setDebugger(AbstractDebugger debugger) { super.setDebugger(debugger); } // Debugger implementation ................................................................. /** * Starts the debugger. The method stops the current debugging (if any) and takes information from * the provided info (containing the class to start and arguments to pass it and name of class to * stop debugging in) and starts new debugging session. * * @param info debugger info about class to start * @exception DebuggerException if an error occures during the start of the debugger */ public void startDebugger(DebuggerInfo info) throws DebuggerException { debuggerInfo = info; if (virtualMachine != null) finishDebugger(); stopOnMain = info.getStopClassName() != null; mainClassName = info .getClassName(); // S ystem.out.println ("JPDADebugger stop on " + info.getStopClassName // ()); // NOI18N // open output window ... super.startDebugger(info); // stop on main if (stopOnMain) { try { String stopClassName = debuggerInfo.getStopClassName(); AbstractDebugger d = (AbstractDebugger) TopManager.getDefault().getDebugger(); breakpointMain = new CoreBreakpoint[stopMethodNames.length]; for (int x = 0; x < breakpointMain.length; x++) { breakpointMain[x] = (CoreBreakpoint) d.createBreakpoint(true); breakpointMain[x].setClassName(""); // NOI18N breakpointMain[x].setMethodName(stopMethodNames[x]); // NOI18N CoreBreakpoint.Action[] a = breakpointMain[x].getActions(); int i, ii = a.length; for (i = 0; i < ii; i++) if (a[i] instanceof PrintAction) { ((PrintAction) a[i]).setPrintText(bundle.getString("CTL_Stop_On_Main_print_text")); } breakpointMain[x].setClassName(stopClassName); } addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent ev) { if (ev.getPropertyName().equals(PROP_STATE)) { if ((((Integer) ev.getNewValue()).intValue() == DEBUGGER_STOPPED) || (((Integer) ev.getNewValue()).intValue() == DEBUGGER_NOT_RUNNING)) { if (breakpointMain != null) { for (int x = 0; x < breakpointMain.length; x++) breakpointMain[x].remove(); breakpointMain = null; } removePropertyChangeListener(this); } } } }); } catch (DebuggerException e) { e.printStackTrace(); } } // start & init remote debugger ............................................ boolean launch = false; if (info instanceof ReconnectDebuggerInfo) { virtualMachine = reconnect((ReconnectDebuggerInfo) info); } else if (info instanceof RemoteDebuggerInfo) { virtualMachine = connect((RemoteDebuggerInfo) info); } else { virtualMachine = launch(info); process = virtualMachine.process(); showOutput(process, STD_OUT, STD_OUT); connectInput(process); launch = true; } requestManager = virtualMachine.eventRequestManager(); operator = new Operator( virtualMachine, launch ? new Runnable() { public void run() { startDebugger(); } } : null, new Runnable() { public void run() { try { finishDebugger(); } catch (DebuggerException e) { } } }); operator.start(); if (!launch) startDebugger(); } /** Finishes debugger. */ public void finishDebugger() throws DebuggerException { if (breakpointMain != null) { for (int x = 0; x < breakpointMain.length; x++) breakpointMain[x].remove(); breakpointMain = null; } try { if (virtualMachine != null) virtualMachine.exit(0); } catch (VMDisconnectedException e) { } if (threadManager != null) threadManager.finish(); if (debuggerThread != null) { debuggerThread.interrupt(); debuggerThread.stop(); } super.finishDebugger(); } /** Trace into. */ public synchronized void traceInto() throws DebuggerException { if (virtualMachine == null) return; removeStepRequest(); try { setLastAction(ACTION_TRACE_INTO); stepRequest = requestManager.createStepRequest( currentThread.getThreadReference(), StepRequest.STEP_LINE, StepRequest.STEP_INTO); stepRequest.addCountFilter(1); stepRequest.putProperty("traceInto", "traceInto"); // NOI18N stepRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); operator.register(stepRequest, this); stepRequest.enable(); virtualMachine.resume(); super.traceInto(); } catch (DuplicateRequestException e) { e.printStackTrace(); } } /** Trace over. */ public synchronized void traceOver() throws DebuggerException { if (virtualMachine == null) return; removeStepRequest(); try { setLastAction(ACTION_TRACE_OVER); stepRequest = requestManager.createStepRequest( currentThread.getThreadReference(), StepRequest.STEP_LINE, StepRequest.STEP_OVER); stepRequest.addCountFilter(1); stepRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); operator.register(stepRequest, this); stepRequest.enable(); virtualMachine.resume(); super.traceOver(); } catch (DuplicateRequestException e) { e.printStackTrace(); } } /** Go. */ public synchronized void go() throws DebuggerException { if (virtualMachine == null) return; setLastAction(ACTION_GO); removeStepRequest(); virtualMachine.resume(); threadGroup.refresh(); super.go(); } /** Step out. */ public synchronized void stepOut() throws DebuggerException { if (virtualMachine == null) return; removeStepRequest(); try { setLastAction(ACTION_STEP_OUT); stepRequest = requestManager.createStepRequest( currentThread.getThreadReference(), StepRequest.STEP_LINE, StepRequest.STEP_OUT); stepRequest.addCountFilter(1); stepRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL); operator.register(stepRequest, this); stepRequest.enable(); virtualMachine.resume(); super.stepOut(); } catch (DuplicateRequestException e) { e.printStackTrace(); } } // WATCHES .............................................................. /** * Creates new uninitialized watch. The watch is visible (not hidden). * * @return new uninitialized watch */ public Watch createWatch() { JPDAWatch w = new JPDAWatch(this); watch.addElement(w); fireWatchCreated(w); return w; } /** * Creates a watch its expression is set to initial value. Also allows to create a watch not * presented to the user, for example for internal usage in the editor to obtain values of * variables under the mouse pointer. * * @param expr expresion to watch for * @param hidden allows to specify whether the watch should be presented to the user or not (be * only of internal usage of the IDE). * @return new watch */ public Watch createWatch(String expr, boolean hidden) { JPDAWatch w = new JPDAWatch(this); if (!hidden) watch.addElement(w); w.setVariableName(expr); if (!hidden) fireWatchCreated(w); return w; } // AbstractDebugger implementation .................................................. // properties ........................ /** Returns version of this debugger. */ public String getVersion() { return bundle.getString("CTL_Debugger_version"); /* if (virtualMachine != null) return virtualMachine.versionDescription () + " (" + virtualMachine.majorVersion () + "/" + virtualMachine.minorVersion () + ")"; else return bundle.getString ("CTL_Debugger_version");*/ } /** Returns size of memory. */ public int getTotalMemory() throws DebuggerException { if (virtualMachine == null) return 0; return 0; } /** Returns size of free memory. */ public int getFreeMemory() throws DebuggerException { if (virtualMachine == null) return 0; return 0; } /** @return newly constructed string containing classpath obtained from filesystems */ public String getClasspath() { return ""; // NOI18N } /** @return Connect Panel for this version of debugger. */ public JComponent getConnectPanel() { return new Connector(); } /** @return name of proces for given DebuggerInfo. */ public String getProcessName(DebuggerInfo info) { if (info instanceof RemoteDebuggerInfo) { if (((RemoteDebuggerInfo) info).getConnector().transport().name().equals("dt_shmem")) { Argument a = (Argument) ((RemoteDebuggerInfo) info).getArgs().get("name"); if (a == null) return "localhost:???"; else return "localhost:" + a.value(); } else if (((RemoteDebuggerInfo) info) .getConnector() .transport() .name() .equals("dt_socket")) { Argument name = (Argument) ((RemoteDebuggerInfo) info).getArgs().get("hostname"); Argument port = (Argument) ((RemoteDebuggerInfo) info).getArgs().get("port"); return ((name == null) ? "???:" : (name.value() + ":")) + ((port == null) ? "???" : (port.value())); } else return "???"; } else return (info.getStopClassName() != null) ? info.getStopClassName() : info.getClassName(); } /** @return name of location for given DebuggerInfo. */ public String getLocationName(DebuggerInfo info) { if (info instanceof RemoteDebuggerInfo) { if (((RemoteDebuggerInfo) info).getConnector().transport().name().equals("dt_shmem")) { return "localhost"; } else if (((RemoteDebuggerInfo) info) .getConnector() .transport() .name() .equals("dt_socket")) { Argument name = (Argument) ((RemoteDebuggerInfo) info).getArgs().get("hostname"); return name == null ? "localhost" : name.value(); } else return "localhost"; } else return "localhost"; } /** Returns true - JPDADebugger supports evaluation of expressions. */ public boolean supportsExpressions() { return true; } // breakpoints ........................ /** Returns events available for this version of debugger. */ public CoreBreakpoint.Event[] getBreakpointEvents() { return breakpointEvents; } /** Returns actions available for this version of debugger. */ public CoreBreakpoint.Action[] getBreakpointActions() { return breakpointActions; } // threads ........................ /** Returns root of all threads. */ public AbstractThreadGroup getThreadGroupRoot() { return threadGroup; } /** Returns current thread or null. */ public AbstractThread getCurrentThread() { return currentThread; } /** Sets current thread. If thread is null, unsets curent thread. */ public void setCurrentThread(AbstractThread thread) { if (currentThread == thread) return; Object old = currentThread; currentThread = (JPDAThread) thread; firePropertyChange(PROP_CURRENT_THREAD, old, thread); } // interface Executor ..................................................................... /** Executes breakpoint hit event. */ public void exec(com.sun.jdi.event.Event ev) { // S ystem.out.println ("exec "); // NOI18N removeStepRequest(); StepEvent event = (StepEvent) ev; ThreadReference tr = event.thread(); Location loc = event.location(); int ln = -1; String methodName = "?"; // NOI18N String className = "?"; // NOI18N String lineNumber = "?"; // NOI18N String threadName = tr.name(); Line l = null; if (loc != null) { if (loc.method() != null) methodName = loc.method().name(); className = loc.declaringType().name(); ln = loc.lineNumber(); if (ln >= 0) lineNumber = "" + loc.lineNumber(); } if (ln != -1) try { l = Utils.getLineForSource(className, loc.sourceName(), ln); } catch (AbsentInformationException e) { l = Utils.getLine(className, ln); } if (resolveCanBeCurrent(tr, l)) // if this line can not be current resolveCanBeCurrent () calls stepOver return; // line can be current if ((l == null) && (getLastAction() == ACTION_TRACE_INTO)) // try to find another "intelligent" line of code traceToSourceCode(tr); // you know - intelligent means that one with source code else { makeCurrent(threadName, className, methodName, lineNumber, l != null, tr); operator.stopRequest(); } } // support for multisession debugging // ................................................................ /** Disconnects from running debugged process. */ public void disconnect() throws DebuggerException { if (breakpointMain != null) { for (int x = 0; x < breakpointMain.length; x++) breakpointMain[x].remove(); breakpointMain = null; } try { if (virtualMachine != null) virtualMachine.dispose(); } catch (VMDisconnectedException e) { } if (threadManager != null) threadManager.finish(); if (debuggerThread != null) { debuggerThread.interrupt(); debuggerThread.stop(); } super.finishDebugger(); } /** Reconnects to disconnected Virtual Machine. */ public void reconnect() throws DebuggerException { startDebugger(new ReconnectDebuggerInfo(connector, args)); } // helper private methods // ......................................................................... /** Finds the first executed line with source code. */ public void traceToSourceCode(ThreadReference thread) { // S ystem.out.println ("Start finding!!! "); // NOI18N // create Step Request for searching a source code try { findSourceSR = requestManager.createStepRequest(thread, StepRequest.STEP_LINE, StepRequest.STEP_OUT); findSourceSR.addCountFilter(1); findSourceSR.setSuspendPolicy(EventRequest.SUSPEND_ALL); operator.register(findSourceSR, this); findSourceSR.enable(); } catch (DuplicateRequestException e) { e.printStackTrace(); } // create Method Entry Request for searching a source code findSourceMER = requestManager.createMethodEntryRequest(); findSourceMER.setSuspendPolicy(EventRequest.SUSPEND_ALL); findSourceMER.addThreadFilter(thread); findSourceCounter = 0; operator.register( findSourceMER, new Executor() { public void exec(com.sun.jdi.event.Event event) { if (findSourceCounter == 500) { // finding source takes a long time operator.resume(); if (findSourceMER != null) { requestManager.deleteEventRequest(findSourceMER); findSourceMER = null; } return; } findSourceCounter++; Location loc = ((MethodEntryEvent) event).location(); if (loc == null) { // no line => continue finding operator.resume(); return; } String className = loc.declaringType().name(); int ln = loc.lineNumber(); // S ystem.out.println ("FIND " + className + " : " + ln); // NOI18N try { Line l = null; if ((l = Utils.getLineForSource(className, loc.sourceName(), ln)) == null) { // no line => continue finding operator.resume(); return; } // WOW I have a nice line! ThreadReference tr = ((MethodEntryEvent) event).thread(); if (resolveCanBeCurrent(tr, l)) // if can not be current => steps to some line return; // line can be current! String threadName = tr.name(); String methodName = loc.method() != null ? loc.method().name() : ""; // NOI18N String lineNumber = ln == -1 ? "?" : "" + ln; // NOI18N makeCurrent(threadName, className, methodName, lineNumber, true, tr); operator.stopRequest(); } catch (AbsentInformationException e) { } } }); findSourceMER.enable(); operator.resume(); return; } /** if this line can not be current => stepOver & return true. return false on the other hand. */ boolean resolveCanBeCurrent(ThreadReference tr) { try { Location l = tr.frame(0).location(); if (l == null) return false; return resolveCanBeCurrent( tr, Utils.getLineForSource(l.declaringType().name(), l.sourceName(), l.lineNumber())); } catch (Exception e) { } return false; } /** * If this line can not be current => stepOver & return true. {support for non java languages} * * <p>return false on the other hand. */ boolean resolveCanBeCurrent(ThreadReference tr, Line l) { if ((l != null) && (!canBeCurrent(l, false))) { try { removeStepRequest(); findSourceSR = requestManager.createStepRequest(tr, StepRequest.STEP_LINE, StepRequest.STEP_OVER); findSourceSR.addCountFilter(1); findSourceSR.setSuspendPolicy(EventRequest.SUSPEND_ALL); operator.register(findSourceSR, this); findSourceSR.enable(); operator.resume(); } catch (DuplicateRequestException e) { e.printStackTrace(); } return true; } return false; } /** * Sets curent line. It means: change debugger state to stopped, shows message, sets current * thread and updates watches. */ private void makeCurrent( final String threadName, final String className, final String methodName, final String lineNumber, final boolean hasSource, final ThreadReference tr) { setDebuggerState(DEBUGGER_STOPPED); SwingUtilities.invokeLater( new Runnable() { public void run() { // show message if (isFollowedByEditor()) { if (hasSource) { println( new MessageFormat(bundle.getString("CTL_Thread_stopped")) .format(new Object[] {threadName, className, methodName, lineNumber}), ERR_OUT + STL_OUT); } else { println( new MessageFormat(bundle.getString("CTL_Thread_stopped_no_source")) .format(new Object[] {threadName, className, methodName, lineNumber}), ERR_OUT + STL_OUT); } } else println( new MessageFormat(bundle.getString("CTL_Thread_stopped")) .format(new Object[] {threadName, className, methodName, lineNumber}), ERR_OUT + STL_OUT); // refresh all JPDAThread tt = threadManager.getThread(tr); tt.setCurrent(true); updateWatches(); } }); } /** Second part of debugger start procedure. */ private void startDebugger() { threadManager = new ThreadManager(this); setBreakpoints(); updateWatches(); println(bundle.getString("CTL_Debugger_running"), STL_OUT); setDebuggerState(DEBUGGER_RUNNING); virtualMachine.resume(); // start refresh thread ................................................. if (debuggerThread != null) debuggerThread.stop(); debuggerThread = new Thread( new Runnable() { public void run() { for (; ; ) { try { Thread.sleep(5000); } catch (InterruptedException ex) { } if (getState() == DEBUGGER_RUNNING) threadGroup.refresh(); } } }, "Debugger refresh thread"); // NOI18N debuggerThread.setPriority(Thread.MIN_PRIORITY); debuggerThread.start(); } /** Removes last step request. */ void removeStepRequest() { if (stepRequest != null) { requestManager.deleteEventRequest(stepRequest); stepRequest = null; } if (findSourceMER != null) { requestManager.deleteEventRequest(findSourceMER); findSourceMER = null; } if (findSourceSR != null) { requestManager.deleteEventRequest(findSourceSR); findSourceSR = null; } } private static String generatePassword() { StringBuffer sb = new StringBuffer(); for (int i = 0; i < 4; i++) sb.append((char) (random.nextInt(26) + 'a')); return new String(sb); } private VirtualMachine launch(DebuggerInfo info) throws DebuggerException { // create process & read password for local debugging // create main class & arguments ............................................... StringBuffer sb = new StringBuffer(); sb.append(mainClassName); String[] infoArgs = info.getArguments(); int i, k = infoArgs.length; for (i = 0; i < k; i++) sb.append(" \"").append(infoArgs[i]).append('"'); // NOI18N String main = new String(sb); // create connector .............................................................. VirtualMachineManager vmm = Bootstrap.virtualMachineManager(); java.util.List lcs = vmm.launchingConnectors(); k = lcs.size(); for (i = 0; i < k; i++) if (((LaunchingConnector) lcs.get(i)).name().indexOf("RawCommandLineLaunch") >= 0) // NOI18N break; if (i == k) { finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_Cannot_find_launcher")) .format( new Object[] { "RawCommandLineLaunch" // NOI18N })); } LaunchingConnector lc = (LaunchingConnector) lcs.get(i); String transport = lc.transport().name(); // create commandLine & NbProcessDescriptor .............................. NbProcessDescriptor debugerProcess; if (info instanceof ProcessDebuggerInfo) debugerProcess = ((ProcessDebuggerInfo) info).getDebuggerProcess(); else debugerProcess = ProcessDebuggerType.DEFAULT_DEBUGGER_PROCESS; // generate password String password; if (transport.equals("dt_shmem")) { // NOI18N connector = getAttachingConnectorFor("dt_shmem"); password = generatePassword(); args = connector.defaultArguments(); ((Argument) args.get("name")).setValue(password); } else { try { java.net.ServerSocket ss = new java.net.ServerSocket(0); password = "" + ss.getLocalPort(); // NOI18N ss.close(); } catch (java.io.IOException e) { finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_Cannot_find_empty_local_port")) .format(new Object[] {e.toString()})); } connector = getAttachingConnectorFor("dt_socket"); args = connector.defaultArguments(); ((Argument) args.get("port")).setValue(password); } HashMap map = Utils.processDebuggerInfo( info, "-Xdebug -Xnoagent -Xrunjdwp:transport=" + // NOI18N transport + ",address=" + // NOI18N password + ",suspend=y ", // NOI18N main); MapFormat format = new MapFormat(map); String commandLine = format.format( debugerProcess.getProcessName() + " " + // NOI18N debugerProcess.getArguments()); println(commandLine, ERR_OUT); /* We mus wait on process start to connect... try { process = debugerProcess.exec (format); } catch (java.io.IOException exc) { finishDebugger (); throw new DebuggerException ( new MessageFormat (bundle.getString ("EXC_While_create_debuggee")). format (new Object[] { debugerProcess.getProcessName (), exc.toString () }), exc ); } return connect ( null, connector, args );*/ /* S ystem.out.println ("attaching: "); Utils.showConnectors (vmm.attachingConnectors ()); S ystem.out.println ("launching: "); Utils.showConnectors (vmm.launchingConnectors ()); S ystem.out.println ("listening: "); Utils.showConnectors (vmm.listeningConnectors ());*/ // set debugger-start arguments Map params = lc.defaultArguments(); ((Argument) params.get("command")) .setValue( // NOI18N commandLine); ((Argument) params.get("address")) .setValue( // NOI18N password); // launch VM try { return lc.launch(params); } catch (VMStartException exc) { showOutput(process = exc.process(), ERR_OUT, ERR_OUT); finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_While_create_debuggee")) .format( new Object[] {format.format(debugerProcess.getProcessName()), exc.toString()}), exc); } catch (Exception exc) { finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_While_create_debuggee")) .format( new Object[] {format.format(debugerProcess.getProcessName()), exc.toString()}), exc); } } private VirtualMachine reconnect(ReconnectDebuggerInfo info) throws DebuggerException { return connect("CTL_Reconnecting_to", info.getConnector(), info.getArgs()); } private VirtualMachine connect(RemoteDebuggerInfo info) throws DebuggerException { return connect("CTL_Connecting_to", connector = info.getConnector(), args = info.getArgs()); } private VirtualMachine connect(String bndlPrefix, AttachingConnector connector, Map args) throws DebuggerException { if (bndlPrefix != null) { if (connector.transport().name().equals("dt_shmem")) { Argument a = (Argument) args.get("name"); if (a == null) println(bundle.getString(bndlPrefix + "_shmem_noargs"), ERR_OUT); else println( new MessageFormat(bundle.getString(bndlPrefix + "_shmem")) .format(new Object[] {a.value()}), ERR_OUT); } else if (connector.transport().name().equals("dt_socket")) { Argument name = (Argument) args.get("hostname"); Argument port = (Argument) args.get("port"); if ((name == null) || (port == null)) println(bundle.getString(bndlPrefix + "_socket_noargs"), ERR_OUT); else println( new MessageFormat(bundle.getString(bndlPrefix + "_socket")) .format(new Object[] {name.value(), port.value()}), ERR_OUT); } else println(bundle.getString(bndlPrefix), ERR_OUT); } // launch VM try { // S ystem.out.println ("attach to:" + ac + " : " + password); // NOI18N return connector.attach(args); } catch (Exception e) { finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_While_connecting_to_debuggee")) .format(new Object[] {e.toString()}), e); } } /** Performs stop action. */ void stop(boolean stop, final AbstractThread thread) { final ResourceBundle bundle = NbBundle.getBundle(JPDADebugger.class); if (stop) { removeStepRequest(); setLastAction(ACTION_BREAKPOINT_HIT); setDebuggerState(DEBUGGER_STOPPED); operator.stopRequest(); SwingUtilities.invokeLater( new Runnable() { public void run() { thread.setCurrent(true); updateWatches(); threadGroup.refresh(); } }); } else operator.resume(); } private static AttachingConnector getAttachingConnectorFor(String transport) { List acs = Bootstrap.virtualMachineManager().attachingConnectors(); AttachingConnector ac; int i, k = acs.size(); for (i = 0; i < k; i++) if ((ac = (AttachingConnector) acs.get(i)).transport().name().equals(transport)) return ac; return null; } /** * Setter method for debugger state property. * * @param newState */ public synchronized void setDebuggerState(final int newState) { super.setDebuggerState(newState); } // innerclasses .............................................................. private class ReconnectDebuggerInfo extends RemoteDebuggerInfo { private ReconnectDebuggerInfo(AttachingConnector connector, Map args) { super(connector, args); } } class Connector extends JPanel implements DebuggerInfoProducer, ActionListener { private JComboBox cbConnectors; private Map args; private java.util.List acs; private JTextField[] tfParams; private AttachingConnector ac; Connector() { VirtualMachineManager vmm = Bootstrap.virtualMachineManager(); acs = vmm.attachingConnectors(); setLayout(new GridBagLayout()); refresh(0); } private void refresh(int index) { GridBagConstraints c = new GridBagConstraints(); // No connector ................ if (acs.size() == 0) { add(new JLabel(bundle.getString("CTL_No_Connector")), c); return; } // Connector switch ................ if (acs.size() > 1) { c.insets = new Insets(0, 0, 3, 3); add(new JLabel(bundle.getString("CTL_Connector")), c); cbConnectors = new JComboBox(); int i, k = acs.size(); for (i = 0; i < k; i++) { AttachingConnector ac = (AttachingConnector) acs.get(i); int jj = ac.name().lastIndexOf('.'); String s = (jj < 0) ? ac.name() : ac.name().substring(jj + 1); cbConnectors.addItem(s + " (" + ac.description() + ")"); } c = new GridBagConstraints(); c.insets = new Insets(0, 3, 3, 0); c.weightx = 1.0; c.fill = java.awt.GridBagConstraints.HORIZONTAL; c.gridwidth = 0; cbConnectors.setSelectedIndex(index); cbConnectors.setActionCommand("SwitchMe!"); cbConnectors.addActionListener(this); add(cbConnectors, c); } ac = (AttachingConnector) acs.get(index); // Transport ................ c = new GridBagConstraints(); c.insets = new Insets(3, 0, 0, 3); add(new JLabel(bundle.getString("CTL_Transport")), c); JTextField tfTransport = new JTextField(ac.transport().name()); tfTransport.setEnabled(false); c = new GridBagConstraints(); c.gridwidth = 0; c.insets = new Insets(3, 3, 0, 0); c.fill = java.awt.GridBagConstraints.HORIZONTAL; c.weightx = 1.0; add(tfTransport, c); // Other params ................ args = ac.defaultArguments(); tfParams = new JTextField[args.size()]; Iterator it = args.keySet().iterator(); int i = 0; while (it.hasNext()) { String name = (String) it.next(); Argument a = (Argument) args.get(name); c = new GridBagConstraints(); c.insets = new Insets(6, 0, 0, 3); c.anchor = GridBagConstraints.WEST; add(new JLabel(a.label() + ": "), c); JTextField tfParam = new JTextField(a.value()); tfParams[i++] = tfParam; tfParam.setName(name); c = new GridBagConstraints(); c.gridwidth = 0; c.insets = new Insets(6, 3, 0, 0); c.fill = java.awt.GridBagConstraints.HORIZONTAL; c.weightx = 1.0; add(tfParam, c); } c = new GridBagConstraints(); c.weighty = 1.0; JPanel p = new JPanel(); p.setPreferredSize(new Dimension(1, 1)); add(p, c); } /** Returns DebuggerInfo. */ public DebuggerInfo getDebuggerInfo() { int i, k = tfParams.length; for (i = 0; i < k; i++) { Argument a = (Argument) args.get(tfParams[i].getName()); a.setValue(tfParams[i].getText()); } return new RemoteDebuggerInfo(ac, args); } public void actionPerformed(ActionEvent e) { removeAll(); refresh(((JComboBox) e.getSource()).getSelectedIndex()); Component w = getParent(); while (!(w instanceof Window)) w = w.getParent(); if (w != null) ((Window) w).pack(); // ugly hack... return; } private String translate(String name) { /* if (name.equals ("SwitchMe!")) return else*/ return name; } } }
/** * Main Corona debugger class * * @author Jan Jancura, Jaroslav Tulach * @version 0.47, May 26, 1998 */ public class ToolsDebugger extends AbstractDebugger { // static ........................................................................ static final long serialVersionUID = 2791375515739651906L; /** bundle to obtain text information from */ static ResourceBundle bundle = org.openide.util.NbBundle.getBundle(ToolsDebugger.class); static final int TIMEOUT = 5000; private static CoreBreakpoint.Event[] breakpointEvents; private static CoreBreakpoint.Action[] breakpointActions; private static String host = "localhost"; // NOI18N static { breakpointEvents = new CoreBreakpoint.Event[] { new LineBreakpoint(), new MethodBreakpoint(), new ExceptionBreakpoint() }; breakpointActions = new CoreBreakpoint.Action[] {}; } // variables ................................................................. /* Helper for synchronizing sun.tools.debug */ transient RequestSynchronizer synchronizer; /* sun.tools.debug main debugger class */ transient RemoteDebugger remoteDebugger = null; /* debugged process */ private transient Process process; private transient String hostName; private transient String password; private transient String mainClassName; private transient String stopClassName; // threads private transient ToolsThread currentThread = null; transient RemoteThread lastCurrentThread = null; protected transient ToolsThreadGroup threadGroup = new ToolsThreadGroup(this, null); /** Refresh thread. */ private transient Thread debuggerThread; // properties private transient String sourcePath = null; private transient String[] exceptionCatchList = null; private transient DebuggerInfo debuggerInfo; transient RequestSynchronizer.RequestWaiter killer; transient boolean stopOnMainFlag; // init ....................................................................... public ToolsDebugger() { this(false, null); } public ToolsDebugger(boolean multisession, Validator validator) { super(multisession, validator); killer = new RequestSynchronizer.RequestWaiter() { public void run(Thread t) { // S ystem.out.println ("KILL!!!"); // NOI18N // T hread.dumpStack (); if (process != null) { if (System.getProperty("netbeans.full.hack") == null) { // [PENDING] process.destroy(); t.stop(); } TopManager.getDefault() .notify( new NotifyDescriptor.Message( new MessageFormat(bundle.getString("EXC_Deadlock")) .format(new Object[] {t.getName()}))); } } }; } /** Deserializes debugger. */ protected void setDebugger(AbstractDebugger debugger) { super.setDebugger(debugger); } // Debugger implementation ................................................................. /** * Starts the debugger. The method stops the current debugging (if any) and takes information from * the provided info (containing the class to start and arguments to pass it and name of class to * stop debugging in) and starts new debugging session. * * @param info debugger info about class to start * @exception DebuggerException if an error occures during the start of the debugger */ public void startDebugger(DebuggerInfo info) throws DebuggerException { debuggerInfo = info; if (remoteDebugger != null) finishDebugger(); // S ystem.out.println("startDebugger " + info); // NOI18N // RemoteDebugging support hostName = null; password = null; boolean local = true; if (info instanceof ReconnectDebuggerInfo) { ReconnectDebuggerInfo rdi = (ReconnectDebuggerInfo) info; hostName = rdi.getHostName(); password = rdi.getPassword(); local = false; } else if (info instanceof RemoteDebuggerInfo) { hostName = ((RemoteDebuggerInfo) info).getHostName(); password = ((RemoteDebuggerInfo) info).getPassword(); local = false; } boolean stopOnMain = info.getStopClassName() != null; stopOnMainFlag = stopOnMain; // S ystem.out.println ("ToolsDebugger.startDebugger " + info.getStopClassName ()); // NOI18N // T hread.dumpStack (); synchronizer = new RequestSynchronizer(); // open output window ... super.startDebugger(info); // start & init remote debugger ................................................ // process = null; if (local) { // create process & read password for local debugging // create starting string & NbProcessDescriptor NbProcessDescriptor debugerProcess; if (info instanceof ProcessDebuggerInfo) debugerProcess = ((ProcessDebuggerInfo) info).getDebuggerProcess(); else debugerProcess = ProcessDebuggerType.DEFAULT_DEBUGGER_PROCESS; HashMap map; if (info instanceof ToolsDebugger10Info) { map = Utils.processDebuggerInfo( info, "-debug", // NOI18N "sun.tools.debug.EmptyApp" // NOI18N ); map.put(ToolsDebugger10Type.JAVA_HOME_SWITCH, ((ToolsDebugger10Info) info).getJavaHome()); } else { if (info instanceof ToolsDebugger11Info) { String javaHome11 = ((ToolsDebugger11Info) info).getJavaHome(); if ((javaHome11 == null) || (javaHome11.trim().length() == 0)) { finishDebugger(); throw new DebuggerException(bundle.getString("EXC_JDK11_home_is_not_set")); } map = Utils.processDebuggerInfo( info, "-debug -nojit", // NOI18N "sun.tools.debug.EmptyApp" // NOI18N ); map.put(ToolsDebugger11Type.JAVA_HOME_SWITCH, javaHome11); } else { map = Utils.processDebuggerInfo( info, "-Xdebug", // NOI18N "sun.tools.agent.EmptyApp" // NOI18N ); } } MapFormat format = new MapFormat(map); String s = format.format( debugerProcess.getProcessName() + " " + debugerProcess.getArguments() // NOI18N ); println(s, ERR_OUT); // start process & read password ...................................... try { process = debugerProcess.exec(format); BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(process.getInputStream())); password = bufferedreader.readLine(); showOutput(process, ERR_OUT, ERR_OUT); connectInput(process); } catch (java.lang.Exception e) { finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_While_create_debuggee")) .format( new Object[] {format.format(debugerProcess.getProcessName()), e.toString()}), e); } if (password == null) { // no reply finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_While_connect_to_debuggee")) .format(new Object[] {format.format(debugerProcess.getProcessName())})); } if (password.indexOf("=") < 0) { // NOI18N // unexpected reply println(bundle.getString("CTL_Unexpected_reply") + ": " + password, ERR_OUT); showOutput(process, ERR_OUT + STD_OUT, ERR_OUT); finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_Unecpected_debugger_reply")) .format(new Object[] {password})); } password = password.substring(password.indexOf("=") + 1); // NOI18N println(bundle.getString("CTL_Password") + ": " + password, ERR_OUT); hostName = "127.0.0.1"; // NOI18N } // end of local debugging specific else if (info instanceof ReconnectDebuggerInfo) { println(bundle.getString("CTL_Reconnecting"), ERR_OUT | STD_OUT); } else println(bundle.getString("CTL_Connecting_to") + ": " + hostName + ":" + password, ERR_OUT); // start RemoteDebugger ................................................... try { remoteDebugger = new RemoteDebugger( hostName, password.length() < 1 ? null : password, new ToolsCallback(this), isShowMessages()); } catch (java.net.ConnectException e) { finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_Cannot_connect_to_debuggee")) .format(new Object[] {e.toString()}), e); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath) e; // e.printStackTrace (); finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_Cannot_connect_to_debuggee")) .format(new Object[] {e.toString()}), e); } // create arguments for main class ............................................... mainClassName = info.getClassName(); RemoteClass cls; String[] args = null; if ((mainClassName != null) && (mainClassName.length() > 0)) { String[] infoArgs = info.getArguments(); args = new String[infoArgs.length + 1]; args[0] = mainClassName; System.arraycopy(infoArgs, 0, args, 1, infoArgs.length); // args[0] = name of class // args[...] = parameters // find main class ......................................................... try { cls = remoteDebugger.findClass(mainClassName); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath) e; finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_Cannot_find_class")) .format(new Object[] {mainClassName, e.toString()}), e); } if (cls == null) { finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_Cannot_find_class")) .format(new Object[] {mainClassName, new ClassNotFoundException().toString()})); } } // set breakpoint on stop class method ............................................... if (stopOnMain) { RemoteClass stopClass = null; try { stopClass = remoteDebugger.findClass(stopClassName = info.getStopClassName()); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath) e; println( bundle.getString("MSG_Exc_while_finding_class") + stopClassName + '\n' + e, ERR_OUT); } if (stopClass == null) { println(bundle.getString("CTL_No_such_class") + ": " + stopClassName, ERR_OUT); } else { try { RemoteField[] rf = stopClass.getMethods(); int i, k = rf.length; Type t = Type.tMethod(Type.tVoid, new Type[] {Type.tArray(Type.tString)}); Type startT = Type.tMethod(Type.tVoid); RemoteField startM = null; RemoteField initM = null; RemoteField constM = null; for (i = 0; i < k; i++) { if (rf[i].getName().equals("main") && // NOI18N rf[i].getType().equals(t)) break; else if (rf[i].getName().equals("start") && // NOI18N rf[i].getType().equals(startT)) startM = rf[i]; else if (rf[i].getName().equals("init") && // NOI18N rf[i].getType().equals(startT)) initM = rf[i]; else if (rf[i].getName().equals("<init>") && // NOI18N rf[i].getType().equals(startT)) constM = rf[i]; } if (i < k) // [PENDING] stop on non main too !!!!!!!!!!!!!!!!!!!!! stopClass.setBreakpointMethod(rf[i]); // have main else if (initM != null) stopClass.setBreakpointMethod(initM); else if (startM != null) stopClass.setBreakpointMethod(startM); else if (constM != null) stopClass.setBreakpointMethod(constM); // S ystem.out.println ("Stop: " + (i <k) + " " + initM +" " + startM +" " + constM); // // NOI18N /* pendingBreakpoints = new RemoteField [1]; pendingBreakpoints [0] = rf[i]; pendingBreakpointsClass = stopClass;*/ } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath) e; println(bundle.getString("MSG_Exc_while_setting_breakpoint") + '\n' + e, ERR_OUT); } } } // stopOnMain setBreakpoints(); updateWatches(); println(bundle.getString("CTL_Debugger_running"), STL_OUT); setDebuggerState(DEBUGGER_RUNNING); // run debugged class ............................................... if (args != null) { RemoteThreadGroup rtg = null; try { rtg = remoteDebugger.run(args.length, args); // threadGroup.setRemoteThreadGroup (rtg); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath) e; finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_While_calling_run")) .format(new Object[] {mainClassName, e.toString()}), e); } if (rtg == null) { finishDebugger(); throw new DebuggerException( new MessageFormat(bundle.getString("EXC_While_calling_run")) .format( new Object[] { mainClassName, "" // NOI18N })); } } // start refresh thread ................................................. if (debuggerThread != null) debuggerThread.stop(); debuggerThread = new Thread( new Runnable() { public void run() { for (; ; ) { try { Thread.sleep(5000); } catch (InterruptedException ex) { } if (getState() == DEBUGGER_RUNNING) try { threadGroup.threadChanged(); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath) e; if (e instanceof java.net.SocketException) { debuggerThread = null; try { finishDebugger(); } catch (Throwable ee) { if (ee instanceof ThreadDeath) throw (ThreadDeath) ee; } Thread.currentThread().stop(); } } } } }, "Debugger refresh thread"); // NOI18N debuggerThread.setPriority(Thread.MIN_PRIORITY); debuggerThread.start(); } /** Finishes debugger. */ public void finishDebugger() throws DebuggerException { threadGroup.setRemoteThreadGroup(null); if (remoteDebugger != null) { remoteDebugger.close(); remoteDebugger = null; } if (process != null) process.destroy(); if (debuggerThread != null) { debuggerThread.interrupt(); debuggerThread.stop(); } super.finishDebugger(); synchronizer = null; } /** Trace into. */ public void traceInto() throws DebuggerException { if (currentThread == null) return; setLastAction(ACTION_TRACE_INTO); currentThread.setLastAction(ACTION_TRACE_INTO); new Protector("AbstractDebugger.traceInto") { // NOI18N public Object protect() throws Exception { currentThread.getRemoteThread().step(true); ToolsDebugger.super.traceInto(); return null; } }.go(synchronizer, killer); } /** Trace over. */ public void traceOver() throws DebuggerException { if (currentThread == null) return; setLastAction(ACTION_TRACE_OVER); currentThread.setLastAction(ACTION_TRACE_OVER); new Protector("AbstractDebugger.traceOver") { // NOI18N public Object protect() throws Exception { currentThread.getRemoteThread().next(); ToolsDebugger.super.traceOver(); return null; } }.go(synchronizer, killer); } /** Go. */ public void go() throws DebuggerException { if (currentThread == null) return; setLastAction(ACTION_GO); currentThread.setLastAction(ACTION_GO); new Protector("AbstractDebugger.go") { // NOI18N public Object protect() throws Exception { remoteDebugger.cont(); ToolsDebugger.super.go(); return null; } }.go(synchronizer, killer); // threadGroup.setSuspended (false); } /** Step out. */ public void stepOut() throws DebuggerException { if (currentThread == null) return; setLastAction(ACTION_STEP_OUT); currentThread.setLastAction(ACTION_STEP_OUT); new Protector("AbstractDebugger.stepOut") { // NOI18N public Object protect() throws Exception { currentThread.getRemoteThread().stepOut(); ToolsDebugger.super.stepOut(); return null; } }.go(synchronizer, killer); } // WATCHES .............................................................. /** * Creates new uninitialized watch. The watch is visible (not hidden). * * @return new uninitialized watch */ public Watch createWatch() { ToolsWatch w = new ToolsWatch(this); watch.addElement(w); fireWatchCreated(w); return w; } /** * Creates a watch its expression is set to initial value. Also allows to create a watch not * presented to the user, for example for internal usage in the editor to obtain values of * variables under the mouse pointer. * * @param expr expresion to watch for * @param hidden allows to specify whether the watch should be presented to the user or not (be * only of internal usage of the IDE). * @return new watch */ public Watch createWatch(String expr, boolean hidden) { ToolsWatch w = new ToolsWatch(this); if (!hidden) watch.addElement(w); w.setVariableName(expr); if (!hidden) fireWatchCreated(w); return w; } // AbstractDebugger implementation .................................................. // properties ........................ /** Returns version of this debugger. */ public String getVersion() { return bundle.getString("CTL_Debugger_version"); } /** Returns size of memory. */ public int getTotalMemory() throws DebuggerException { if (remoteDebugger == null) return 0; try { return ((Integer) new Protector("AbstractDebugger.getTotalMemory") { // NOI18N public Object protect() throws Exception { return new Integer(remoteDebugger.totalMemory()); } }.throwAndWait(synchronizer, killer)) .intValue(); } catch (Exception e) { throw new DebuggerException(e); } } /** Returns size of free memory. */ public int getFreeMemory() throws DebuggerException { if (remoteDebugger == null) return 0; try { return ((Integer) new Protector("AbstractDebugger.getFreeMemory") { // NOI18N public Object protect() throws Exception { return new Integer(remoteDebugger.freeMemory()); } }.throwAndWait(synchronizer, killer)) .intValue(); } catch (Exception e) { throw new DebuggerException(e); } } /** @return newly constructed string containing classpath obtained from filesystems */ public String getClasspath() { if (remoteDebugger != null) { try { return remoteDebugger.getSourcePath(); } catch (Exception e) { } } return ""; // getDefaultClasspath (); // NOI18N } /** @return Connect Panel for this version of debugger. */ public JComponent getConnectPanel() { return new Connector(); } /** @return name of proces for given DebuggerInfo. */ public String getProcessName(DebuggerInfo info) { String n; if (info instanceof RemoteDebuggerInfo) return ((RemoteDebuggerInfo) info).getHostName() + ":" + // NOI18N ((RemoteDebuggerInfo) info).getPassword(); else return (info.getStopClassName() != null) ? info.getStopClassName() : info.getClassName(); } /** @return name of location for given DebuggerInfo. */ public String getLocationName(DebuggerInfo info) { String n; if (info instanceof RemoteDebuggerInfo) return ((RemoteDebuggerInfo) info).getHostName(); else return "localhost"; } /** Returns false, ToolsDebugger does not support evaluation of expressions. */ public boolean supportsExpressions() { return false; } // breakpoints ........................ /** Returns events available for this version of debugger. */ public CoreBreakpoint.Event[] getBreakpointEvents() { return breakpointEvents; } /** Returns actions available for this version of debugger. */ public CoreBreakpoint.Action[] getBreakpointActions() { return breakpointActions; } // threads ........................ /** Returns root of all threads. */ public AbstractThreadGroup getThreadGroupRoot() { return threadGroup; } /** Returns current thread or null. */ public AbstractThread getCurrentThread() { return currentThread; } /** Sets current thread. If thread is null, unsets curent thread. */ public void setCurrentThread(AbstractThread thread) { if (currentThread == thread) return; Object old = currentThread; currentThread = (ToolsThread) thread; firePropertyChange(PROP_CURRENT_THREAD, old, thread); } // support for multisession debugging // ................................................................ /** Disconnects from running debugged process. */ public void disconnect() throws DebuggerException { threadGroup.setRemoteThreadGroup(null); if (remoteDebugger != null) { remoteDebugger.close(); remoteDebugger = null; } if (debuggerThread != null) { debuggerThread.interrupt(); debuggerThread.stop(); } super.finishDebugger(); synchronizer = null; } /** Reconnects to disconnected Virtual Machine. */ public void reconnect() throws DebuggerException { startDebugger(new ReconnectDebuggerInfo(hostName, password)); } /** * Adds breakpoint on the method specified from the RemoteDebugger. Is called from CoreBreakpoint * only. * * @return true if breakpoint is valid. */ boolean addBreakpoint(final String className, final String method) { if (synchronizer == null) return false; try { return ((Boolean) new Protector("AbstractDebugger.addBreakpoint1") { // NOI18N public Object protect() throws Exception { RemoteClass cls = remoteDebugger.findClass(className); if (cls == null) return new Integer(0); RemoteField m = cls.getMethod(method); if (m == null) return new Integer(0); String s = cls.setBreakpointMethod(m); if (s.trim().equals("")) new Integer(1); // NOI18N println(bundle.getString("CTL_Cannot_set_breakpoint") + ": " + s, ERR_OUT); return new Boolean(false); } }.throwAndWait(synchronizer, killer)) .booleanValue(); } catch (Exception e) { return false; } } /** * Removes breakpoint on the method specified from the RemoteDebugger. Is called from * CoreBreakpoint only. */ boolean removeBreakpoint(final String className, final String method) { if (synchronizer == null) return false; try { return ((Boolean) new Protector("AbstractDebugger.removeBreakpoint") { // NOI18N public Object protect() throws Exception { RemoteClass cls = remoteDebugger.findClass(className); if (cls == null) return new Boolean(false); RemoteField m = cls.getMethod(method); if (m == null) return new Boolean(false); String s = cls.clearBreakpointMethod(m); if (s.trim().equals("")) return new Boolean(true); // NOI18N println(bundle.getString("CTL_Cannot_clear_breakpoint") + ": " + s, ERR_OUT); return new Boolean(false); } }.throwAndWait(synchronizer, killer)) .booleanValue(); } catch (Exception e) { return false; } } /** Sets current line in editor. */ Line getLine(final RemoteStackFrame stackFrame) { return (Line) new Protector("AbstractDebugger.showInEditor") { // NOI18N public Object protect() throws Exception { try { return Utils.getLineForSource( stackFrame.getRemoteClass().getName(), stackFrame.getRemoteClass().getSourceFileName(), stackFrame.getLineNumber()); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath) e; } return null; } }.wait(synchronizer, killer); } /** Performs stop action. */ void stop(boolean stop, final AbstractThread thread) { /* int lastAction = null; int currentStackDepth = 0; int lastStackDepth = 0; if (!stop) { // obtain values only if they are really needed lastAction = ((ToolsThread)thread).getLastAction (); lastStackDepth = ((ToolsThread)thread).getLastStackDepth (); try { currentStackDepth = ((ToolsThread)thread).getStackDepth (); } catch (DebuggerException e) { currentStackDepth = lastStackDepth + 1; // the condition in the following 'if' will be false } } if (stop || (lastAction == ACTION_TRACE_INTO) || ((lastAction == ACTION_TRACE_OVER) && (currentStackDepth <= lastStackDepth)) || ((lastAction == ACTION_STEP_OUT) && (currentStackDepth < lastStackDepth)) ) { */ if (stop) { setLastAction(ACTION_BREAKPOINT_HIT); setDebuggerState(DEBUGGER_STOPPED); SwingUtilities.invokeLater( new Runnable() { public void run() { try { threadGroup.threadChanged(); // 'thread' could be created by Event.getThread (), but we must use a ToolsThread // created by threadChanged method (line above) AbstractThread tt = threadGroup.getThread(((ToolsThread) thread).getRemoteThread()); if (tt == null) tt = thread; // ************************************************************************************** tt.setCurrent(true); ((ToolsThread) tt).setLastAction(ACTION_BREAKPOINT_HIT); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath) e; println(bundle.getString("EXC_Debugger") + ": " + e, ERR_OUT); // NOI18N return; } updateWatches(); } }); } else { int lastAction = ((ToolsThread) thread).getLastAction(); if ((lastAction == ACTION_TRACE_OVER) || (lastAction == ACTION_STEP_OUT)) new Protector("AbstractDebugger.stepOut") { // NOI18N public Object protect() throws Exception { ((ToolsThread) thread).getRemoteThread().stepOut(); return null; } }.go(synchronizer, killer); else { new Protector("AbstractDebugger.go") { // NOI18N public Object protect() throws Exception { remoteDebugger.cont(); return null; } }.go(synchronizer, killer); } } } // innerclasses ...................................................................... private class ReconnectDebuggerInfo extends RemoteDebuggerInfo { private ReconnectDebuggerInfo(String hostName, String password) { super(hostName, password); } } private class Connector extends JPanel implements DebuggerInfoProducer { private JTextField tfHost; private JTextField tfPassword; private Connector() { setLayout(new GridBagLayout()); // setBorder (new EmptyBorder (8, 8, 8, 8)); GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(0, 0, 3, 3); c.anchor = GridBagConstraints.WEST; add(new JLabel(bundle.getString("CTL_HostName")), c); tfHost = new JTextField(host, 25); c = new GridBagConstraints(); c.gridwidth = 0; c.insets = new Insets(0, 3, 3, 0); c.fill = java.awt.GridBagConstraints.HORIZONTAL; c.weightx = 1.0; add(tfHost, c); c = new GridBagConstraints(); c.insets = new Insets(3, 0, 0, 3); c.anchor = GridBagConstraints.WEST; add(new JLabel(bundle.getString("CTL_Password")), c); tfPassword = new JTextField(25); c = new GridBagConstraints(); c.gridwidth = 0; c.fill = java.awt.GridBagConstraints.HORIZONTAL; c.weightx = 1.0; c.insets = new Insets(3, 3, 0, 0); add(tfPassword, c); c = new GridBagConstraints(); c.fill = java.awt.GridBagConstraints.BOTH; c.weighty = 1.0; JPanel p = new JPanel(); p.setPreferredSize(new Dimension(1, 1)); add(p, c); } /** Returns DebuggerInfo. */ public DebuggerInfo getDebuggerInfo() { return new RemoteDebuggerInfo(tfHost.getText(), tfPassword.getText()); } } }