[Pydev-cvs] org.python.pydev.debug/src/org/python/pydev/debug/model PyThread.java,NONE,1.1 VersionCo
Brought to you by:
fabioz
From: Aleksandar T. <at...@us...> - 2004-04-22 10:56:28
|
Update of /cvsroot/pydev/org.python.pydev.debug/src/org/python/pydev/debug/model In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18445/src/org/python/pydev/debug/model Modified Files: RemoteDebuggerCommand.java RemoteDebugger.java Added Files: PyThread.java VersionCommand.java ModelUtils.java ListThreadsCommand.java PyDebugTarget.java Removed Files: PythonDebugTarget.java Log Message: The beginning of the new debugger technology --- NEW FILE: VersionCommand.java --- /* * Author: atotic * Created on Apr 19, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; /** * Version debugger command. * * See protocol definition for more info */ public class VersionCommand extends RemoteDebuggerCommand { static final String VERSION = "1.0"; int sequence; /** * @param debugger */ public VersionCommand(RemoteDebugger debugger) { super(debugger); sequence = debugger.getNextSequence(); } public String getOutgoing() { return makeCommand(Integer.toString(CMD_VERSION), sequence, VERSION); } public boolean needResponse() { return true; } public int getSequence() { return sequence; } public void processResponse(int cmdCode, String payload) { System.err.println("The version is " + payload); } } Index: RemoteDebugger.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev.debug/src/org/python/pydev/debug/model/RemoteDebugger.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** RemoteDebugger.java 29 Mar 2004 17:07:25 -0000 1.1 --- RemoteDebugger.java 22 Apr 2004 10:56:18 -0000 1.2 *************** *** 9,85 **** import java.net.*; import java.util.ArrayList; ! import java.util.Iterator; /** * Network interface to the remote debugger. */ ! public class RemoteDebugger implements Runnable { ! // socket communication ! Socket socket; ! PrintWriter toServer; ! BufferedReader fromServer; ! InputStream sin; ! ArrayList commands = new ArrayList(); // command queue ! public RemoteDebugger(Socket socket) throws IOException { ! this.socket = socket; ! OutputStream sout = socket.getOutputStream(); ! sin = socket.getInputStream(); ! fromServer = new BufferedReader(new InputStreamReader(sin)); ! toServer = new PrintWriter(new OutputStreamWriter(sout)); ! } ! public void sendCommand(RemoteDebuggerCommand command) { ! synchronized(commands) { ! commands.add(command); } - } ! private void execute1Command(RemoteDebuggerCommand c) { ! String sendThis = c.getXMLMessage(); ! toServer.write(sendThis); ! // TODO process result } ! /** ! * ! * @param commandList - a list of RemoteDebuggerCommand's to be executed ! */ ! private void executeCommands(ArrayList commandList) { ! Iterator iter = commandList.iterator(); ! while (!iter.hasNext()) { ! execute1Command((RemoteDebuggerCommand)iter.next()); } } ! /** ! * Execute commands in an infinite loop. */ ! public void run() { ! try { ! while (!socket.isClosed()) { ! if (!commands.isEmpty()) { ! ArrayList toExecute = new ArrayList(); ! synchronized(commands) { ! while (!commands.isEmpty()) ! toExecute.add(commands.remove(0)); } ! executeCommands(toExecute); ! } ! if (fromServer.ready()) { ! char[] cbuf = new char[2048]; ! int howMany = fromServer.read(cbuf); ! System.out.print(new String(cbuf, 0, howMany)); } Thread.sleep(100); } - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO handle this - e.printStackTrace(); } } --- 9,305 ---- import java.net.*; import java.util.ArrayList; ! import java.util.Hashtable; ! ! import org.eclipse.core.runtime.CoreException; ! import org.eclipse.core.runtime.IProgressMonitor; ! import org.eclipse.core.runtime.IStatus; ! import org.eclipse.core.runtime.Status; ! import org.eclipse.debug.core.model.IProcess; ! import org.python.pydev.debug.core.PydevDebugPlugin; ! import org.python.pydev.debug.ui.launching.PythonRunnerConfig; /** * Network interface to the remote debugger. */ ! public class RemoteDebugger extends Object { ! private int sequence = -1; // sequence seed for command numbers ! ! private Socket socket; // connection socket ! private Reader reader; // reading thread ! private Writer writer; // writing thread ! private ListenConnector connector; // Runnable that connects to the debugger ! private Thread connectThread; // ! private PythonRunnerConfig config; ! private PyDebugTarget target = null; ! protected class ListenConnector implements Runnable { ! int port; ! int timeout; ! ServerSocket serverSocket; ! Socket socket; // what got accepted ! Exception e; ! ! boolean terminated; ! ! public ListenConnector(int port, int timeout) throws IOException { ! this.port = port; ! this.timeout = timeout; ! serverSocket = new ServerSocket(port); ! } ! ! Exception getException() { ! return e; ! } ! public Socket getSocket() { ! return socket; ! } ! public void stopListening() { ! if (serverSocket != null) ! try { ! serverSocket.close(); ! } catch (IOException e) { ! PydevDebugPlugin.log(IStatus.WARNING, "Error closing pydevd socket", e); ! } ! terminated = true; } ! public void run() { ! try { ! serverSocket.setSoTimeout(timeout); ! socket = serverSocket.accept(); ! } ! catch (IOException e) { ! this.e = e; ! } ! } } ! /** ! * Writer writes debugger commands to the network. ! * Use postCommand to put new ones in queue. ! */ ! protected class Writer implements Runnable { ! ArrayList cmdQueue; // a list of RemoteDebuggerCommands ! PrintWriter out; ! boolean done; ! ! public Writer(Socket s) throws IOException { ! done = false; ! cmdQueue = new ArrayList(); ! OutputStream sout; ! sout = s.getOutputStream(); ! out = new PrintWriter(new OutputStreamWriter(sout)); ! } ! ! /** ! * Add command for processing ! */ ! public void postCommand(RemoteDebuggerCommand cmd) { ! synchronized(cmdQueue) { ! cmdQueue.add(cmd); ! } ! } ! ! public void done() { ! this.done = true; ! } ! ! /** ! * Loops and writes commands to the output ! */ ! public void run() { ! while (!done) { ! RemoteDebuggerCommand cmd = null; ! synchronized (cmdQueue) { ! if (cmdQueue.size() > 0) ! cmd = (RemoteDebuggerCommand) cmdQueue.remove(0); ! } ! if (cmd != null) { ! cmd.aboutToSend(); ! out.write(cmd.getOutgoing()); ! out.write("\n"); ! out.flush(); ! } ! try { ! Thread.sleep(100); ! } catch (InterruptedException e) { ! // TODO Auto-generated catch block ! e.printStackTrace(); ! } ! } } } ! ! /** ! * Reads and dispatches commands */ ! protected class Reader implements Runnable { ! boolean done; ! Hashtable responseQueue; // commands waiting for response. Their keys are the sequence ids ! BufferedReader in; ! ! public Reader(Socket socket) throws IOException { ! done = false; ! responseQueue = new Hashtable(); ! InputStream sin = socket.getInputStream(); ! in = new BufferedReader(new InputStreamReader(sin)); ! } ! ! public void done() { ! this.done = true; ! } ! ! public void addToResponseQueue(RemoteDebuggerCommand cmd) { ! responseQueue.put(new Integer(cmd.getSequence()), cmd); ! Object o = responseQueue.remove(new Integer(cmd.getSequence())); ! System.out.println(o.toString()); ! responseQueue.put(new Integer(cmd.getSequence()), cmd); ! } ! ! /** ! * Parses & dispatches the command ! */ ! private void processCommand(String cmdLine) { ! int cmdCode; ! int seqCode; ! String payload; ! String[] cmdParsed = cmdLine.split("\t", 3); ! cmdCode = Integer.parseInt(cmdParsed[0]); ! seqCode = Integer.parseInt(cmdParsed[1]); ! payload = cmdParsed[2]; ! // is there a response waiting ! RemoteDebuggerCommand cmd = (RemoteDebuggerCommand)responseQueue.remove(new Integer(seqCode)); ! if (cmd == null) ! if (target != null) ! target.processCommand(cmdParsed[0], cmdParsed[1], cmdParsed[2]); ! else ! PydevDebugPlugin.log(IStatus.ERROR, "internal error, command received no target", null); ! else { ! if (cmdParsed[0].startsWith("9")) ! cmd.processErrorResponse(cmdCode, payload); ! else ! cmd.processResponse(cmdCode, payload); ! } ! } ! ! public void run() { ! while (!done) { ! try { ! if (in.ready()) { ! String cmdLine = in.readLine(); ! processCommand(cmdLine); } ! Thread.sleep(100); ! } catch (IOException e) { ! PydevDebugPlugin.log(IStatus.WARNING, "Unexpected termination of remote dbg input stream", e); ! } catch (InterruptedException e1) { ! e1.printStackTrace(); } + if (socket.isConnected() == false) + System.err.println("no longer connected"); + } + } + } + + public RemoteDebugger(PythonRunnerConfig config) { + this.config = config; + } + + public void setTarget(PyDebugTarget target) { + this.target = target; + } + + /** + * @return next available debugger command sequence number + */ + public int getNextSequence() { + sequence += 2; + return sequence; + } + + public void startConnect(IProgressMonitor monitor) throws IOException, CoreException { + monitor.subTask("Finding free socket..."); + connector = new ListenConnector(config.getDebugPort(), config.acceptTimeout); + connectThread = new Thread(connector, "pydevd.connect"); + connectThread.start(); + } + + /** + * Wait for the connection to the debugger to complete. + * + * If this method returns without an exception, we've connected. + * @return true if operation was cancelled by user + */ + public boolean waitForConnect(IProgressMonitor monitor, Process p, IProcess ip) throws Exception { + // Launch the debug listener on a thread, and wait until it completes + while (connectThread.isAlive()) { + if (monitor.isCanceled()) { + connector.stopListening(); + p.destroy(); + return true; + } + try { + p.exitValue(); // throws exception if process has terminated + // process has terminated - stop waiting for a connection + connector.stopListening(); + String errorMessage= ip.getStreamsProxy().getErrorStreamMonitor().getContents(); + if (errorMessage.length() != 0) + // not sure if this is really an error + throw new CoreException(new Status(IStatus.ERROR, PydevDebugPlugin.getPluginID(), 0, "Something got printed in the error stream", null)); + } catch (IllegalThreadStateException e) { + // expected while process is alive + } + try { Thread.sleep(100); + } catch (InterruptedException e) { } } + if (connector.getException() != null) + throw connector.getException(); + connected(connector.getSocket()); + return false; + } + + /** + * Remote debugger has connected + */ + public void connected(Socket socket) throws IOException { + this.socket = socket; + this.reader = new Reader(socket); + this.writer = new Writer(socket); + Thread t = new Thread(reader, "pydevd.reader"); + t.start(); + t = new Thread(writer, "pydevd.writer"); + t.start(); + writer.postCommand(new VersionCommand(this)); + } + /** + * Dispose must be called to clean up. + */ + public void dispose() { + if (connector != null) + connector.stopListening(); + if (reader != null) + reader.done(); + if (writer != null) + writer.done(); + if (socket != null && socket.isConnected()) + try { + socket.close(); + } catch (IOException e) { + // other end might have closed first + } + target = null; + } + + public void addToResponseQueue(RemoteDebuggerCommand cmd) { + reader.addToResponseQueue(cmd); + } + + public void postCommand(RemoteDebuggerCommand cmd) { + writer.postCommand(cmd); } --- NEW FILE: ModelUtils.java --- /* * Author: atotic * Created on Apr 22, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; import java.io.IOException; import java.io.StringBufferInputStream; import java.util.ArrayList; import java.util.Iterator; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.eclipse.debug.core.model.IThread; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Various utilities */ public class ModelUtils { /** * SAX parser for thread info * <xml><thread name="name" id="id"/><xml> */ static class XMLToThreadInfo extends DefaultHandler { public PyDebugTarget target; public ArrayList threads = new ArrayList(); public XMLToThreadInfo(PyDebugTarget target) { this.target = target; } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("thread")) { String name = attributes.getValue("name"); String id = attributes.getValue("id"); threads.add(new PyThread(target, name, id)); } } } /** * Creates IThread[] from the XML response */ static public IThread[] ThreadsFromXML(PyDebugTarget target, String payload) { IThread[] threads = null; try { SAXParserFactory parserFactory = SAXParserFactory.newInstance(); SAXParser parser = parserFactory.newSAXParser(); XMLToThreadInfo info = new XMLToThreadInfo(target); parser.parse(new StringBufferInputStream(payload), info); threads = new IThread[info.threads.size()]; Iterator it = info.threads.iterator(); int i = 0; while (it.hasNext()) threads[i++] = (IThread)it.next(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return threads; } } --- PythonDebugTarget.java DELETED --- --- NEW FILE: ListThreadsCommand.java --- /* * Author: atotic * Created on Apr 21, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; import org.eclipse.core.runtime.IStatus; import org.eclipse.debug.core.model.IThread; import org.python.pydev.debug.core.PydevDebugPlugin; /** * ListThreads command. * * See protocol for more info */ public class ListThreadsCommand extends RemoteDebuggerCommand { int sequence; boolean done; PyDebugTarget target; IThread[] threads; public ListThreadsCommand(RemoteDebugger debugger, PyDebugTarget target) { super(debugger); this.target = target; sequence = debugger.getNextSequence(); done = false; } public void waitUntilDone(int timeout) throws InterruptedException { while (!done && timeout > 0) { timeout -= 100; Thread.sleep(100); } if (timeout < 0) throw new InterruptedException(); } public IThread[] getThreads() { return threads; } public int getSequence() { return sequence; } public String getOutgoing() { return makeCommand(Integer.toString(CMD_LIST_THREADS), sequence, ""); } public boolean needResponse() { return true; } /** * The response is a list of threads */ public void processResponse(int cmdCode, String payload) { if (cmdCode != 102) { PydevDebugPlugin.log(IStatus.ERROR, "Unexpected response to LIST THREADS" + payload, null); return; } threads = ModelUtils.ThreadsFromXML(target, payload); done = true; } public void processErrorResponse(int cmdCode, String payload) { PydevDebugPlugin.log(IStatus.ERROR, "LIST THREADS got an error " + payload, null); } } --- NEW FILE: PyThread.java --- /* * Author: atotic * Created on Apr 21, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; import org.eclipse.core.resources.IResource; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; /** * Represents python threads. * * */ public class PyThread implements IThread { private PyDebugTarget target; private String name; private String id; public PyThread(PyDebugTarget target, String name, String id) { this.target = target; this.name = name; this.id = id; } public String getName() throws DebugException { return name; } public int getPriority() throws DebugException { // TODO maybe daemon status of the threads? return 0; } public String getModelIdentifier() { return target.getModelIdentifier(); } public IDebugTarget getDebugTarget() { return target; } public ILaunch getLaunch() { return target.getLaunch(); } public boolean canTerminate() { return true; } public boolean isTerminated() { return target.isTerminated(); } public void terminate() throws DebugException { System.out.print("Terminating thread"); } public boolean canResume() { // TODO Auto-generated method stub return false; } public boolean canSuspend() { // TODO Auto-generated method stub return true; } public boolean isSuspended() { // TODO Auto-generated method stub return false; } public void resume() throws DebugException { // TODO Auto-generated method stub } public void suspend() throws DebugException { // TODO Auto-generated method stub } public boolean canStepInto() { // TODO Auto-generated method stub return false; } public boolean canStepOver() { // TODO Auto-generated method stub return false; } public boolean canStepReturn() { // TODO Auto-generated method stub return false; } public boolean isStepping() { // TODO Auto-generated method stub return false; } public void stepInto() throws DebugException { // TODO Auto-generated method stub } public void stepOver() throws DebugException { // TODO Auto-generated method stub } public void stepReturn() throws DebugException { // TODO Auto-generated method stub } public IStackFrame[] getStackFrames() throws DebugException { // TODO Auto-generated method stub return null; } public boolean hasStackFrames() throws DebugException { // TODO Auto-generated method stub return false; } public IStackFrame getTopStackFrame() throws DebugException { // TODO Auto-generated method stub return null; } public IBreakpoint[] getBreakpoints() { // TODO Auto-generated method stub return null; } public Object getAdapter(Class adapter) { if (adapter.equals(ILaunch.class) || adapter.equals(IResource.class)) return target.getAdapter(adapter); // ongoing, I do not fully understand all the interfaces they'd like me to support System.err.println("PythonThread Need adapter " + adapter.toString()); return null; } } Index: RemoteDebuggerCommand.java =================================================================== RCS file: /cvsroot/pydev/org.python.pydev.debug/src/org/python/pydev/debug/model/RemoteDebuggerCommand.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** RemoteDebuggerCommand.java 29 Mar 2004 17:07:25 -0000 1.1 --- RemoteDebuggerCommand.java 22 Apr 2004 10:56:18 -0000 1.2 *************** *** 6,79 **** package org.python.pydev.debug.model; /** ! * Interacts with jpydaemon.py. * ! * Knows how to create and interpret jpydaemon commands. * ! * jpydaemon commands: * - * STOP: exits the debugger - * CMD <command>: takes a command and executes it - - success: - <JPY> <COMMAND cmd="CMD a=1" operation="a=1" result="OK" /></JPY> - <JPY> <STDOUT content="1" /></JPY> - <JPY> <STDOUT content="/EOL/" /></JPY> - <JPY> <COMMAND cmd="CMD print a" operation="print a" result="OK" /></JPY> - error: - <JPY> <COMMAND cmd="CMD er!" operation="er!" result="Error on CMD" /></JPY> - <JPY> <COMMANDDETAIL content="Traceback (most recent call last):" /></JPY> - <JPY> <COMMANDDETAIL content=" File "D:\pydevspace2\org.python.pydev.debug\pysrc\jpydaemon.py", line 231, in dealWithCmd code = compile( arg ,"<string>" , cmdType)" /></JPY> - <JPY> <COMMANDDETAIL content=" File "<string>", line 1" /></JPY> - <JPY> <COMMANDDETAIL content=" er!" /></JPY> - <JPY> <COMMANDDETAIL content=" ^" /></JPY> - <JPY> <COMMANDDETAIL content="SyntaxError: unexpected EOF while parsing" /></JPY> - - * READSRC <filename>: reads in the whole file - * SETARGS : sets arguments before we start execution - <JPY> <COMMAND cmd="SETARGS -u -v" operation="-u -v" result="OK" /></JPY> - - * DBG: - <JPY><COMMAND cmd="DBG test.py" /></JPY> - <JPY> <LINE cmd="31" fn="<string>" lineno="1" name="?" line="" /></JPY> */ ! public class RemoteDebuggerCommand { ! public final static String VERSION = "JpyDbg 0.0.3" ; ! public final static int INACTIVE = 0 ; ! public final static int STARTING = 1 ; ! public final static int STARTED = 2 ; ! ! private final static String _ERROR_ = "ERROR:" ; ! private final static String _END_OF_LINE_ = "\n" ; ! private final static String _INACTIVE_TEXT_ = "inactive" ; ! private final static String _READY_TEXT_ = "ready" ; ! private final static String _STRING_ ="<string>" ; ! private final static String _EOL_ = "/EOL/" ; ! private final static String _OK_ = "OK" ; ! ! private final static String _COMMAND_ = "CMD " ; ! private final static String _BPSET_ = "BP+ " ; ! private final static String _BPCLEAR_ = "BP- " ; ! private final static String _DBG_ = "DBG " ; ! private final static String _SETARGS_ = "SETARGS " ; ! private final static String _READSRC_ = "READSRC " ; ! private final static String _NEXT_ = "NEXT " ; ! private final static String _SET_ = "set " ; ! private final static String _STEP_ = "STEP " ; ! private final static String _RUN_ = "RUN " ; ! private final static String _STOP_ = "STOP " ; ! private final static String _STACK_ = "STACK " ; ! private final static String _GLOBALS_ = "GLOBALS " ; ! private final static String _GLOBAL_ = "global" ; ! private final static String _EQUAL_ = "=" ; ! private final static String _SEMICOLON_= ";" ; ! private final static String _SILENT_ = "silent" ; ! private final static String _LOCALS_ = "LOCALS " ; ! private final static String _SPACE_ = " " ; ! String xmlMessage; ! public String getXMLMessage() { ! return xmlMessage; } } --- 6,99 ---- package org.python.pydev.debug.model; + import org.eclipse.core.runtime.IStatus; + import org.python.pydev.debug.core.PydevDebugPlugin; + /** ! * Superclass of all debugger commands. * ! * Debugger commands know how to interact with pydevd.py. ! * See pydevd.py for protocol information. * ! * Command lifecycle: ! * cmd = new Command() // creation ! * cmd.getSequence() // get the sequence number of the command ! * cmd.getOutgoing() // asks command for outgoing message ! * cmd.aboutToSend() // called right before we go on wire ! * // by default, if command needs response ! * // it gets posted to in the response queue ! * if (cmd.needsResponse()) ! * post the command to response queue, otherwise we are done ! * when response arrives: ! * if response is an error ! * cmd.processResponse() ! * else ! * cmd.processErrorResponse() * */ ! public abstract class RemoteDebuggerCommand { ! ! static final int CMD_LIST_THREADS = 102; ! static final int CMD_THREAD_CREATED = 103; ! static final int CMD_ERROR = 501; ! static final int CMD_VERSION = 901; ! static final int CMD_RETURN = 902; ! ! protected RemoteDebugger debugger; ! ! public RemoteDebuggerCommand(RemoteDebugger debugger) { ! this.debugger = debugger; ! } ! /** ! * @return outgoing message ! */ ! public abstract String getOutgoing(); ! /** ! * Notification right before the command is sent. ! * If subclassed, call super() ! */ ! public void aboutToSend() { ! // if we need a response, put me on the waiting queue ! if (needResponse()) ! debugger.addToResponseQueue(this); ! } ! ! /** ! * Does this command require a response? ! */ ! public boolean needResponse() { ! return false; ! } ! ! /** ! * returns Sequence # ! */ ! public int getSequence() { ! System.err.println("Fatal: must override getSequence"); ! PydevDebugPlugin.log(IStatus.ERROR, "getSequence must be overridden", null); ! return 0; ! } ! ! /** ! * notification of the response to the command. ! * You'll get either processResponse or processErrorResponse ! */ ! public void processResponse(int cmdCode, String payload) { ! PydevDebugPlugin.log(IStatus.ERROR, "Debugger command ignored response " + getClass().toString() + payload, null); ! } ! ! public void processErrorResponse(int cmdCode, String payload) { ! PydevDebugPlugin.log(IStatus.ERROR, "Debugger command ignored error response " + getClass().toString() + payload, null); ! } ! ! public static String makeCommand(String code, int sequence, String payload) { ! StringBuffer s = new StringBuffer(); ! s.append(code); ! s.append("\t"); ! s.append(sequence); ! s.append("\t"); ! s.append(payload); ! return s.toString(); } } --- NEW FILE: PyDebugTarget.java --- /* * Author: atotic * Created on Mar 23, 2004 * License: Common Public License v1.0 */ package org.python.pydev.debug.model; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchListener; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IMemoryBlock; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IThread; import org.python.pydev.debug.core.PydevDebugPlugin; /** * * TODO Comment this class * Make sure we fire the right org.eclipse.debug.core.DebugEvents */ public class PyDebugTarget implements IDebugTarget, ILaunchListener { ILaunch launch; IProcess process; RemoteDebugger debugger; IPath file; IThread[] threads; public PyDebugTarget(ILaunch launch, IProcess process, IPath file, RemoteDebugger debugger) { this.launch = launch; this.process = process; this.file = file; this.debugger = debugger; this.threads = new IThread[0]; launch.addDebugTarget(this); debugger.setTarget(this); // we have to know when we get removed, so that we can shut off the debugger DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); } public void launchRemoved(ILaunch launch) { // shut down the remote debugger when parent launch if (launch == this.launch) { debugger.dispose(); debugger = null; } } public void launchAdded(ILaunch launch) { // noop } public void launchChanged(ILaunch launch) { // noop } // From IDebugElement public String getModelIdentifier() { return PydevDebugPlugin.getPluginID(); } // From IDebugElement public IDebugTarget getDebugTarget() { return this; } // From IDebugElement public ILaunch getLaunch() { return launch; } public IProcess getProcess() { return process; } public String getName() throws DebugException { if (file != null) return file.lastSegment(); else return "unknown"; } public boolean canTerminate() { // We can always terminate, it makes no harm return true; } public boolean isTerminated() { return process.isTerminated(); } public void terminate() throws DebugException { process.terminate(); } public boolean canDisconnect() { // TODO NOW Auto-generated method stub return true; } public void disconnect() throws DebugException { // TODO Auto-generated method stub } public boolean isDisconnected() { // TODO NOW Auto-generated method stub return false; } public boolean canResume() { // TODO NOW Auto-generated method stub return false; } public boolean canSuspend() { // TODO NOW Auto-generated method stub return true; } public boolean isSuspended() { // TODO Auto-generated method stub return false; } public void resume() throws DebugException { // TODO Auto-generated method stub } public void suspend() throws DebugException { // TODO Auto-generated method stub } public IThread[] getThreads() throws DebugException { if (threads == null) { ListThreadsCommand cmd = new ListThreadsCommand(debugger, this); debugger.postCommand(cmd); try { cmd.waitUntilDone(1000); threads = cmd.getThreads(); } catch (InterruptedException e) { threads = new IThread[0]; } } return threads; } public boolean hasThreads() throws DebugException { return true; } public boolean supportsBreakpoint(IBreakpoint breakpoint) { // TODO Auto-generated method stub return false; } public void breakpointAdded(IBreakpoint breakpoint) { // TODO Auto-generated method stub } public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { // TODO Auto-generated method stub } public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { // TODO Auto-generated method stub } public boolean supportsStorageRetrieval() { // TODO Auto-generated method stub return false; } public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { // TODO Auto-generated method stub return null; } public Object getAdapter(Class adapter) { // TODO Auto-generated method stub if (adapter.equals(ILaunch.class)) return launch; else if (adapter.equals(IResource.class)) { IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation(file); if (files != null && files.length > 0) return files[0]; else return null; } else System.err.println("Need adapter " + adapter.toString()); return null; } /** * When a command that originates from daemon is received, * this routine processes it. * The responses to commands originating from here * are processed by commands themselves */ public void processCommand(String sCmdCode, String sSeqCode, String payload) { int cmdCode = Integer.parseInt(sCmdCode); int seqCode = Integer.parseInt(sSeqCode); if (cmdCode == RemoteDebuggerCommand.CMD_THREAD_CREATED) processThreadCreated(payload); else PydevDebugPlugin.log(IStatus.WARNING, "Unexpected debugger command" + sCmdCode, null); } private void fireEvent(DebugEvent event) { DebugPlugin manager= DebugPlugin.getDefault(); if (manager != null) { manager.fireDebugEventSet(new DebugEvent[]{event}); } } private void processThreadCreated(String payload) { IThread[] newThreads = ModelUtils.ThreadsFromXML(this, payload); if (threads == null) threads = newThreads; else { IThread[] combined = new IThread[threads.length + newThreads.length]; int i = 0; for (i = 0; i < threads.length; i++) combined[i] = threads[i]; for (int j = 0; j < newThreads.length; i++, j++) combined[i] = newThreads[j]; threads = combined; } // Now notify debugger that new threads were added for (int i =0; i< newThreads.length; i++) fireEvent(new DebugEvent(newThreads[i], DebugEvent.CREATE)); } } |