X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/core/DebugConnection.java b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/core/DebugConnection.java new file mode 100644 index 0000000..64c8550 --- /dev/null +++ b/net.sourceforge.phpeclipse.xdebug.core/src/net/sourceforge/phpeclipse/xdebug/core/DebugConnection.java @@ -0,0 +1,408 @@ +package net.sourceforge.phpeclipse.xdebug.core; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + + +import net.sourceforge.phpeclipse.xdebug.php.model.XDebugLineBreakpoint; +import net.sourceforge.phpeclipse.xdebug.php.model.XDebugTarget; +import net.sourceforge.phpeclipse.xdebug.php.model.XDebugThread; + +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.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IThread; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +public class DebugConnection { + + private ServerSocket fDebugServerSocket; + private DebugResponse lastResponse; + private Socket fDebugSocket; + private OutputStreamWriter fDebugWriter; + private DataInputStream fDebugReader; + private ResponseListenerJob fResponseListener; + + // Settings for Debug Process + private int fTransactionID=0; + private String fileuri = ""; + private String appID=""; + private String lastCommand = ""; + private XDebugTarget fDebugTarget; + private HashMap ResponseList; + + public class DebugResponse { + + private Node parentNode; + private int fTransactionID=-1; + private String fCommand=""; + private String fStatus; + private String fReason; + private String fName; + private boolean fError; + + public synchronized void setParentNode (String xmlInput){ + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder=null; + Document doc=null; + try { + builder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + ByteArrayInputStream InputXMLStream = new ByteArrayInputStream(xmlInput.getBytes()); + + try { + doc = builder.parse(InputXMLStream); + } catch (SAXException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + parentNode=doc.getFirstChild(); + fName=parentNode.getNodeName(); + String idStr = getAttributeValue("transaction_id"); + if (idStr!="") + fTransactionID = Integer.parseInt(idStr); + fCommand = getAttributeValue("command"); + fStatus = getAttributeValue("status"); + fReason = getAttributeValue("reason"); +// notifyAll(); + } + + public String getAttributeValue (String AttributeName) { + String strValue = ""; + if (parentNode.hasAttributes()) { + NamedNodeMap listAttribute = parentNode.getAttributes(); + Node attribute = listAttribute.getNamedItem(AttributeName); + if (attribute !=null) + strValue = attribute.getNodeValue(); + } + return strValue; + } + + public synchronized Node getParentNode(){ + return parentNode; + } + + public synchronized String getCommand() { + return fCommand; + } + public synchronized String getName() { + return fName; + } + + + DebugResponse () { + fTransactionID = -1; + fCommand = ""; + fStatus = ""; + fReason = ""; + fName= ""; + } + + DebugResponse (String XMLInput) { + setParentNode(XMLInput); + } + + public synchronized String getReason() { + return fReason; + } + + public synchronized String getStatus() { + return fStatus; + } + + public synchronized int getTransactionID() { + return fTransactionID; + } + + private synchronized DebugResponse waitforTransactionID(int id) { + while (fTransactionID!= id) { + try { + wait(); + } catch (InterruptedException e) { + } + } +// XDebugCorePlugin.log(IStatus.INFO,"got TransID: "+id); + + return this; + } + + public boolean isError() { + return fError; + } + + public void setError(boolean error) { + fError = error; + } + + protected synchronized void notifyWait() { + notifyAll(); + } + } + + + /** + * Listens to events from the XDebug and fires corresponding + * debug events. + */ + class ResponseListenerJob extends Job { + + public ResponseListenerJob() { + super("XDebug Event Dispatch"); + setSystem(true); + + } + + + + + private void checkResponse(DebugResponse response) { + Node node=response.getParentNode(); + if (node.hasChildNodes()) { + Node child=node.getFirstChild(); + if (child.getNodeName().equals("error")) { + int code = Integer.parseInt(PHPDebugUtils.getAttributeValue(child, "code")); + String text=(child.getFirstChild()).getNodeValue(); + XDebugCorePlugin.log(IStatus.ERROR,lastCommand+" ERROR "+code+": "+text); + lastResponse.setError(true); + return; + } + } + lastResponse.setError(false); + if (response.getStatus().equals("stopped")) + terminated(); + else if (response.getStatus().equals("break") && response.getReason().equals("ok")){ + if (response.getCommand().equals("run")) { // breakpoint hit + int id=-1; + try { + id=sendRequest("stack_get"); + } catch (DebugException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + String InputXML = readData(); + if (InputXML != null) { + XDebugCorePlugin.log(IStatus.INFO, InputXML); + lastResponse.setParentNode(InputXML); + fDebugTarget.breakpointHit(lastResponse.getParentNode()); + } + + } else if (response.getCommand().equals("step_into")) { // step_into + fDebugTarget.suspended(DebugEvent.STEP_END); +// XDebugCorePlugin.log(IStatus.INFO,response.getCommand()+" STEP_END sent"); + } else if (response.getCommand().equals("step_over")) { // step_over + fDebugTarget.suspended(DebugEvent.STEP_END); +// XDebugCorePlugin.log(IStatus.INFO,response.getCommand()+" STEP_END sent"); + } else if (response.getCommand().equals("step_out")) { // step_over + fDebugTarget.suspended(DebugEvent.STEP_END); +// XDebugCorePlugin.log(IStatus.INFO,response.getCommand()+" STEP_END sent"); + } + } else if (response.getCommand().equals("breakpoint_set")) { // step_over + String idStr=response.getAttributeValue("id"); + if (idStr!="") { + int targetID=response.getTransactionID(); + BreakpointResponseData ResponseData= new BreakpointResponseData(response.getTransactionID(),Integer.parseInt(idStr)); + + fDebugTarget.fireDebugResponseEvent(ResponseData); + IBreakpoint[] breakpoints=XDebugCorePlugin.getBreakpoints(); + for(int i=0;i< breakpoints.length;i++) { + XDebugLineBreakpoint breakpoint=(XDebugLineBreakpoint)breakpoints[i]; + try { + if (breakpoint.getID()==targetID) + breakpoint.setID(Integer.parseInt(idStr)); + } catch (NumberFormatException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + protected IStatus run(IProgressMonitor monitor) { + String InputXML = ""; + while (!fDebugTarget.isTerminated() && (InputXML != null)) { + InputXML = readData(); + if (InputXML != null) { + XDebugCorePlugin.log(IStatus.INFO, InputXML); + lastResponse.setParentNode(InputXML); + if (lastResponse.getName() == "init") { + Node myNode=lastResponse.getParentNode(); + appID = PHPDebugUtils.getAttributeValue(myNode, "appid"); + fileuri = PHPDebugUtils.getAttributeValue(myNode, "fileuri"); +// fDebugTarget.started(); + fDebugTarget.fireCreationEvent(); + } else if (lastResponse.getName() == "response") { + checkResponse(lastResponse); + } + ResponseList.put(new Integer(lastResponse.getTransactionID()),lastResponse); + lastResponse.notifyWait(); + } + } + return Status.OK_STATUS; + } + + } + + + public DebugConnection (XDebugTarget debugTarget,int debugPort) { + fDebugTarget=debugTarget; + lastResponse=new DebugResponse(); + ResponseList= new HashMap(); + + try { + fDebugServerSocket = new ServerSocket(debugPort); + fDebugSocket = fDebugServerSocket.accept(); + fDebugWriter = new OutputStreamWriter(fDebugSocket.getOutputStream(), "UTF8"); + fDebugReader = new DataInputStream(fDebugSocket.getInputStream()); +// fDebugReader = new BufferedReader(new InputStreamReader(fDebugSocket.getInputStream())); + + } catch (UnknownHostException e) { +// abort("Unable to connect to PHP Debuger", e); + } catch (IOException e) { +// abort("Unable to connect to PHP Debuger", e); + } + fResponseListener = new ResponseListenerJob(); + fResponseListener.schedule(); + + } + + private void terminated() { + try { + fDebugReader.close(); + fDebugWriter.close(); + fDebugSocket.close(); + fDebugServerSocket.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + fDebugTarget.terminated(); + + } + + private String readData() + { + byte byteBuffer[]=null,b; + int count=0; + + try { + while ( (b =fDebugReader.readByte())!=0) + { + count=count*10+b-'0'; +// count=count*10+Integer.parseInt(b); + } +// System.out.println(count); + byteBuffer = new byte[count]; + int readCount=0; + int attempts=0; + while ((count >0) && (attempts <5)) { + int rc=fDebugReader.read(byteBuffer,readCount,count); + count-=rc; + readCount+=rc; + attempts++; + } + if((b= fDebugReader.readByte())!=0) // reads the NULL Byte at the end; + System.out.println("NULL-Byte missing!!"); + } catch (IOException e) { + // TODO Auto-generated catch block + if (e instanceof EOFException==false) + e.printStackTrace(); + return null; + } + return new String(byteBuffer); + } + + + /** + * Sends a request to the Debugengine and waits for an OK. + * + * @param command debug command + * @throws DebugException if the request fails + */ + + + public int sendRequest(String command) throws DebugException { + return sendRequest(command,""); + } + + /** + * Sends a request to the Debugengine and waits for an OK. + * + * @param command debug command + * @arguments arguments for the command + * @throws DebugException if the request fails + */ + + public synchronized int sendRequest(String command, String arguments) throws DebugException { + +// System.out.println(command+" -i "+transactionID+" "+arguments); + XDebugCorePlugin.log(IStatus.INFO,command+" -i "+fTransactionID+" "+arguments); + synchronized (fDebugSocket) { + try { + fDebugWriter.write(command); + fDebugWriter.write(" -i " + fTransactionID); + if (arguments!="") + fDebugWriter.write(" " + arguments); + fDebugWriter.write(0); + fDebugWriter.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return fTransactionID++; + } + + public DebugResponse waitforTransID(int id) { + if (ResponseList.containsKey(new Integer(id))) + { +// return (DebugResponse)ResponseList.get(new Integer(id)); + return (DebugResponse)ResponseList.remove(new Integer(id)); + } + else + return lastResponse.waitforTransactionID(id); + } + + public DebugResponse getResponse(int id) { + if (ResponseList.containsKey(new Integer(id))) + return (DebugResponse)ResponseList.get(new Integer(id)); + else + return waitforTransID(id); + } + + + +}