Source Code Cross Referenced for JPDADebugger.java in  » IDE » DrJava » edu » rice » cs » drjava » model » debug » jpda » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE » DrJava » edu.rice.cs.drjava.model.debug.jpda 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*BEGIN_COPYRIGHT_BLOCK
0002:         *
0003:         * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
0004:         * All rights reserved.
0005:         * 
0006:         * Redistribution and use in source and binary forms, with or without
0007:         * modification, are permitted provided that the following conditions are met:
0008:         *    * Redistributions of source code must retain the above copyright
0009:         *      notice, this list of conditions and the following disclaimer.
0010:         *    * Redistributions in binary form must reproduce the above copyright
0011:         *      notice, this list of conditions and the following disclaimer in the
0012:         *      documentation and/or other materials provided with the distribution.
0013:         *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
0014:         *      names of its contributors may be used to endorse or promote products
0015:         *      derived from this software without specific prior written permission.
0016:         * 
0017:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0018:         * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0019:         * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0020:         * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0021:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0022:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0023:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0024:         * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0025:         * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0026:         * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0027:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0028:         *
0029:         * This software is Open Source Initiative approved Open Source Software.
0030:         * Open Source Initative Approved is a trademark of the Open Source Initiative.
0031:         * 
0032:         * This file is part of DrJava.  Download the current version of this project
0033:         * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
0034:         * 
0035:         * END_COPYRIGHT_BLOCK*/
0036:
0037:        package edu.rice.cs.drjava.model.debug.jpda;
0038:
0039:        import java.io.*;
0040:        import java.util.Enumeration;
0041:        import java.util.Iterator;
0042:        import java.util.LinkedList;
0043:        import java.util.List;
0044:        import java.util.Map;
0045:        import java.util.NoSuchElementException;
0046:        import java.util.Stack;
0047:        import java.util.StringTokenizer;
0048:        import java.util.Vector;
0049:
0050:        // DrJava stuff
0051:        import edu.rice.cs.util.StringOps;
0052:        import edu.rice.cs.util.UnexpectedException;
0053:        import edu.rice.cs.util.swing.Utilities;
0054:        import edu.rice.cs.drjava.model.GlobalModel;
0055:        import edu.rice.cs.drjava.model.repl.DefaultInteractionsModel;
0056:        import edu.rice.cs.drjava.model.repl.DummyInteractionsListener;
0057:        import edu.rice.cs.drjava.model.repl.InteractionsListener;
0058:        import edu.rice.cs.drjava.model.GlobalModelListener;
0059:        import edu.rice.cs.drjava.model.OpenDefinitionsDocument;
0060:        import edu.rice.cs.util.Log;
0061:        import edu.rice.cs.util.Lambda;
0062:        import edu.rice.cs.drjava.model.debug.*;
0063:
0064:        import com.sun.jdi.*;
0065:        import com.sun.jdi.connect.*;
0066:        import com.sun.jdi.request.*;
0067:        import com.sun.jdi.event.*;
0068:        import javax.swing.SwingUtilities;
0069:
0070:        /** An integrated debugger which attaches to the Interactions JVM using
0071:         *  Sun's Java Platform Debugger Architecture (JPDA/JDI) interface.
0072:         *
0073:         *  Every public method in this class throws an llegalStateException if
0074:         *  it is called while the debugger is not active, except for isAvailable,
0075:         *  isReady, and startUp.  Public methods also throw a DebugException if
0076:         *  the EventHandlerThread has caught an exception.
0077:         *
0078:         *  @version $Id: JPDADebugger.java 4255 2007-08-28 19:17:37Z mgricken $
0079:         */
0080:        public class JPDADebugger implements  Debugger {
0081:
0082:            /** A log for recording messages in a file. */
0083:            private static final Log _log = new Log("GlobalModelTest.txt",
0084:                    false);
0085:
0086:            //  private static final boolean printMessages = false;
0087:            //  private final PrintStream printStream = System.out;
0088:            private static final int OBJECT_COLLECTED_TRIES = 5;
0089:
0090:            /** Reference to DrJava's model. */
0091:            private volatile GlobalModel _model;
0092:
0093:            /** VirtualMachine of the interactions JVM. */
0094:            private volatile VirtualMachine _vm;
0095:
0096:            /** Manages all event requests in JDI. */
0097:            private volatile EventRequestManager _eventManager;
0098:
0099:            /** Vector of all current Watches. */
0100:            private final Vector<DebugWatchData> _watches = new Vector<DebugWatchData>();
0101:
0102:            /** Keeps track of any DebugActions whose classes have not yet been loaded, so that EventRequests can be created when the correct
0103:             * ClassPrepareEvent occurs.
0104:             */
0105:            private final PendingRequestManager _pendingRequestManager = new PendingRequestManager(
0106:                    this );
0107:
0108:            /** Provides a way for the JPDADebugger to communicate with the view. */
0109:            final DebugEventNotifier _notifier = new DebugEventNotifier();
0110:
0111:            /** The running ThreadReference that we are debugging. */
0112:            private volatile ThreadReference _runningThread;
0113:
0114:            /** Storage for all the threads suspended by this debugger. The "current" thread is the top one on the stack. */
0115:            private volatile RandomAccessStack _suspendedThreads;
0116:
0117:            /** A handle to the interpreterJVM that we need so we can populate the environment. */
0118:            private volatile ObjectReference _interpreterJVM;
0119:
0120:            private volatile InteractionsListener _watchListener;
0121:
0122:            /** If not null, this field holds an error caught by the EventHandlerThread. */
0123:            private volatile Throwable _eventHandlerError;
0124:
0125:            /** Builds a new JPDADebugger to debug code in the Interactions JVM, using the JPDA/JDI interfaces.
0126:             *  Does not actually connect to the interpreterJVM until startUp().
0127:             */
0128:            public JPDADebugger(GlobalModel model) {
0129:                _model = model;
0130:                _vm = null;
0131:                _eventManager = null;
0132:
0133:                _suspendedThreads = new RandomAccessStack();
0134:                _runningThread = null;
0135:                _interpreterJVM = null;
0136:                _eventHandlerError = null;
0137:
0138:                // TO DO: Replace this with an InteractionsListener,
0139:                //  since we really can't talk about SingleDisplayModel here!
0140:                _watchListener = new DummyInteractionsListener() {
0141:                    public void interactionEnded() {
0142:                        try {
0143:                            _updateWatches();
0144:                        } catch (DebugException de) {
0145:                            _log("couldn't update watches", de);
0146:                        }
0147:                    }
0148:                };
0149:            }
0150:
0151:            /** Adds a listener to this JPDADebugger.
0152:             *  @param listener a listener that reacts on events generated by the JPDADebugger
0153:             */
0154:            public void addListener(DebugListener listener) {
0155:                _notifier.addListener(listener);
0156:                _model.getBreakpointManager().addListener(listener);
0157:            }
0158:
0159:            /** Removes a listener to this JPDADebugger.
0160:             *  @param listener listener to remove
0161:             */
0162:            public void removeListener(DebugListener listener) {
0163:                _notifier.removeListener(listener);
0164:                _model.getBreakpointManager().removeListener(listener);
0165:            }
0166:
0167:            /** Accessor for the _vm field.  Called from DocumentDebugAction and this. */
0168:            VirtualMachine getVM() {
0169:                return _vm;
0170:            }
0171:
0172:            /** Logs any unexpected behavior that occurs (but which should not cause DrJava to abort).
0173:             *  @param message message to print to the log
0174:             */
0175:            private void _log(String message) {
0176:                _log.log(message);
0177:            }
0178:
0179:            /** Logs any unexpected behavior that occurs (but which should not cause DrJava to abort).
0180:             *  @param message message to print to the log
0181:             *  @param t Exception or Error being logged
0182:             */
0183:            private void _log(String message, Throwable t) {
0184:                _log.log(message, t);
0185:            }
0186:
0187:            /** Returns whether the debugger is available in this copy of DrJava.  This method does not indicate whether the 
0188:             *  debugger is ready to be used, which is indicated by isReady().
0189:             */
0190:            public boolean isAvailable() {
0191:                return true;
0192:            }
0193:
0194:            public DebugModelCallback callback() {
0195:                return new DebugModelCallback() {
0196:                };
0197:            }
0198:
0199:            /** Returns whether the debugger is currently enabled. */
0200:            public boolean isReady() {
0201:                return _vm != null;
0202:            }
0203:
0204:            /** Ensures that debugger is active.  Should be called by every public method in the debugger except for startUp().
0205:             *  Assumes lock is already held.
0206:             *  @throws IllegalStateException if debugger is not active
0207:             *  @throws DebugException if an exception was detected in the EventHandlerThread
0208:             */
0209:            private void _ensureReady() throws DebugException {
0210:                if (!isReady())
0211:                    throw new IllegalStateException("Debugger is not active.");
0212:
0213:                if (_eventHandlerError != null) {
0214:                    Throwable t = _eventHandlerError;
0215:                    _eventHandlerError = null;
0216:                    throw new DebugException(
0217:                            "Error in Debugger Event Handler: " + t);
0218:                }
0219:            }
0220:
0221:            /** Records that an error occurred in the EventHandlerThread. The next call to _ensureReady() will fail, indicating
0222:             *  that the error occurred.  Not private because EventHandlerThread accesses it.
0223:             *  @param t Error occurring in the EventHandlerThread
0224:             */
0225:            void eventHandlerError(Throwable t) {
0226:                _log("Error in EventHandlerThread: " + t);
0227:                _eventHandlerError = t;
0228:            }
0229:
0230:            /** Attaches the debugger to the Interactions JVM to prepare for debugging. */
0231:            public synchronized void startUp() throws DebugException {
0232:                if (!isReady()) {
0233:                    _eventHandlerError = null;
0234:                    // check if all open documents are in sync
0235:                    for (OpenDefinitionsDocument doc : _model
0236:                            .getOpenDefinitionsDocuments()) {
0237:                        doc.checkIfClassFileInSync();
0238:                    }
0239:
0240:                    try {
0241:                        _attachToVM();
0242:                    } catch (DebugException e1) { // We sometimes see ConnectExceptions stating that the connection was refused
0243:                        try {
0244:                            try {
0245:                                Thread.sleep(100);
0246:                            } // Give any temporary connection problems a chance to resolve
0247:                            catch (InterruptedException e) { /* ignore */
0248:                            }
0249:                            _attachToVM();
0250:                            System.out
0251:                                    .println("Two attempts required for debugger to attach to slave JVM");
0252:                        } catch (DebugException e2) {
0253:                            try {
0254:                                Thread.sleep(100);
0255:                            } // Give any temporary connection problems a chance to resolve
0256:                            catch (InterruptedException e) { /* ignore */
0257:                            }
0258:                            _attachToVM();
0259:                            System.out
0260:                                    .println("Three attempts required for debugger to attach to slave JVM");
0261:                        } // if we throw another exception, three strikes and we're out
0262:                    }
0263:
0264:                    // Listen for events when threads die
0265:                    ThreadDeathRequest tdr = _eventManager
0266:                            .createThreadDeathRequest();
0267:                    tdr.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
0268:                    tdr.enable();
0269:
0270:                    // Listen for events from JPDA in a new thread
0271:                    EventHandlerThread eventHandler = new EventHandlerThread(
0272:                            this , _vm);
0273:                    eventHandler.start();
0274:
0275:                    /* Move the following command to the end of the event queue so that it is done outside outside the readLock
0276:                     * held when this method is called from an InteractionsListener. */
0277:                    SwingUtilities.invokeLater(new Runnable() {
0278:                        public void run() {
0279:                            _model.getInteractionsModel().addListener(
0280:                                    _watchListener);
0281:                        }
0282:                    });
0283:
0284:                    // re-set breakpoints that have already been set
0285:                    Vector<Breakpoint> oldBreakpoints = new Vector<Breakpoint>(
0286:                            _model.getBreakpointManager().getRegions());
0287:                    _model.getBreakpointManager().clearRegions();
0288:                    for (int i = 0; i < oldBreakpoints.size(); i++) {
0289:                        Breakpoint bp = oldBreakpoints.get(i);
0290:                        setBreakpoint(new JPDABreakpoint(bp.getDocument(), bp
0291:                                .getOffset(), bp.getLineNumber(), bp
0292:                                .isEnabled(), this ));
0293:                    }
0294:                }
0295:
0296:                else
0297:                    // Already started
0298:                    throw new IllegalStateException(
0299:                            "Debugger has already been started.");
0300:            }
0301:
0302:            /** Handles the details of attaching to the interpreterJVM. Assume lock is already held. */
0303:            private void _attachToVM() throws DebugException {
0304:                // Blocks until the interpreter has registered if hasn't already.  Blocks all synchronized methods in this class.
0305:                _model.waitForInterpreter();
0306:
0307:                // Get the connector
0308:                AttachingConnector connector = _getAttachingConnector();
0309:
0310:                // Try to connect on our debug port
0311:                Map<String, Connector.Argument> args = connector
0312:                        .defaultArguments();
0313:                Connector.Argument port = args.get("port");
0314:                Connector.Argument host = args.get("hostname");
0315:                try {
0316:                    int debugPort = _model.getDebugPort();
0317:                    port.setValue("" + debugPort);
0318:                    host.setValue("127.0.0.1"); // necessary if hostname can't be resolved
0319:                    _vm = connector.attach(args);
0320:                    _eventManager = _vm.eventRequestManager();
0321:                } catch (Exception e) {
0322:                    throw new DebugException("Could not connect to VM: " + e);
0323:                }
0324:
0325:                _interpreterJVM = _getInterpreterJVMRef();
0326:            }
0327:
0328:            /** Returns an attaching connector to use for connecting to the interpreter JVM.  Assumes lock is already held. */
0329:            private AttachingConnector _getAttachingConnector()
0330:                    throws DebugException {
0331:                VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
0332:                List<AttachingConnector> connectors = vmm.attachingConnectors();
0333:                AttachingConnector connector = null;
0334:                for (AttachingConnector conn : connectors) {
0335:                    if (conn.name().equals("com.sun.jdi.SocketAttach"))
0336:                        connector = conn;
0337:                }
0338:                if (connector == null)
0339:                    throw new DebugException(
0340:                            "Could not find an AttachingConnector!");
0341:                return connector;
0342:            }
0343:
0344:            /** Returns an ObjectReference to the singleton instance of the InterpreterJVM class in the virtual machine being 
0345:             *  debugged. This is used to mainupulate interpreters at breakpoints.  Assumes lock is already held.
0346:             */
0347:            private ObjectReference _getInterpreterJVMRef()
0348:                    throws DebugException {
0349:                String className = "edu.rice.cs.drjava.model.repl.newjvm.InterpreterJVM";
0350:                List<ReferenceType> referenceTypes = _vm
0351:                        .classesByName(className); // Added parameterization <ReferenceType>. JDK 1.5 will eliminate this warning
0352:                if (referenceTypes.size() > 0) {
0353:                    ReferenceType rt = referenceTypes.get(0);
0354:                    Field field = rt.fieldByName("ONLY");
0355:                    if (field == null)
0356:                        throw new DebugException("Unable to get ONLY field");
0357:                    return (ObjectReference) rt.getValue(field);
0358:                } else
0359:                    throw new DebugException(
0360:                            "Could not get a reference to interpreterJVM");
0361:            }
0362:
0363:            /** Disconnects the debugger from the Interactions JVM and cleans up any state.
0364:             *  @throws IllegalStateException if debugger is not ready
0365:             */
0366:            public synchronized void shutdown() {
0367:                if (isReady()) {
0368:                    Runnable command = new Runnable() {
0369:                        public void run() {
0370:                            _model.getInteractionsModel().removeListener(
0371:                                    _watchListener);
0372:                        }
0373:                    };
0374:
0375:                    /* Use SwingUtilities.invokeLater rather than Utilities.invokeLater because we want to defer executing this
0376:                     * code after pending events (that may involve the _watchListener) */
0377:                    SwingUtilities.invokeLater(command);
0378:
0379:                    _removeAllDebugInterpreters();
0380:
0381:                    try {
0382:                        _vm.dispose();
0383:                    } catch (VMDisconnectedException vmde) {
0384:                        //VM was shutdown prematurely
0385:                    } finally {
0386:                        _model.getInteractionsModel().setToDefaultInterpreter();
0387:                        _vm = null;
0388:                        _suspendedThreads = new RandomAccessStack();
0389:                        _eventManager = null;
0390:                        _runningThread = null;
0391:                        try {
0392:                            _updateWatches();
0393:                        } catch (DebugException de) {
0394:                            // Couldn't remove breakpoints/watches
0395:                            _log("Could not remove breakpoints/watches or update watches: "
0396:                                    + de);
0397:                        }
0398:                    }
0399:                }
0400:            }
0401:
0402:            /** Returns the current EventRequestManager from JDI, or null if startUp() has not been called. */
0403:            EventRequestManager getEventRequestManager() {
0404:                return _eventManager;
0405:            }
0406:
0407:            /** Returns the pending request manager used by the debugger. */
0408:            PendingRequestManager getPendingRequestManager() {
0409:                return _pendingRequestManager;
0410:            }
0411:
0412:            /**
0413:             * Sets the debugger's currently active thread.
0414:             * This method assumes that the given thread is already suspended.
0415:             * Returns true if this actually changed the suspended thread
0416:             * by pushing it onto the stack of suspended threads.  Returns
0417:             * false if this thread was already selected.
0418:             *
0419:             * The return value fixes a bug that occurs if the user steps
0420:             * into a breakpoint.
0421:             *
0422:             * @throws IllegalArgumentException if thread is not suspended.
0423:             */
0424:            synchronized boolean setCurrentThread(ThreadReference thread) {
0425:                if (!thread.isSuspended()) {
0426:                    throw new IllegalArgumentException(
0427:                            "Thread must be suspended to set as current.  Given: "
0428:                                    + thread);
0429:                }
0430:
0431:                try {
0432:                    if ((_suspendedThreads.isEmpty() || !_suspendedThreads
0433:                            .contains(thread.uniqueID()))
0434:                            && (thread.frameCount() > 0)) {
0435:                        _suspendedThreads.push(thread);
0436:                        return true;
0437:                    } else
0438:                        return false;
0439:                } catch (IncompatibleThreadStateException itse) {
0440:                    // requesting stack frames should be fine, since the thread must be
0441:                    // suspended or frameCount() is not called
0442:                    throw new UnexpectedException(itse);
0443:                }
0444:            }
0445:
0446:            /** Sets the notion of current thread to the one contained in threadData.  The thread must be suspended. (Note: the
0447:             *  intention is for this method to suspend the thread if necessary, but this is not yet implemented.  The catch is
0448:             *  that any manually suspended threads won't cooperate with the debug interpreters; the thread must be suspended by
0449:             *  a breakpoint or step.)
0450:             *  @param threadData Thread to set as current
0451:             *  @throws IllegalStateException if debugger is not ready
0452:             *  @throws IllegalArgumentException if threadData is null or not suspended
0453:             */
0454:            public synchronized void setCurrentThread(DebugThreadData threadData)
0455:                    throws DebugException {
0456:                _ensureReady();
0457:
0458:                if (threadData == null) {
0459:                    throw new IllegalArgumentException(
0460:                            "Cannot set current thread to null.");
0461:                }
0462:
0463:                ThreadReference threadRef = _getThreadFromDebugThreadData(threadData);
0464:
0465:                // Special case to avoid overhead of scrollToSource() if we
0466:                // are selecting the thread we have already selected currently
0467:
0468:                // Currently disabled, so we will always scroll to source, even if the
0469:                // thread is already selected.
0470:                //    if ( _suspendedThreads.size() > 0 &&
0471:                //       _suspendedThreads.peek().uniqueID() == threadRef.uniqueID() ) {
0472:                //      return;
0473:                //    }
0474:
0475:                // if we switch to a currently suspended thread, we need to remove
0476:                // it from the stack and put it on the top
0477:                if (_suspendedThreads.contains(threadRef.uniqueID()))
0478:                    _suspendedThreads.remove(threadRef.uniqueID());
0479:
0480:                if (!threadRef.isSuspended()) {
0481:                    throw new IllegalArgumentException(
0482:                            "Given thread must be suspended.");
0483:                    //       threadRef.suspend();
0484:                    //
0485:                    //       try{
0486:                    //         if ( threadRef.frameCount() <= 0 ) {
0487:                    //           printMessage(threadRef.name() + " could not be suspended. It had no stackframes.");
0488:                    //           _suspendedThreads.push(threadRef);
0489:                    //           resume();
0490:                    //           return;
0491:                    //         }
0492:                    //       }
0493:                    //       catch(IncompatibleThreadStateException ex) {
0494:                    //         throw new UnexpectedException(ex);
0495:                    //       }
0496:                    //
0497:                    //       //
0498:                    //       // Step now so that we can get an interpreter,
0499:                    //       // do not notify (hence the false argument)
0500:                    //       _stepHelper(StepRequest.STEP_OVER, false);
0501:                    //return;
0502:                }
0503:
0504:                _suspendedThreads.push(threadRef);
0505:
0506:                try {
0507:                    if (threadRef.frameCount() <= 0) {
0508:                        printMessage(threadRef.name()
0509:                                + " could not be suspended since it has no stackframes.");
0510:                        resume();
0511:                        return;
0512:                    }
0513:                } catch (IncompatibleThreadStateException e) {
0514:                    throw new DebugException("Could not suspend thread: " + e);
0515:                }
0516:
0517:                // Activate the debug interpreter for interacting with this thread
0518:                _switchToInterpreterForThreadReference(threadRef);
0519:                _switchToSuspendedThread();
0520:                printMessage("The current thread has changed.");
0521:            }
0522:
0523:            /** Returns the currently selected thread for the debugger.  */
0524:            ThreadReference getCurrentThread() {
0525:                // Current thread is the top one on the stack
0526:                return _suspendedThreads.peek();
0527:            }
0528:
0529:            /** Returns the suspended thread at the current index of the stack.
0530:             *  @param i index into the stack of suspended threads
0531:             */
0532:            ThreadReference getThreadAt(int i) {
0533:                return _suspendedThreads.peekAt(i);
0534:            }
0535:
0536:            /** Returns the running thread currently tracked by the debugger. */
0537:            ThreadReference getCurrentRunningThread() {
0538:                return _runningThread;
0539:            }
0540:
0541:            /** Returns whether the debugger currently has any suspended threads. */
0542:            public synchronized boolean hasSuspendedThreads()
0543:                    throws DebugException {
0544:                if (!isReady())
0545:                    return false;
0546:                return _suspendedThreads.size() > 0;
0547:            }
0548:
0549:            /** Returns whether the debugger's current thread is suspended. */
0550:            public synchronized boolean isCurrentThreadSuspended()
0551:                    throws DebugException {
0552:                if (!isReady())
0553:                    return false;
0554:                return hasSuspendedThreads() && !hasRunningThread();
0555:            }
0556:
0557:            /** Returns whether the thread the debugger is tracking is now running. */
0558:            public synchronized boolean hasRunningThread()
0559:                    throws DebugException {
0560:                if (!isReady())
0561:                    return false;
0562:                return _runningThread != null;
0563:            }
0564:
0565:            /** Returns a Vector with all the loaded ReferenceTypes for the given class name (empty if the class could not be 
0566:             *  found).  Makes no attempt to load the class if it is not already loaded.
0567:             *  <p>
0568:             *  If custom class loaders are in use, multiple copies of the class may be loaded, so all are returned.
0569:             */
0570:            Vector<ReferenceType> getReferenceTypes(String className) {
0571:                return getReferenceTypes(className, DebugAction.ANY_LINE);
0572:            }
0573:
0574:            /** Returns a Vector with the loaded ReferenceTypes for the given class name
0575:             * (empty if the class could not be found).  Makes no attempt to load the
0576:             * class if it is not already loaded.  If the lineNumber is not
0577:             * DebugAction.ANY_LINE, this method ensures that the returned ReferenceTypes
0578:             * contain the given lineNumber, searching through inner classes if necessary.
0579:             * If no inner classes contain the line number, an empty Vector is returned.
0580:             * <p>
0581:             * If custom class loaders are in use, multiple copies of the class
0582:             * may be loaded, so all are returned.
0583:             */
0584:            synchronized Vector<ReferenceType> getReferenceTypes(
0585:                    String className, int lineNumber) {
0586:                // Get all classes that match this name
0587:                List<ReferenceType> classes;
0588:
0589:                try {
0590:                    classes = _vm.classesByName(className);
0591:                } catch (VMDisconnectedException vmde) {
0592:                    // We're quitting, return empty Vector.
0593:                    return new Vector<ReferenceType>();
0594:                }
0595:
0596:                // Return each valid reference type
0597:                Vector<ReferenceType> refTypes = new Vector<ReferenceType>();
0598:                ReferenceType ref;
0599:                for (int i = 0; i < classes.size(); i++) {
0600:                    ref = classes.get(i);
0601:
0602:                    if (lineNumber != DebugAction.ANY_LINE) {
0603:                        List<Location> lines = new LinkedList<Location>();
0604:                        try {
0605:                            lines = ref.locationsOfLine(lineNumber); // JDK 1.5 will eliminate this type warning
0606:                        } catch (AbsentInformationException aie) {
0607:                            // try looking in inner classes
0608:                        } catch (ClassNotPreparedException cnpe) {
0609:                            // try the next class, maybe loaded by a different classloader
0610:                            continue;
0611:                        }
0612:                        // If lines.size > 0, lineNumber was found in ref
0613:                        if (lines.size() == 0) {
0614:                            // The ReferenceType might be in an inner class, so
0615:                            //  look for locationsOfLine for nestedTypes
0616:                            List<ReferenceType> innerRefs = ref.nestedTypes(); // Added parameterization <ReferenceType>. JDK 1.5 will eliminate this type warning
0617:                            ref = null;
0618:                            for (int j = 0; j < innerRefs.size(); j++) {
0619:                                try {
0620:                                    ReferenceType currRef = innerRefs.get(j);
0621:                                    lines = currRef.locationsOfLine(lineNumber); // JDK 1.5 will eliminate this type warning
0622:                                    if (lines.size() > 0) {
0623:                                        ref = currRef;
0624:                                        break;
0625:                                    }
0626:                                } catch (AbsentInformationException aie) {
0627:                                    // skipping this inner class, look in another
0628:                                } catch (ClassNotPreparedException cnpe) {
0629:                                    // skipping this inner class, look in another
0630:                                }
0631:                            }
0632:                        }
0633:                    }
0634:                    if ((ref != null) && ref.isPrepared()) {
0635:                        refTypes.add(ref);
0636:                    }
0637:                }
0638:                return refTypes;
0639:            }
0640:
0641:            /** Assumes lock is already held.
0642:             *  @return The thread in the virtual machine with name d.uniqueID()
0643:             *  @throws NoSuchElementException if the thread could not be found
0644:             */
0645:            private ThreadReference _getThreadFromDebugThreadData(
0646:                    DebugThreadData d) throws NoSuchElementException {
0647:                List<ThreadReference> threads = _vm.allThreads();
0648:                Iterator<ThreadReference> iterator = threads.iterator();
0649:                while (iterator.hasNext()) {
0650:                    ThreadReference threadRef = iterator.next();
0651:                    if (threadRef.uniqueID() == d.getUniqueID()) {
0652:                        return threadRef;
0653:                    }
0654:                }
0655:                // Thread not found
0656:                throw new NoSuchElementException("Thread " + d.getName()
0657:                        + " not found in virtual machine!");
0658:            }
0659:
0660:            /**
0661:             * Suspends all the currently running threads in the virtual machine.
0662:             *
0663:             * Not currently in use/available, since it is incompatible with
0664:             * the debug interpreters.
0665:             *
0666:            public synchronized void suspendAll() {
0667:              _ensureReady();
0668:              List threads = _vm.allThreads();
0669:              Iterator iterator = threads.iterator();
0670:              ThreadReference threadRef = null;
0671:
0672:              while(iterator.hasNext()) {
0673:                threadRef = (ThreadReference)iterator.next();
0674:
0675:                if ( !threadRef.isSuspended() ) {
0676:                  threadRef.suspend();
0677:                  _suspendedThreads.push(threadRef);
0678:                }
0679:              }
0680:              _runningThread = null;
0681:            }*/
0682:
0683:            /**
0684:             * Suspends execution of the thread referenced by threadData.
0685:             *
0686:             * Not in use/available, since it is currently incompatible with the
0687:             * debug interpreters.  (Can't execute code in a suspended thread unless
0688:             * it was suspended with a breakpoint/step.)
0689:             *
0690:            public synchronized void suspend(DebugThreadData threadData)
0691:              throws DebugException
0692:            {
0693:              _ensureReady();
0694:              // setCurrentThread suspends if necessary
0695:              setCurrentThread(threadData);
0696:              _runningThread = null;
0697:            }*/
0698:
0699:            /** Resumes the thread currently being debugged without removing the debug interpreter or switching to the next 
0700:             *  suspended thread.  Assumes lock is already held.
0701:             */
0702:            private void _resumeFromStep() throws DebugException {
0703:                _resumeHelper(true);
0704:            }
0705:
0706:            /** Resumes the thread currently being debugged, copying back all variables from the current debug interpreter. */
0707:            public synchronized void resume() throws DebugException {
0708:                _ensureReady();
0709:                _resumeHelper(false);
0710:            }
0711:
0712:            /** Resumes execution of the currently suspended thread.  Assumes lock is already held.
0713:             *  @param fromStep Whether to copy back the variables from the current debug interpreter and switch to the next
0714:             *  suspended thread.
0715:             */
0716:            private void _resumeHelper(boolean fromStep) throws DebugException {
0717:                try {
0718:                    ThreadReference thread = _suspendedThreads.pop();
0719:
0720:                    _log.log("In resumeThread()");
0721:                    _resumeThread(thread, fromStep);
0722:                } catch (NoSuchElementException e) {
0723:                    throw new DebugException("No thread to resume.");
0724:                }
0725:            }
0726:
0727:            /** Resumes the given thread, copying back any variables from its associated debug interpreter.
0728:             * @param threadData Thread to resume
0729:             */
0730:            public synchronized void resume(DebugThreadData threadData)
0731:                    throws DebugException {
0732:                _ensureReady();
0733:                ThreadReference thread = _suspendedThreads.remove(threadData
0734:                        .getUniqueID());
0735:                _resumeThread(thread, false);
0736:            }
0737:
0738:            /** Resumes the given thread, only copying variables from its debug interpreter if shouldCopyBack is true.  Assumes
0739:             * lock on this is already held.
0740:             * @param thread Thread to resume
0741:             * @param fromStep Whether to copy back the variables from
0742:             * the current debug interpreter and switch to the next
0743:             * suspended thread.
0744:             * @throws IllegalArgumentException if thread is null
0745:             */
0746:            private void _resumeThread(ThreadReference thread, boolean fromStep)
0747:                    throws DebugException {
0748:                if (thread == null) {
0749:                    throw new IllegalArgumentException(
0750:                            "Cannot resume a null thread");
0751:                }
0752:
0753:                int suspendCount = thread.suspendCount();
0754:                _log.log("Getting suspendCount = " + suspendCount);
0755:
0756:                _runningThread = thread;
0757:                if (!fromStep) {
0758:                    // Copy variables back into the thread
0759:                    _copyVariablesFromInterpreter();
0760:                    _updateWatches();
0761:                }
0762:                try {
0763:                    _removeCurrentDebugInterpreter(fromStep);
0764:                    currThreadResumed();
0765:                } catch (DebugException e) {
0766:                    throw new UnexpectedException(e);
0767:                }
0768:
0769:                // Must resume the correct number of times
0770:                for (int i = suspendCount; i > 0; i--)
0771:                    thread.resume();
0772:
0773:                // Notify listeners of a resume
0774:
0775:                // Switch to next suspended thread, if any
0776:                if (!fromStep && !_suspendedThreads.isEmpty())
0777:                    _switchToSuspendedThread();
0778:            }
0779:
0780:            /** Steps the execution of the currently loaded document. */
0781:            public synchronized void step(StepType type) throws DebugException {
0782:                _ensureReady();
0783:                _stepHelper(type, true);
0784:            }
0785:
0786:            /** Performs a step in the currently suspended thread, only generating a step event if shouldNotify if true.  Assumes
0787:             *  that lock is already held.
0788:             *  @param type The type of step to perform
0789:             *  @param shouldNotify Whether to generate a step event
0790:             */
0791:            private void _stepHelper(StepType type, boolean shouldNotify)
0792:                    throws DebugException {
0793:                if (_suspendedThreads.size() <= 0 || _runningThread != null) {
0794:                    throw new IllegalStateException(
0795:                            "Cannot step if the current thread is not suspended.");
0796:                }
0797:
0798:                _log.log(this  + "is About to peek ...");
0799:
0800:                ThreadReference thread = _suspendedThreads.peek();
0801:                _log.log(this  + "is Stepping " + thread.toString());
0802:
0803:                // Copy the variables back into the thread from the appropriate interpreter.
0804:                // We do this before stepping since DrJava will hang if you try to copy back
0805:                // variables after creating the step request.
0806:                _runningThread = thread;
0807:                _copyVariablesFromInterpreter();
0808:
0809:                _log.log(this  + " is Deleting pending requests ...");
0810:
0811:                // If there's already a step request for the current thread, delete
0812:                //  it first
0813:                List<StepRequest> steps = _eventManager.stepRequests();
0814:                for (int i = 0; i < steps.size(); i++) {
0815:                    StepRequest step = steps.get(i);
0816:                    if (step.thread().equals(thread)) {
0817:                        _eventManager.deleteEventRequest(step);
0818:                        break;
0819:                    }
0820:                }
0821:
0822:                _log.log(this  + " Issued step request");
0823:                int stepFlag = Integer.MIN_VALUE; // should always be changed, but compiler doesn't check that
0824:                switch (type) {
0825:                case STEP_INTO:
0826:                    stepFlag = StepRequest.STEP_INTO;
0827:                    break;
0828:                case STEP_OVER:
0829:                    stepFlag = StepRequest.STEP_OVER;
0830:                    break;
0831:                case STEP_OUT:
0832:                    stepFlag = StepRequest.STEP_OUT;
0833:                    break;
0834:                }
0835:                new Step(this , StepRequest.STEP_LINE, stepFlag);
0836:                if (shouldNotify)
0837:                    notifyStepRequested();
0838:                _log.log(this  + " About to resume");
0839:                _resumeFromStep();
0840:            }
0841:
0842:            /** Adds a watch on the given field or variable.
0843:             * @param field the name of the field we will watch
0844:             */
0845:            public synchronized void addWatch(String field)
0846:                    throws DebugException {
0847:                // _ensureReady();
0848:
0849:                final DebugWatchData w = new DebugWatchData(field);
0850:                _watches.add(w);
0851:                _updateWatches();
0852:
0853:                Utilities.invokeLater(new Runnable() {
0854:                    public void run() {
0855:                        _notifier.watchSet(w);
0856:                    }
0857:                });
0858:            }
0859:
0860:            /**
0861:             * Removes any watches on the given field or variable.
0862:             * Has no effect if the given field is not being watched.
0863:             * @param field the name of the field we will watch
0864:             */
0865:            public synchronized void removeWatch(String field)
0866:                    throws DebugException {
0867:                // _ensureReady();
0868:
0869:                for (int i = 0; i < _watches.size(); i++) {
0870:                    final DebugWatchData watch = _watches.get(i);
0871:                    if (watch.getName().equals(field)) {
0872:                        _watches.remove(i);
0873:                        Utilities.invokeLater(new Runnable() {
0874:                            public void run() {
0875:                                _notifier.watchRemoved(watch);
0876:                            }
0877:                        });
0878:                    }
0879:                }
0880:            }
0881:
0882:            /**
0883:             * Removes the watch at the given index.
0884:             * @param index Index of the watch to remove
0885:             */
0886:            public synchronized void removeWatch(int index)
0887:                    throws DebugException {
0888:                // _ensureReady();
0889:
0890:                if (index < _watches.size()) {
0891:                    final DebugWatchData watch = _watches.get(index);
0892:                    _watches.remove(index);
0893:                    Utilities.invokeLater(new Runnable() {
0894:                        public void run() {
0895:                            _notifier.watchRemoved(watch);
0896:                        }
0897:                    });
0898:                }
0899:            }
0900:
0901:            /**
0902:             * Removes all watches on existing fields and variables.
0903:             */
0904:            public synchronized void removeAllWatches() throws DebugException {
0905:                // _ensureReady();
0906:
0907:                while (_watches.size() > 0) {
0908:                    removeWatch(_watches.get(0).getName());
0909:                }
0910:            }
0911:
0912:            /**
0913:             * Enable or disable the specified breakpoint.
0914:             * @param breakpoint breakpoint to change
0915:             */
0916:            public synchronized void notifyBreakpointChange(
0917:                    Breakpoint breakpoint) {
0918:                _model.getBreakpointManager().changeRegion(breakpoint,
0919:                        new Lambda<Object, Breakpoint>() {
0920:                            public Object apply(Breakpoint bp) {
0921:                                // change has already been made, just notify all listeners
0922:                                return null;
0923:                            }
0924:                        });
0925:            }
0926:
0927:            /** Toggles whether a breakpoint is set at the given line in the given document.
0928:             *  @param doc  Document in which to set or remove the breakpoint
0929:             *  @param offset  Start offset on the line to set the breakpoint
0930:             *  @param lineNum  Line on which to set or remove the breakpoint, >=1
0931:             *  @param isEnabled  {@code true} if this breakpoint should be enabled
0932:             */
0933:            public synchronized void toggleBreakpoint(
0934:                    OpenDefinitionsDocument doc, int offset, int lineNum,
0935:                    boolean isEnabled) throws DebugException {
0936:                Breakpoint breakpoint = _model.getBreakpointManager()
0937:                        .getRegionAt(doc, offset);
0938:
0939:                if (breakpoint == null) {
0940:                    if (doc.getLineStartPos(offset) == doc
0941:                            .getLineEndPos(offset)) {
0942:                        Utilities
0943:                                .show("Cannot set a breakpoint on an empty line.");
0944:                    } else {
0945:                        try {
0946:                            setBreakpoint(new JPDABreakpoint(doc, offset,
0947:                                    lineNum, isEnabled, this ));
0948:                        } catch (LineNotExecutableException lnee) {
0949:                            Utilities.show(lnee.getMessage());
0950:                        }
0951:                    }
0952:                } else
0953:                    _model.getBreakpointManager().removeRegion(breakpoint);
0954:            }
0955:
0956:            /** Sets a breakpoint.
0957:             *  @param breakpoint The new breakpoint to set
0958:             */
0959:            public synchronized void setBreakpoint(final Breakpoint breakpoint)
0960:                    throws DebugException {
0961:                breakpoint.getDocument().checkIfClassFileInSync();
0962:
0963:                _model.getBreakpointManager().addRegion(breakpoint);
0964:            }
0965:
0966:            /** Removes a breakpoint. Called from toggleBreakpoint -- even with BPs that are not active.
0967:             *  @param breakpoint The breakpoint to remove.
0968:             */
0969:            public synchronized void removeBreakpoint(Breakpoint bp)
0970:                    throws DebugException {
0971:                if (!(bp instanceof  JPDABreakpoint)) {
0972:                    throw new IllegalArgumentException("Unsupported breakpoint");
0973:                } else {
0974:                    JPDABreakpoint breakpoint = (JPDABreakpoint) bp;
0975:                    Vector<BreakpointRequest> requests = breakpoint
0976:                            .getRequests();
0977:                    if (requests.size() > 0 && _eventManager != null) {
0978:                        // Remove all event requests for this breakpoint
0979:                        try {
0980:                            for (int i = 0; i < requests.size(); i++) {
0981:                                _eventManager.deleteEventRequest(requests
0982:                                        .get(i));
0983:                            }
0984:                        } catch (VMMismatchException vme) {
0985:                            // Not associated with this VM; probably from a previous session.
0986:                            // Ignore and make sure it gets removed from the document.
0987:                            _log("VMMismatch when removing breakpoint.", vme);
0988:                        } catch (VMDisconnectedException vmde) {
0989:                            // The VM has already disconnected for some reason
0990:                            // Ignore it and make sure the breakpoint gets removed from the document
0991:                            _log("VMDisconnected when removing breakpoint.",
0992:                                    vmde);
0993:                        }
0994:                    }
0995:
0996:                    // Always remove from pending request, since it's always there
0997:                    _pendingRequestManager.removePendingRequest(breakpoint);
0998:                }
0999:            }
1000:
1001:            /** Called when a breakpoint is reached.  The Breakpoint object itself should be stored in the 
1002:             *  "debugAction" property on the request.
1003:             *  @param request The BreakPointRequest reached by the debugger
1004:             */
1005:            synchronized void reachedBreakpoint(BreakpointRequest request) {
1006:                //    Utilities.showDebug("JPDADebugger.reachedBreakPoint(" + request + ") called");
1007:                Object property = request.getProperty("debugAction");
1008:                if ((property != null) && (property instanceof  JPDABreakpoint)) {
1009:                    final JPDABreakpoint breakpoint = (JPDABreakpoint) property;
1010:                    printMessage("Breakpoint hit in class "
1011:                            + breakpoint.getClassName() + "  [line "
1012:                            + breakpoint.getLineNumber() + "]");
1013:
1014:                    Utilities.invokeLater(new Runnable() {
1015:                        public void run() {
1016:                            _notifier.breakpointReached(breakpoint);
1017:                        }
1018:                    });
1019:                } else {
1020:                    // A breakpoint we didn't set??
1021:                    _log("Reached a breakpoint without a debugAction property: "
1022:                            + request);
1023:                }
1024:            }
1025:
1026:            /** Returns all currently watched fields and variables. No synchronization required because _watches is final. */
1027:            public Vector<DebugWatchData> getWatches() throws DebugException {
1028:                //_ensureReady();
1029:                return _watches;
1030:            }
1031:
1032:            /** Returns a list of all threads being tracked by the debugger. Does not return any threads known to be dead. */
1033:            public synchronized Vector<DebugThreadData> getCurrentThreadData()
1034:                    throws DebugException {
1035:                if (!isReady()) {
1036:                    return new Vector<DebugThreadData>();
1037:                }
1038:                List<ThreadReference> listThreads; // Add parameterization <ThreadReference> to listThreads.
1039:                try {
1040:                    listThreads = _vm.allThreads();
1041:                } catch (VMDisconnectedException vmde) {
1042:                    // We're quitting, just pass back an empty Vector
1043:                    return new Vector<DebugThreadData>();
1044:                }
1045:
1046:                // get an iterator from the list returned by _vm.allThreads()
1047:                Iterator<ThreadReference> iter = listThreads.iterator(); // Added parameterization <ThreadReference>.
1048:                Vector<DebugThreadData> threads = new Vector<DebugThreadData>();
1049:                while (iter.hasNext()) {
1050:                    try {
1051:                        threads.add(new JPDAThreadData(iter.next()));
1052:                    } catch (ObjectCollectedException e) {
1053:                        // this thread just died, we don't want to list it anyway
1054:                    }
1055:                }
1056:                return threads;
1057:            }
1058:
1059:            /**
1060:             * Returns a Vector of DebugStackData for the current suspended thread.
1061:             * @throws DebugException if the current thread is running or there
1062:             * are no suspended threads
1063:             * TO DO: Config option for hiding DrJava subset of stack trace
1064:             */
1065:            public synchronized Vector<DebugStackData> getCurrentStackFrameData()
1066:                    throws DebugException {
1067:                if (!isReady())
1068:                    return new Vector<DebugStackData>();
1069:
1070:                if (_runningThread != null || _suspendedThreads.size() <= 0) {
1071:                    throw new DebugException(
1072:                            "No suspended thread to obtain stack frames.");
1073:                }
1074:
1075:                try {
1076:                    ThreadReference thread = _suspendedThreads.peek();
1077:                    Iterator<StackFrame> iter = thread.frames().iterator(); // Added <StackFrame> parameterization; warning will go away in JDK 1.5
1078:                    Vector<DebugStackData> frames = new Vector<DebugStackData>();
1079:                    while (iter.hasNext()) {
1080:                        frames.add(new JPDAStackData(iter.next()));
1081:                    }
1082:                    return frames;
1083:                } catch (IncompatibleThreadStateException itse) {
1084:                    _log("Unable to obtain stack frame.", itse);
1085:                    return new Vector<DebugStackData>();
1086:                } catch (VMDisconnectedException vmde) {
1087:                    _log(
1088:                            "VMDisconnected when getting the current stack frame data.",
1089:                            vmde);
1090:                    return new Vector<DebugStackData>();
1091:                } catch (InvalidStackFrameException isfe) {
1092:                    _log("The stack frame requested is invalid.", isfe);
1093:                    return new Vector<DebugStackData>();
1094:                }
1095:            }
1096:
1097:            /** Takes the location of event e, opens the document corresponding to its class and centers the definition pane's
1098:             * view on the appropriate line number.  Assumes lock on this is already held.
1099:             * @param e LocatableEvent containing location to display
1100:             */
1101:            private void scrollToSource(LocatableEvent e) {
1102:                Location location = e.location();
1103:
1104:                // First see if doc is stored
1105:                EventRequest request = e.request();
1106:                Object docProp = request.getProperty("document");
1107:                if ((docProp != null)
1108:                        && (docProp instanceof  OpenDefinitionsDocument)) {
1109:                    openAndScroll((OpenDefinitionsDocument) docProp, location,
1110:                            true);
1111:                } else
1112:                    scrollToSource(location);
1113:            }
1114:
1115:            /** Scroll to the location specified by location  Assumes lock on this is already held */
1116:            private void scrollToSource(Location location) {
1117:                scrollToSource(location, true);
1118:            }
1119:
1120:            /** Return the document associated with this location. A document is preloaded when a debugger step is
1121:             * made to avoid the deadlock described in [ 1696060 ] Debugger Infinite Loop.
1122:             */
1123:            public OpenDefinitionsDocument preloadDocument(Location location) {
1124:                OpenDefinitionsDocument doc = null;
1125:
1126:                // No stored doc, look on the source root set (later, also the sourcepath)
1127:                ReferenceType rt = location.declaringType();
1128:                String fileName;
1129:                try {
1130:                    fileName = getPackageDir(rt.name()) + rt.sourceName();
1131:                } catch (AbsentInformationException aie) {
1132:                    // Don't know real source name:
1133:                    //   assume source name is same as file name
1134:                    String className = rt.name();
1135:                    String ps = System.getProperty("file.separator");
1136:                    // replace periods with the System's file separator
1137:                    className = StringOps.replace(className, ".", ps);
1138:
1139:                    // crop off the $ if there is one and anything after it
1140:                    int indexOfDollar = className.indexOf('$');
1141:                    if (indexOfDollar > -1) {
1142:                        className = className.substring(0, indexOfDollar);
1143:                    }
1144:
1145:                    fileName = className + ".java";
1146:                }
1147:
1148:                // Check source root set (open files)
1149:                File f = _model.getSourceFile(fileName);
1150:                if (f != null) {
1151:                    // Get a document for this file, forcing it to open
1152:                    try {
1153:                        doc = _model.getDocumentForFile(f);
1154:                    } catch (IOException ioe) {
1155:                        // No doc, so don't notify listener
1156:                    }
1157:                }
1158:                return doc;
1159:            }
1160:
1161:            /** Scroll to the location specified by location.  Assumes lock on this is already held. */
1162:            private void scrollToSource(Location location,
1163:                    boolean shouldHighlight) {
1164:                OpenDefinitionsDocument doc = preloadDocument(location);
1165:                openAndScroll(doc, location, shouldHighlight);
1166:            }
1167:
1168:            /** Scrolls to the source location specified by the the debug stack data.
1169:             * @param stackData Stack data containing location to display
1170:             * @throws DebugException if current thread is not suspended
1171:             */
1172:            public synchronized void scrollToSource(DebugStackData stackData)
1173:                    throws DebugException {
1174:                _ensureReady();
1175:                if (_runningThread != null) {
1176:                    throw new DebugException(
1177:                            "Cannot scroll to source unless thread is suspended.");
1178:                }
1179:
1180:                ThreadReference threadRef = _suspendedThreads.peek();
1181:                Iterator<StackFrame> i;
1182:
1183:                try {
1184:                    if (threadRef.frameCount() <= 0) {
1185:                        printMessage("Could not scroll to source. The current thread had no stack frames.");
1186:                        return;
1187:                    }
1188:                    i = threadRef.frames().iterator(); // JDK 1.5 will eliminate this warning
1189:                } catch (IncompatibleThreadStateException e) {
1190:                    throw new DebugException("Unable to find stack frames: "
1191:                            + e);
1192:                }
1193:
1194:                while (i.hasNext()) {
1195:                    StackFrame frame = i.next();
1196:
1197:                    if (frame.location().lineNumber() == stackData.getLine()
1198:                            && stackData.getMethod().equals(
1199:                                    frame.location().declaringType().name()
1200:                                            + "."
1201:                                            + frame.location().method().name())) {
1202:                        scrollToSource(frame.location(), false);
1203:                    }
1204:                }
1205:            }
1206:
1207:            /** Scrolls to the source of the given breakpoint.
1208:             * @param bp the breakpoint
1209:             */
1210:            public synchronized void scrollToSource(Breakpoint bp) {
1211:                openAndScroll(bp.getDocument(), bp.getLineNumber(), bp
1212:                        .getClassName(), false);
1213:            }
1214:
1215:            /**
1216:             * Gets the Breakpoint object at the specified line in the given class.
1217:             * If the given data do not correspond to an actual breakpoint, null is returned.
1218:             * @param line the line number of the breakpoint
1219:             * @param className the name of the class the breakpoint's in
1220:             * @return the Breakpoint corresponding to the line and className, or null if
1221:             *         there is no such breakpoint.
1222:             */
1223:            public synchronized Breakpoint getBreakpoint(int line,
1224:                    String className) {
1225:                for (int i = 0; i < _model.getBreakpointManager().getRegions()
1226:                        .size(); i++) {
1227:                    Breakpoint bp = _model.getBreakpointManager().getRegions()
1228:                            .get(i);
1229:                    if ((bp.getLineNumber() == line)
1230:                            && (bp.getClassName().equals(className))) {
1231:                        return bp;
1232:                    }
1233:                }
1234:                // bp not found in the list of breakpoints
1235:                return null;
1236:            }
1237:
1238:            /** Opens a document and scrolls to the appropriate location.  If doc is null, a message is printed indicating the 
1239:             * source file could not be found.  Assumes lock on this is already held.
1240:             * @param doc Document to open
1241:             * @param location Location to display
1242:             */
1243:            private void openAndScroll(OpenDefinitionsDocument doc,
1244:                    Location location, boolean shouldHighlight) {
1245:                openAndScroll(doc, location.lineNumber(), location
1246:                        .declaringType().name(), shouldHighlight);
1247:            }
1248:
1249:            /** Opens a document and scrolls to the appropriate location.  If doc is null, a message is printed indicating the
1250:             * source file could not be found.  Assumes lock on this is already held.
1251:             * @param doc Document to open
1252:             * @param line the line number to display
1253:             * @param className the name of the appropriate class
1254:             */
1255:            private void openAndScroll(final OpenDefinitionsDocument doc,
1256:                    final int line, String className,
1257:                    final boolean shouldHighlight) {
1258:                // Open and scroll if doc was found
1259:                if (doc != null) {
1260:                    doc.checkIfClassFileInSync();
1261:                    // change UI if in sync in MainFrame listener
1262:
1263:                    Utilities.invokeLater(new Runnable() {
1264:                        public void run() {
1265:                            _notifier.threadLocationUpdated(doc, line,
1266:                                    shouldHighlight);
1267:                        }
1268:                    });
1269:                } else
1270:                    printMessage("  (Source for " + className + " not found.)");
1271:            }
1272:
1273:            /** Returns the relative directory (from the source root) that the source file with this qualifed name will be in, 
1274:             * given its package. Returns the empty string for classes without packages.
1275:             * TO DO: Move this to a static utility class
1276:             * @param className The fully qualified class name
1277:             */
1278:            static String getPackageDir(String className) {
1279:                // Only keep up to the last dot
1280:                int lastDotIndex = className.lastIndexOf(".");
1281:                if (lastDotIndex == -1) {
1282:                    // No dots, so no package
1283:                    return "";
1284:                } else {
1285:                    String packageName = className.substring(0, lastDotIndex);
1286:                    // replace periods with the System's file separator
1287:                    String ps = System.getProperty("file.separator");
1288:                    packageName = StringOps.replace(packageName, ".", ps);
1289:                    return packageName + ps;
1290:                }
1291:            }
1292:
1293:            /** Prints a message in the Interactions Pane.  Not synchronized on this on this because no local state is accessed.
1294:             * @param message Message to display
1295:             */
1296:            void printMessage(String message) {
1297:                _model.printDebugMessage(message);
1298:            }
1299:
1300:            /** Returns whether the given className corresponds to a class
1301:             * that is anonymous or has an anonymous enclosing class.
1302:             * @param rt the ReferenceType to check
1303:             * @return whether the class is anonymous
1304:             */
1305:            private boolean hasAnonymous(ReferenceType rt) {
1306:                String className = rt.name();
1307:                StringTokenizer st = new StringTokenizer(className, "$");
1308:                while (st.hasMoreElements()) {
1309:                    String currToken = st.nextToken();
1310:                    try {
1311:                        Integer anonymousNum = Integer.valueOf(currToken);
1312:                        return true;
1313:                    } catch (NumberFormatException nfe) {
1314:                        // flow through to false if token cannot be parsed into an int
1315:                    }
1316:                }
1317:                return false;
1318:            }
1319:
1320:            private boolean _getWatchFromInterpreter(DebugWatchData currWatch) {
1321:                String currName = currWatch.getName();
1322:                // get the value and type from the interactions model
1323:                String value = _model.getInteractionsModel()
1324:                        .getVariableToString(currName);
1325:                if (value != null) {
1326:                    String type = _model.getInteractionsModel()
1327:                            .getVariableClassName(currName);
1328:                    currWatch.setValue(value);
1329:                    currWatch.setType(type);
1330:                    return true;
1331:                } else {
1332:                    return false;
1333:                }
1334:            }
1335:
1336:            /** Hides all of the values of the watches and their types. Called when there is no debug information.  Assumes lock
1337:             * is already held.
1338:             */
1339:            private void _hideWatches() {
1340:                for (int i = 0; i < _watches.size(); i++) {
1341:                    DebugWatchData currWatch = _watches.get(i);
1342:                    currWatch.hideValueAndType();
1343:                }
1344:            }
1345:
1346:            /** Updates the stored value of each watched field and variable. Synchronization is necessary because this method is 
1347:             * called from unsynchronized listeners. */
1348:            private synchronized void _updateWatches() throws DebugException {
1349:                if (!isReady())
1350:                    return;
1351:
1352:                if (_suspendedThreads.size() <= 0) {
1353:                    // Not suspended, get values in interpreter
1354:                    for (int i = 0; i < _watches.size(); i++) {
1355:                        DebugWatchData currWatch = _watches.get(i);
1356:                        if (!_getWatchFromInterpreter(currWatch))
1357:                            currWatch.hideValueAndType();
1358:                    }
1359:                    return;
1360:                    //      for (int i = 0; i < _watches.size(); i++) {
1361:                    //        DebugWatchData currWatch = _watches.get(i);
1362:                    //        currWatch.hideValueAndType();
1363:                    //      }
1364:                    //      return;
1365:                }
1366:
1367:                try {
1368:                    StackFrame currFrame;
1369:                    List<StackFrame> frames;
1370:                    ThreadReference thread = _suspendedThreads.peek();
1371:                    if (thread.frameCount() <= 0) {
1372:                        printMessage("Could not update watch values. The current thread had no stack frames.");
1373:                        return;
1374:                    }
1375:                    frames = thread.frames(); // JDK 1.5 will eliminate this warning
1376:                    currFrame = frames.get(0);
1377:                    Location location = currFrame.location();
1378:
1379:                    ReferenceType rt = location.declaringType();
1380:                    ObjectReference obj = currFrame.this Object();
1381:                    // note: obj is null if we're in a static context
1382:
1383:                    // Get the name to determine how many $'s there are
1384:                    String rtName = rt.name();
1385:                    int numDollars = 0;
1386:                    int dollarIndex = rtName.indexOf("$", 0);
1387:                    while (dollarIndex != -1) {
1388:                        numDollars++;
1389:                        dollarIndex = rtName.indexOf("$", dollarIndex + 1);
1390:                    }
1391:
1392:                    for (int i = 0; i < _watches.size(); i++) {
1393:                        DebugWatchData currWatch = _watches.get(i);
1394:                        String currName = currWatch.getName();
1395:                        if (_getWatchFromInterpreter(currWatch)) {
1396:                            continue;
1397:                        }
1398:                        //        // check for "this"
1399:                        //        if (currName.equals("this")) {
1400:                        //          if (obj != null) {
1401:                        //            currWatch.setValue(_getValue(obj));
1402:                        //            currWatch.setType(String.valueOf(obj.type()));
1403:                        //          }
1404:                        //          else {
1405:                        //            // "this" is not defined in a static context
1406:                        //            currWatch.setNoValue();
1407:                        //            currWatch.setNoType();
1408:                        //          }
1409:                        //          continue;
1410:                        //        }
1411:
1412:                        //        // Look for a variable with this name
1413:                        //        LocalVariable localVar = null;
1414:                        //        try {
1415:                        //          frames = thread.frames();
1416:                        //          currFrame = (StackFrame) frames.get(0);
1417:                        //          localVar = currFrame.visibleVariableByName(currName);
1418:                        //        }
1419:                        //        catch (AbsentInformationException aie) {
1420:                        //          // Not compiled with debug flag.... ignore
1421:                        //        }
1422:                        //        catch (InvalidStackFrameException isfe) {
1423:                        //          currWatch.setNoValue();
1424:                        //          currWatch.setNoType();
1425:                        //          _log("Failed to get local var from stack frame", isfe);
1426:                        //          continue;
1427:                        //        }
1428:                        //
1429:                        //        if (localVar != null) {
1430:                        //          // currWatch.setValue(_getValue(currFrame.getValue(localVar)));
1431:                        //          try {
1432:                        //            Value v = _getValueOfLocalVariable(localVar, thread);
1433:                        //            if (v == null) {
1434:                        //              currWatch.setValue(_getValue(null));
1435:                        //              try {
1436:                        //                currWatch.setType(localVar.type().name());
1437:                        //              }
1438:                        //              catch (ClassNotLoadedException cnle) {
1439:                        //                List classes = _vm.classesByName(localVar.typeName());
1440:                        //                if (!classes.isEmpty()) {
1441:                        //                  currWatch.setType(((Type)classes.get(0)).name());
1442:                        //                }
1443:                        //                else {
1444:                        //                  currWatch.setTypeNotLoaded();
1445:                        //                }
1446:                        //              }
1447:                        //            }
1448:                        //            else {
1449:                        //              currWatch.setValue(_getValue(v));
1450:                        //              currWatch.setType(v.type().name());
1451:                        //            }
1452:                        //          }
1453:                        //          catch (Exception ex) {
1454:                        //            _log("Exception when getting the value of a local variable", ex);
1455:                        //            currWatch.setNoValue();
1456:                        //            currWatch.setNoType();
1457:                        //          }
1458:                        //        }
1459:                        // if the variable being watched is not a local variable,
1460:                        //  check if it's a field
1461:                        ReferenceType outerRt = rt;
1462:                        ObjectReference outer = obj; // (null if static context)
1463:                        Field field = outerRt.fieldByName(currName);
1464:
1465:                        if (obj != null) {
1466:                            // We're not in a static context
1467:
1468:                            // If we don't find it in this class, loop through any enclosing
1469:                            // classes. Start at this$N, where N is the number of dollar signs in
1470:                            // the reference type's name, minus one.
1471:                            int outerIndex = numDollars - 1;
1472:                            if (hasAnonymous(outerRt)) {
1473:                                // We don't know the appropriate this$N to look for so we have to
1474:                                // search for a field that begins with this$.
1475:                                List<Field> fields = outerRt.allFields(); // This type warning will go away in JDK 1.5
1476:                                Iterator<Field> iter = fields.iterator();
1477:                                while (iter.hasNext()) {
1478:                                    Field f = iter.next();
1479:                                    String name = f.name();
1480:                                    if (name.startsWith("this$")) {
1481:                                        int lastIndex = name.lastIndexOf("$");
1482:                                        outerIndex = Integer.valueOf(
1483:                                                name.substring(lastIndex + 1,
1484:                                                        name.length()))
1485:                                                .intValue();
1486:                                        break;
1487:                                    }
1488:                                }
1489:                            }
1490:                            Field outerThis = outerRt.fieldByName("this$"
1491:                                    + outerIndex);
1492:                            if (field == null) {
1493:                                // Try concatenating "val$" to the beginning of the field in
1494:                                // case it's a final local variable of the outer class
1495:                                field = outerRt.fieldByName("val$" + currName);
1496:                            }
1497:
1498:                            while ((field == null) && (outerThis != null)) {
1499:                                outer = (ObjectReference) outer
1500:                                        .getValue(outerThis);
1501:                                if (outer == null) {
1502:                                    // We're probably in the constructor and this$N has
1503:                                    // not yet been initialized. We can't do anything, so just
1504:                                    // break display no value.
1505:                                    break;
1506:                                }
1507:                                outerRt = outer.referenceType();
1508:                                field = outerRt.fieldByName(currName);
1509:
1510:                                if (field == null) {
1511:                                    // Try concatenating "val$" to the beginning of the field in
1512:                                    // case it's a final local variable of the outer class
1513:                                    field = outerRt.fieldByName("val$"
1514:                                            + currName);
1515:
1516:                                    if (field == null) {
1517:                                        // Enter the loop again with the next outer enclosing class
1518:                                        outerIndex--;
1519:                                        outerThis = outerRt.fieldByName("this$"
1520:                                                + outerIndex);
1521:                                    }
1522:                                }
1523:                            }
1524:                        } else {
1525:                            // We're in a static context
1526:
1527:                            // If we don't find it in this class, loop through any enclosing
1528:                            // classes. Do this by loading any outer classes by invoking the
1529:                            // method on the class loader that loaded this class and passing
1530:                            // it the class name with the last class removed each time.
1531:                            String rtClassName = outerRt.name();
1532:                            int index = rtClassName.lastIndexOf("$");
1533:                            while ((field == null) && (index != -1)) {
1534:                                rtClassName = rtClassName.substring(0, index);
1535:                                List<ReferenceType> l = _vm
1536:                                        .classesByName(rtClassName); // JDK 1.5 will eliminate this warning
1537:                                if (l.isEmpty()) {
1538:                                    // field is null, we will end up setting
1539:                                    // the value to no value
1540:                                    break;
1541:                                }
1542:                                outerRt = l.get(0);
1543:                                field = outerRt.fieldByName(currName);
1544:
1545:                                if (field == null) {
1546:                                    // Enter the loop again with the next outer enclosing class
1547:                                    index = rtClassName.lastIndexOf("$");
1548:                                }
1549:                            }
1550:                        }
1551:
1552:                        // Try to set the value and type of the field.
1553:                        //  If the field is not static and we are in a static context
1554:                        //  (outer==null), we have to setNoValue.
1555:                        if ((field != null)
1556:                                && (field.isStatic() || (outer != null))) {
1557:                            Value v = (field.isStatic()) ? outerRt
1558:                                    .getValue(field) : outer.getValue(field);
1559:                            currWatch.setValue(_getValue(v));
1560:                            try {
1561:                                currWatch.setType(field.type().name());
1562:                            } catch (ClassNotLoadedException cnle) {
1563:                                List<ReferenceType> classes = _vm
1564:                                        .classesByName(field.typeName()); // JDK 1.5 will eliminate this warning
1565:                                if (!classes.isEmpty()) {
1566:                                    currWatch.setType(classes.get(0).name());
1567:                                } else {
1568:                                    currWatch.setTypeNotLoaded();
1569:                                }
1570:                            }
1571:                        } else {
1572:                            currWatch.setNoValue();
1573:                            currWatch.setNoType();
1574:                        }
1575:
1576:                    }
1577:                } catch (IncompatibleThreadStateException itse) {
1578:                    _log("Exception updating watches.", itse);
1579:                } catch (InvalidStackFrameException isfe) {
1580:                    _log("Exception updating watches.", isfe);
1581:                } catch (VMDisconnectedException vmde) {
1582:                    _log("Exception updating watches.", vmde);
1583:                    shutdown();
1584:                }
1585:            }
1586:
1587:            /**
1588:             * Returns a string representation of the given Value from JDI.
1589:             * @param value the Value of interest
1590:             * @return the String representation of the Value
1591:             */
1592:            private String _getValue(Value value) throws DebugException {
1593:                // Most types work as they are; for the rest, for now, only care about getting
1594:                // accurate toString for Objects
1595:                if (value == null) {
1596:                    return "null";
1597:                }
1598:
1599:                if (!(value instanceof  ObjectReference)) {
1600:                    return value.toString();
1601:                }
1602:                ObjectReference object = (ObjectReference) value;
1603:                ReferenceType rt = object.referenceType();
1604:                ThreadReference thread = _suspendedThreads.peek();
1605:                List<Method> toStrings = rt.methodsByName("toString"); // JDK 1.5 will eliminate this warning
1606:                if (toStrings.size() == 0) {
1607:                    // not sure how an Object can't have a toString method, but it happens
1608:                    return value.toString();
1609:                }
1610:                // Assume that there's only one method named toString
1611:                Method method = toStrings.get(0);
1612:                try {
1613:                    Value stringValue = object.invokeMethod(thread, method,
1614:                            new LinkedList<Value>(),
1615:                            ObjectReference.INVOKE_SINGLE_THREADED);
1616:                    if (stringValue == null)
1617:                        return "null";
1618:                    return stringValue.toString();
1619:                } catch (InvalidTypeException ite) {
1620:                    // shouldn't happen, not passing any arguments to toString()
1621:                    throw new UnexpectedException(ite);
1622:                } catch (ClassNotLoadedException cnle) {
1623:                    // once again, no arguments
1624:                    throw new UnexpectedException(cnle);
1625:                } catch (IncompatibleThreadStateException itse) {
1626:                    throw new DebugException(
1627:                            "Cannot determine value from thread: " + itse);
1628:                } catch (InvocationException ie) {
1629:                    throw new DebugException("Could not invoke toString: " + ie);
1630:                }
1631:            }
1632:
1633:            /** @return the appropriate Method to call in the InterpreterJVM in order to define a variable of the type val. */
1634:            private Method _getDefineVariableMethod(
1635:                    ReferenceType interpreterRef, Value val)
1636:                    throws DebugException {
1637:                List<Method> methods;
1638:                String signature_beginning = "(Ljava/lang/String;";
1639:                String signature_end = ")V";
1640:                String signature_mid;
1641:                String signature;
1642:
1643:                if ((val == null) || (val instanceof  ObjectReference)) {
1644:                    signature_mid = "Ljava/lang/Object;Ljava/lang/Class;";
1645:                } else if (val instanceof  BooleanValue) {
1646:                    signature_mid = "Z";
1647:                } else if (val instanceof  ByteValue) {
1648:                    signature_mid = "B";
1649:                } else if (val instanceof  CharValue) {
1650:                    signature_mid = "C";
1651:                } else if (val instanceof  DoubleValue) {
1652:                    signature_mid = "D";
1653:                } else if (val instanceof  FloatValue) {
1654:                    signature_mid = "F";
1655:                } else if (val instanceof  IntegerValue) {
1656:                    signature_mid = "I";
1657:                } else if (val instanceof  LongValue) {
1658:                    signature_mid = "J";
1659:                } else if (val instanceof  ShortValue) {
1660:                    signature_mid = "S";
1661:                } else {
1662:                    throw new IllegalArgumentException(
1663:                            "Tried to define a variable which is\n"
1664:                                    + "not an Object or a primitive type:\n"
1665:                                    + val);
1666:                }
1667:
1668:                signature = signature_beginning + signature_mid + signature_end;
1669:                methods = interpreterRef.methodsByName("defineVariable",
1670:                        signature); // JDK 1.5 will eliminate this warning
1671:                if (methods.size() <= 0) {
1672:                    throw new DebugException(
1673:                            "Could not find defineVariable method.");
1674:                }
1675:
1676:                // Make sure we have a concrete method
1677:                Method tempMethod = methods.get(0);
1678:                for (int i = 1; i < methods.size() && tempMethod.isAbstract(); i++) {
1679:                    tempMethod = methods.get(i);
1680:                }
1681:                if (tempMethod.isAbstract()) {
1682:                    throw new DebugException(
1683:                            "Could not find concrete defineVariable method.");
1684:                }
1685:
1686:                return tempMethod;
1687:            }
1688:
1689:            /** Assumes that this method is only called immedeately after suspending a thread. */
1690:            private ObjectReference _getDebugInterpreter()
1691:                    throws InvalidTypeException, ClassNotLoadedException,
1692:                    IncompatibleThreadStateException, InvocationException,
1693:                    DebugException {
1694:
1695:                ThreadReference threadRef = _suspendedThreads.peek();
1696:                String interpreterName = _getUniqueThreadName(threadRef);
1697:                return _getDebugInterpreter(interpreterName, threadRef);
1698:            }
1699:
1700:            /** Gets the debug interpreter with the given name using the given suspended thread to invoke methods.
1701:             *  @param interpreterName Name of the interpreter in the InterpreterJVM
1702:             *  @param threadRef Suspended thread to use for invoking methods
1703:             *  @throws IllegalStateException if threadRef is not suspended
1704:             */
1705:            private ObjectReference _getDebugInterpreter(
1706:                    String interpreterName, ThreadReference threadRef)
1707:                    throws InvalidTypeException, ClassNotLoadedException,
1708:                    IncompatibleThreadStateException, InvocationException,
1709:                    DebugException {
1710:
1711:                if (!threadRef.isSuspended()) {
1712:                    throw new IllegalStateException(
1713:                            "threadRef must be suspended to get a debug interpreter.");
1714:                }
1715:
1716:                // Get the method to return the interpreter
1717:                Method m = _getMethod(_interpreterJVM.referenceType(),
1718:                        "getJavaInterpreter");
1719:
1720:                // invokeMethod would throw an ObjectCollectedException if the StringReference
1721:                // declared by _vm.mirrorOf(name) had been garbage collected before
1722:                // invokeMethod could execute. We now just disable collection until after the
1723:                // method is invoked.
1724:
1725:                int tries = 0;
1726:                StringReference sr = null;
1727:                while (tries < OBJECT_COLLECTED_TRIES) {
1728:                    try {
1729:                        LinkedList<StringReference> args = new LinkedList<StringReference>(); //Added parameterization <StringReference>.
1730:                        sr = _vm.mirrorOf(interpreterName);
1731:                        sr.disableCollection();
1732:                        args.add(sr); // make the String a JDI Value
1733:                        _log.log("Invoking " + m.toString() + " on "
1734:                                + args.toString());
1735:                        _log.log("Thread is " + threadRef.toString()
1736:                                + " <suspended = " + threadRef.isSuspended()
1737:                                + ">");
1738:
1739:                        ObjectReference tmpInterpreter = (ObjectReference) _interpreterJVM
1740:                                .invokeMethod(threadRef, m, args,
1741:                                        ObjectReference.INVOKE_SINGLE_THREADED);
1742:
1743:                        _log.log("Returning...");
1744:                        return tmpInterpreter;
1745:                    } catch (ObjectCollectedException e) {
1746:                        tries++;
1747:                    } finally {
1748:                        sr.enableCollection();
1749:                    }
1750:                }
1751:                throw new DebugException("The debugInterpreter: "
1752:                        + interpreterName
1753:                        + " could not be obtained from interpreterJVM");
1754:            }
1755:
1756:            /**
1757:             * Notifies the debugger that an assignment has been made in
1758:             * the given debug interpreter.
1759:             *
1760:             * Not currently used.
1761:             *
1762:             * @param name the name of the interpreter
1763:             *
1764:            public void notifyDebugInterpreterAssignment(String name) {
1765:              //System.out.println("notifyDebugInterpreterAssignment(" + name + ")");
1766:            }*/
1767:
1768:            /**
1769:             * Copy the current selected thread's visible variables (those in scope) into
1770:             * an interpreter's environment and then switch the Interactions window's
1771:             * interpreter to that interpreter.
1772:             */
1773:            private void _dumpVariablesIntoInterpreterAndSwitch()
1774:                    throws DebugException, AbsentInformationException {
1775:                _log.log(this 
1776:                        + " invoked dumpVariablesIntoInterpreterAndSwitch");
1777:                try {
1778:                    ThreadReference suspendedThreadRef = _suspendedThreads
1779:                            .peek();
1780:                    StackFrame frame = suspendedThreadRef.frame(0);
1781:                    Location l = frame.location();
1782:                    ReferenceType rt = l.declaringType();
1783:                    String className = rt.name();
1784:
1785:                    // Name the new interpreter based on this thread
1786:                    String interpreterName = _getUniqueThreadName(suspendedThreadRef);
1787:                    _model.getInteractionsModel().addDebugInterpreter(
1788:                            interpreterName, className);
1789:                    ObjectReference debugInterpreter = _getDebugInterpreter();
1790:                    _log
1791:                            .log(this 
1792:                                    + " executing: frame = suspendedThreadRef.frame(0);");
1793:                    frame = suspendedThreadRef.frame(0);
1794:
1795:                    List<LocalVariable> vars = frame.visibleVariables(); // JDK 1.5 will eliminate this warning
1796:                    Iterator<LocalVariable> varsIterator = vars.iterator();
1797:
1798:                    _log.log(this  + " got visibleVariables");
1799:
1800:                    // Define each variable
1801:                    while (varsIterator.hasNext()) {
1802:                        LocalVariable localVar = varsIterator.next();
1803:                        _log.log(this  + " defined local variable: " + localVar);
1804:                        // Have to update the frame each time
1805:                        frame = suspendedThreadRef.frame(0);
1806:                        Value val = frame.getValue(localVar);
1807:                        Type type;
1808:                        if (val != null) {
1809:                            type = val.type();
1810:                        } else {
1811:                            try {
1812:                                type = localVar.type();
1813:                            } catch (ClassNotLoadedException e) {
1814:                                List<ReferenceType> classes = _vm
1815:                                        .classesByName(localVar.typeName()); //JDK 1.5 will eliminate this warning
1816:                                if (!classes.isEmpty()) {
1817:                                    type = classes.get(0);
1818:                                } else {
1819:                                    type = null;
1820:                                }
1821:                            }
1822:                        }
1823:                        _defineVariable(suspendedThreadRef, debugInterpreter,
1824:                                localVar.name(), val, type);
1825:                    }
1826:
1827:                    // Update the frame
1828:                    frame = suspendedThreadRef.frame(0);
1829:
1830:                    // Define "this"
1831:                    Value this Val = frame.this Object();
1832:                    if (this Val != null) {
1833:                        _defineVariable(suspendedThreadRef, debugInterpreter,
1834:                                "this", this Val, this Val.type());
1835:                        //_setThisInInterpreter(suspendedThreadRef, debugInterpreter, thisVal);
1836:                    }
1837:
1838:                    // Set the new interpreter and prompt
1839:                    String prompt = _getPromptString(suspendedThreadRef);
1840:                    _log.log(this  + " is setting active interpreter");
1841:                    _model.getInteractionsModel().setActiveInterpreter(
1842:                            interpreterName, prompt);
1843:                } catch (InvalidTypeException exc) {
1844:                    throw new DebugException(exc.toString());
1845:                } catch (IncompatibleThreadStateException e2) {
1846:                    throw new DebugException(e2.toString());
1847:                } catch (ClassNotLoadedException e3) {
1848:                    throw new DebugException(e3.toString());
1849:                } catch (InvocationException e4) {
1850:                    throw new DebugException(e4.toString());
1851:                }
1852:            }
1853:
1854:            /**
1855:             * @return the prompt to display in the itneractions console
1856:             * based upon the ThreadReference threadRef, which is being debugged.
1857:             */
1858:            private String _getPromptString(ThreadReference threadRef) {
1859:                return "[" + threadRef.name() + "] > ";
1860:            }
1861:
1862:            /**
1863:             * Defines a variable with the given name to the given value, using
1864:             * a thread reference and JavaInterpreter.
1865:             * If type == null, we assume that the type of this variable
1866:             * has not been loaded so we will set it to Object in DynamicJavaAdapter.
1867:             * @param suspendedThreadRef Thread ref being debugged
1868:             * @param debugInterpreter ObjectReference to the JavaInterpreter to contain
1869:             * the variable
1870:             * @param name Name of the variable
1871:             * @param val Value of the variable
1872:             */
1873:            private void _defineVariable(ThreadReference suspendedThreadRef,
1874:                    ObjectReference debugInterpreter, String name, Value val,
1875:                    Type type) throws InvalidTypeException,
1876:                    IncompatibleThreadStateException, ClassNotLoadedException,
1877:                    InvocationException, DebugException {
1878:                ReferenceType rtDebugInterpreter = debugInterpreter
1879:                        .referenceType();
1880:                Method method2Call = _getDefineVariableMethod(
1881:                        rtDebugInterpreter, val);
1882:
1883:                // invokeMethod would throw an ObjectCollectedException if the StringReference
1884:                // declared by _vm.mirrorOf(name) had been garbage collected before
1885:                // invokeMethod could execute. We now just disable collection until after the
1886:                // method is invoked.
1887:
1888:                int tries = 0;
1889:                StringReference sr = null;
1890:                while (tries < OBJECT_COLLECTED_TRIES) {
1891:                    try {
1892:                        //Added parameterization <Value>.
1893:                        List<Value> args = new LinkedList<Value>();
1894:                        /* Mirror is the common supertype of StringReference, Value, and ReferenceType.  Changed from Mirror to Value 
1895:                         * because invokeMethod requires a List of Value type. It does not need to be a Mirror because neither sr nor 
1896:                         * val can be a ReferenceType */
1897:                        sr = _vm.mirrorOf(name);
1898:                        sr.disableCollection();
1899:                        args.add(sr);
1900:                        args.add(val);
1901:                        if (type == null)
1902:                            args.add(null);
1903:                        else if (type instanceof  ReferenceType) {
1904:                            args.add(((ReferenceType) type).classObject());
1905:                        }
1906:
1907:                        /* System.out.println("Calling " + method2Call.toString() + "with " + args.get(0).toString()); */
1908:                        debugInterpreter.invokeMethod(suspendedThreadRef,
1909:                                method2Call, args,
1910:                                ObjectReference.INVOKE_SINGLE_THREADED);
1911:                        return;
1912:                    } catch (ObjectCollectedException oce) {
1913:                        tries++;
1914:                    } finally {
1915:                        sr.enableCollection();
1916:                    }
1917:                }
1918:                throw new DebugException("The variable: " + name
1919:                        + " could not be defined in the debug interpreter");
1920:            }
1921:
1922:            /** Notifies all listeners that the current thread has been suspended. Synchronization is necessary because it is 
1923:             * called from unsynchronized listeners and other classes (in same package). 
1924:             */
1925:            synchronized void currThreadSuspended() {
1926:                try {
1927:                    try {
1928:                        // copy the variables in scope into an interpreter
1929:                        // and switch the current interpreter to that interpreter
1930:                        _dumpVariablesIntoInterpreterAndSwitch();
1931:                        _switchToSuspendedThread();
1932:                    } catch (AbsentInformationException aie) {
1933:                        // an AbsentInformationException can be thrown if the user does not
1934:                        // compile the classes to be debugged with the -g flag
1935:                        printMessage("No debug information available for this class.\nMake sure to compile classes to be debugged with the -g flag.");
1936:                        _hideWatches();
1937:                        // don't updateWatches in _switchToSuspendedThread since it will display the default
1938:                        // interpreter's watch information.
1939:                        _switchToSuspendedThread(false);
1940:                    }
1941:                } catch (DebugException de) {
1942:                    throw new UnexpectedException(de);
1943:                }
1944:            }
1945:
1946:            /** Calls the real switchToSuspendedThread, telling it to updateWatches. This is what is usually called. */
1947:            private void _switchToSuspendedThread() throws DebugException {
1948:                _switchToSuspendedThread(true);
1949:            }
1950:
1951:            /** Performs the bookkeeping to switch to the suspened thread on the top of the _suspendedThreads stack.
1952:             *  @param updateWatches this is false if the current file does not have debug information. This prevents the default
1953:             *  interpreter's watch values from being shown.
1954:             */
1955:            private void _switchToSuspendedThread(boolean updateWatches)
1956:                    throws DebugException {
1957:                _log.log(this  + " executing _switchToSuspendedThread()");
1958:                _runningThread = null;
1959:                if (updateWatches)
1960:                    _updateWatches();
1961:                final ThreadReference currThread = _suspendedThreads.peek();
1962:                _notifier.currThreadSuspended();
1963:                // Anytime a thread is suspended, it becomes the current thread.
1964:                // This makes sure the debug panel will correctly put the
1965:                // current thread in bold.
1966:                _notifier.currThreadSet(new JPDAThreadData(currThread));
1967:
1968:                try {
1969:                    if (currThread.frameCount() > 0) {
1970:                        scrollToSource(currThread.frame(0).location());
1971:                    }
1972:                } catch (IncompatibleThreadStateException itse) {
1973:                    throw new UnexpectedException(itse);
1974:                }
1975:            }
1976:
1977:            /**
1978:             * Returns a unique name for the given thread.
1979:             */
1980:            private String _getUniqueThreadName(ThreadReference thread) {
1981:                return Long.toString(thread.uniqueID());
1982:            }
1983:
1984:            /**
1985:             * @return the Method corresponding to DynamicJavaAdapter.getVariable()
1986:             */
1987:            private Method _getGetVariableMethod(ReferenceType rtInterpreter) {
1988:                return _getMethod(rtInterpreter, "getVariable");
1989:            }
1990:
1991:            /**
1992:             * Returns the concrete method with the given name on the reference type.
1993:             * @param rt ReferenceType containing the method
1994:             * @param name Name of the method
1995:             * @throws NoSuchElementException if no concrete method could be found
1996:             */
1997:            private Method _getMethod(ReferenceType rt, String name) {
1998:                List<Method> methods = rt.methodsByName(name); // JDK 1.5 will eliminate this warning
1999:                Iterator<Method> methodsIterator = methods.iterator();
2000:
2001:                // iterate over all the methods in the list and return the first non-abstract one
2002:                while (methodsIterator.hasNext()) {
2003:                    Method m = methodsIterator.next();
2004:                    if (!m.isAbstract()) {
2005:                        return m;
2006:                    }
2007:                }
2008:
2009:                throw new NoSuchElementException(
2010:                        "No non-abstract method called " + name + " found in "
2011:                                + rt.name());
2012:            }
2013:
2014:            /**
2015:             * Converts a primitive wrapper object (eg. Integer) to its corresponding
2016:             * primitive value (eg. int) by invoking the appropriate method in the
2017:             * given thread.
2018:             * @param threadRef Thread in which to invoke the method
2019:             * @param localVar Variable to convert
2020:             * @param v Value of localVar
2021:             * @return Converted primitive, or v if it was a reference type
2022:             */
2023:            private Value _convertToActualType(ThreadReference threadRef,
2024:                    LocalVariable localVar, Value v)
2025:                    throws InvalidTypeException, ClassNotLoadedException,
2026:                    IncompatibleThreadStateException, InvocationException {
2027:                String typeSignature;
2028:                try {
2029:                    typeSignature = localVar.type().signature();
2030:                } catch (ClassNotLoadedException cnle) {
2031:                    return v;
2032:                }
2033:                Method m;
2034:                ObjectReference ref = (ObjectReference) v;
2035:                ReferenceType rt = ref.referenceType();
2036:
2037:                if (typeSignature.equals("Z")) {
2038:                    m = _getMethod(rt, "booleanValue");
2039:                } else if (typeSignature.equals("B")) {
2040:                    m = _getMethod(rt, "byteValue");
2041:                } else if (typeSignature.equals("C")) {
2042:                    m = _getMethod(rt, "charValue");
2043:                } else if (typeSignature.equals("S")) {
2044:                    m = _getMethod(rt, "shortValue");
2045:                } else if (typeSignature.equals("I")) {
2046:                    m = _getMethod(rt, "intValue");
2047:                } else if (typeSignature.equals("J")) {
2048:                    m = _getMethod(rt, "longValue");
2049:                } else if (typeSignature.equals("F")) {
2050:                    m = _getMethod(rt, "floatValue");
2051:                } else if (typeSignature.equals("D")) {
2052:                    m = _getMethod(rt, "doubleValue");
2053:                } else {
2054:                    return v;
2055:                }
2056:
2057:                return ref.invokeMethod(threadRef, m, new LinkedList<Value>(),
2058:                        ObjectReference.INVOKE_SINGLE_THREADED);
2059:            }
2060:
2061:            //  private ClassObjectReference _getClassForName(String name, ThreadReference thread, ClassLoaderReference clr)
2062:            //    throws InvalidTypeException, ClassNotLoadedException, AbsentInformationException,
2063:            //    IncompatibleThreadStateException, InvocationException, DebugException
2064:            //  {
2065:            //    Value v = null;
2066:            //
2067:            //    // invokeMethod would throw an ObjectCollectedException if the StringReference
2068:            //    // declared by _vm.mirrorOf(name) had been garbage collected before
2069:            //    // invokeMethod could execute. This happened infrequently so by trying this
2070:            //    // multiple times, the chance of failure each time should be acceptably low.
2071:            //    int tries = 0;
2072:            //    while (tries < MAXINVOKETRIES) {
2073:            //      try {
2074:            //        ReferenceType rt = clr.referenceType();
2075:            //        Method method2Call = _getMethod(rt, "loadClass");
2076:            //        List args = new LinkedList();
2077:            //        args.add(_vm.mirrorOf(name));
2078:            //        args.add(_vm.mirrorOf(true));
2079:            //        v = clr.invokeMethod(thread, method2Call, args,
2080:            //                                   ObjectReference.INVOKE_SINGLE_THREADED);
2081:            //        break;
2082:            //      }
2083:            //      catch (ObjectCollectedException oce) {
2084:            //        _log.log("Got ObjectCollectedException");
2085:            //        tries++;
2086:            //      }
2087:            //    }
2088:            //    if (v != null) {
2089:            //      //v = _convertToActualType(thread, var, v);
2090:            //      return (ClassObjectReference)v;
2091:            //    }
2092:            //
2093:            //    return null;
2094:            //  }
2095:
2096:            private Value _getValueOfLocalVariable(LocalVariable var,
2097:                    ThreadReference thread) throws InvalidTypeException,
2098:                    ClassNotLoadedException, IncompatibleThreadStateException,
2099:                    InvocationException, DebugException {
2100:                ObjectReference interpreter = _getDebugInterpreter(
2101:                        _getUniqueThreadName(thread), thread);
2102:                ReferenceType rtInterpreter = interpreter.referenceType();
2103:                Method method2Call = _getGetVariableMethod(rtInterpreter);
2104:
2105:                // invokeMethod would throw an ObjectCollectedException if the StringReference
2106:                // declared by _vm.mirrorOf(name) had been garbage collected before
2107:                // invokeMethod could execute. We now just disable collection until after the
2108:                // method is invoked.
2109:
2110:                int tries = 0;
2111:                StringReference sr = null;
2112:                String varName = var.name();
2113:                while (tries < OBJECT_COLLECTED_TRIES) {
2114:                    try {
2115:                        List<Value> args = new LinkedList<Value>(); //Added parameterization <Value>
2116:                        sr = _vm.mirrorOf(varName);
2117:                        sr.disableCollection();
2118:                        args.add(sr);
2119:                        Value v = interpreter.invokeMethod(thread, method2Call,
2120:                                args, ObjectReference.INVOKE_SINGLE_THREADED);
2121:                        if (v != null)
2122:                            v = _convertToActualType(thread, var, v);
2123:
2124:                        return v;
2125:                    } catch (ObjectCollectedException oce) {
2126:                        tries++;
2127:                    } finally {
2128:                        sr.enableCollection();
2129:                    }
2130:                }
2131:                throw new DebugException("The value of variable: " + varName
2132:                        + " could not be obtained from the debug interpreter");
2133:
2134:            }
2135:
2136:            /** Copies the variables in the current interpreter back into the Threaf it refers to. */
2137:            private void _copyBack(ThreadReference threadRef)
2138:                    throws IncompatibleThreadStateException,
2139:                    AbsentInformationException, InvocationException,
2140:                    DebugException {
2141:                _log.log("Getting debug interpreter");
2142:                _log.log("Getting variables");
2143:                StackFrame frame = threadRef.frame(0);
2144:                List<LocalVariable> vars = frame.visibleVariables(); // Added <LocalVariable> type argument; warning will go away in JDK 1.5
2145:                Iterator<LocalVariable> varsIterator = vars.iterator();
2146:
2147:                // Get each variable from the stack frame
2148:                while (varsIterator.hasNext()) {
2149:                    _log.log("Iterating through vars");
2150:                    LocalVariable localVar = varsIterator.next();
2151:
2152:                    try {
2153:                        Value v = _getValueOfLocalVariable(localVar, threadRef);
2154:                        frame = threadRef.frame(0);
2155:                        frame.setValue(localVar, v);
2156:                    } catch (ClassNotLoadedException cnle) {
2157:                        printMessage("Could not update the value of '"
2158:                                + localVar.name() + "' (class not loaded)");
2159:                    } catch (InvalidTypeException ite) {
2160:                        printMessage("Could not update the value of '"
2161:                                + localVar.name()
2162:                                + "' (invalid type exception)");
2163:                    }
2164:                }
2165:            }
2166:
2167:            /** Assumes lock is already held. */
2168:            private void _copyVariablesFromInterpreter() throws DebugException {
2169:                try {
2170:                    // copy variables values out of interpreter's environment and
2171:                    // into the relevant stack frame
2172:                    _log.log("In _copyBack()");
2173:                    _copyBack(_runningThread);
2174:                    _log.log("Out of _copyBack()");
2175:                } catch (AbsentInformationException e2) {
2176:                    //throw new DebugException(e2.toString());
2177:                    // Silently fail for now to ignore the AbsentInformationException that
2178:                    // we should have noticed when first suspending on this line (see currThreadSuspended).
2179:                } catch (IncompatibleThreadStateException e) {
2180:                    throw new DebugException(e.toString());
2181:                } catch (InvocationException e4) {
2182:                    throw new DebugException(e4.toString());
2183:                }
2184:            }
2185:
2186:            /** Removes all of the debug interpreters as part of shutting down.  Assumes lock is already held. */
2187:            private void _removeAllDebugInterpreters() {
2188:                DefaultInteractionsModel interactionsModel = _model
2189:                        .getInteractionsModel();
2190:                String oldInterpreterName;
2191:                if (_runningThread != null) {
2192:                    oldInterpreterName = _getUniqueThreadName(_runningThread);
2193:                    interactionsModel.removeInterpreter(oldInterpreterName);
2194:                }
2195:                while (!_suspendedThreads.isEmpty()) {
2196:                    ThreadReference threadRef = _suspendedThreads.pop();
2197:                    oldInterpreterName = _getUniqueThreadName(threadRef);
2198:                    interactionsModel.removeInterpreter(oldInterpreterName);
2199:                }
2200:            }
2201:
2202:            /** This method is called to remove the current debug interpreter upon resuming the current thread.  Assumes that 
2203:             * lock on this is alaredy held.
2204:             * @param fromStep If true, switch to the default interpreter since we don't want to switch to the next debug 
2205:             *   interpreter and display its watch data. We would like to just not have an active interpreter and put up an 
2206:             *   hourglass over the interactions pane, but the interpreterJVM must have an active interpreter.
2207:             */
2208:            private void _removeCurrentDebugInterpreter(boolean fromStep) {
2209:                DefaultInteractionsModel interactionsModel = _model
2210:                        .getInteractionsModel();
2211:                // switch to next interpreter on the stack
2212:                if (fromStep || _suspendedThreads.isEmpty()) {
2213:                    interactionsModel.setToDefaultInterpreter();
2214:                } else {
2215:                    ThreadReference threadRef = _suspendedThreads.peek();
2216:                    _switchToInterpreterForThreadReference(threadRef);
2217:                }
2218:                String oldInterpreterName = _getUniqueThreadName(_runningThread);
2219:                interactionsModel.removeInterpreter(oldInterpreterName);
2220:            }
2221:
2222:            /** Notifies all listeners that the current thread has been resumed.  Synchronization dropped because invokeLater runs
2223:             * asynchronously.
2224:             *  Precondition: Assumes that the current thread hasn't yet been resumed
2225:             */
2226:            private void currThreadResumed() throws DebugException {
2227:                _log.log(this  + " is executing currThreadResumed()");
2228:                Utilities.invokeLater(new Runnable() {
2229:                    public void run() {
2230:                        _notifier.currThreadResumed();
2231:                    }
2232:                });
2233:            }
2234:
2235:            /** Switches the current interpreter to the one corresponding to threadRef.  Assumes lock on this is already held.
2236:             * @param threadRef The ThreadRefernce corresponding to the interpreter to switch to
2237:             */
2238:            private void _switchToInterpreterForThreadReference(
2239:                    ThreadReference threadRef) {
2240:                String threadName = _getUniqueThreadName(threadRef);
2241:                String prompt = _getPromptString(threadRef);
2242:                _model.getInteractionsModel().setActiveInterpreter(threadName,
2243:                        prompt);
2244:            }
2245:
2246:            /** Not synchronized because invokeLater is asynchronous. */
2247:            void threadStarted() {
2248:                Utilities.invokeLater(new Runnable() {
2249:                    public void run() {
2250:                        _notifier.threadStarted();
2251:                    }
2252:                });
2253:            }
2254:
2255:            /** Notifies all listeners that the current thread has died.  updateThreads is set to true if the threads and stack
2256:             * tables need to be updated, false if there are no suspended threads
2257:             */
2258:            synchronized void currThreadDied() throws DebugException {
2259:                printMessage("The current thread has finished.");
2260:                _runningThread = null;
2261:
2262:                _updateWatches();
2263:
2264:                if (_suspendedThreads.size() > 0) {
2265:                    ThreadReference thread = _suspendedThreads.peek();
2266:                    _switchToInterpreterForThreadReference(thread);
2267:
2268:                    try {
2269:                        if (thread.frameCount() <= 0) {
2270:                            printMessage("Could not scroll to source for "
2271:                                    + thread.name()
2272:                                    + ". It has no stackframes.");
2273:                        } else
2274:                            scrollToSource(thread.frame(0).location());
2275:                    } catch (IncompatibleThreadStateException e) {
2276:                        throw new UnexpectedException(e);
2277:                    }
2278:
2279:                    // updates watches and makes buttons in UI active, does this because
2280:                    // there are suspended threads on the stack
2281:                    _switchToSuspendedThread();
2282:                }
2283:                Utilities.invokeLater(new Runnable() {
2284:                    public void run() {
2285:                        _notifier.currThreadDied();
2286:                    }
2287:                });
2288:            }
2289:
2290:            void nonCurrThreadDied() {
2291:                Utilities.invokeLater(new Runnable() {
2292:                    public void run() {
2293:                        _notifier.nonCurrThreadDied();
2294:                    }
2295:                });
2296:            }
2297:
2298:            /** Notifies all listeners that the debugger has shut down. updateThreads is set to true if the threads and stack 
2299:             *  tables need to be updated, false if there are no suspended threads
2300:             */
2301:            void notifyDebuggerShutdown() {
2302:                Utilities.invokeLater(new Runnable() {
2303:                    public void run() {
2304:                        _notifier.debuggerShutdown();
2305:                    }
2306:                });
2307:            }
2308:
2309:            /** Notifies all listeners that the debugger has started. */
2310:            void notifyDebuggerStarted() {
2311:                Utilities.invokeLater(new Runnable() {
2312:                    public void run() {
2313:                        _notifier.debuggerStarted();
2314:                    }
2315:                });
2316:            }
2317:
2318:            /** Notifies all listeners that a step has been requested. */
2319:            void notifyStepRequested() {
2320:                Utilities.invokeLater(new Runnable() {
2321:                    public void run() {
2322:                        _notifier.stepRequested();
2323:                    }
2324:                });
2325:            }
2326:
2327:            /** A thread-safe stack from which you can remove any element, not just the top of the stack.  All synchronization is 
2328:             *  performed on the wrapped vector.
2329:             *  TODO: make a generic Collection extending/replacing Stack.
2330:             */
2331:            private static class RandomAccessStack extends
2332:                    Stack<ThreadReference> {
2333:
2334:                public ThreadReference peekAt(int i) {
2335:                    return get(i);
2336:                }
2337:
2338:                public ThreadReference remove(long id)
2339:                        throws NoSuchElementException {
2340:                    synchronized (this ) {
2341:                        for (int i = 0; i < size(); i++) {
2342:                            if (get(i).uniqueID() == id) {
2343:                                ThreadReference t = get(i);
2344:                                remove(i);
2345:                                return t;
2346:                            }
2347:                        }
2348:                    }
2349:
2350:                    throw new NoSuchElementException("Thread " + id
2351:                            + " not found in debugger suspended threads stack!");
2352:                }
2353:
2354:                public synchronized boolean contains(long id) {
2355:                    for (int i = 0; i < size(); i++) {
2356:                        if (get(i).uniqueID() == id)
2357:                            return true;
2358:                    }
2359:                    return false;
2360:                }
2361:
2362:                public boolean isEmpty() {
2363:                    return empty();
2364:                }
2365:            }
2366:
2367:            //  /** This class tries to filter out system threads. It is currently unused. */
2368:            //  class SystemThreadsFilter{
2369:            //    private HashMap<String,Boolean> _filterThese;
2370:            //
2371:            //    public SystemThreadsFilter(List threads) {
2372:            //      _filterThese = new HashMap<String,Boolean>();
2373:            //      Iterator iterator = threads.iterator();
2374:            //      String temp = null;
2375:            //
2376:            //      while(iterator.hasNext()) {
2377:            //        temp = ((ThreadReference)iterator.next()).name();
2378:            //        _filterThese.put(temp, Boolean.TRUE);
2379:            //      }
2380:            //    }
2381:            //
2382:            //    public List filter(List list) {
2383:            //      LinkedList retList = new LinkedList();
2384:            //      String temp = null;
2385:            //      ThreadReference tempThreadRef = null;
2386:            //      Iterator iterator = list.iterator();
2387:            //
2388:            //      while(iterator.hasNext()) {
2389:            //        tempThreadRef = (ThreadReference)iterator.next();
2390:            //        temp = tempThreadRef.name();
2391:            //        if ( _filterThese.get(temp) == null ) {
2392:            //          retList.add(tempThreadRef);
2393:            //        }
2394:            //      }
2395:            //
2396:            //      return retList;
2397:            //    }
2398:            //  }
2399:        }
w__ww_.__j_a_v_a__2__s___.__c__o___m___ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.