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 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 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.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); } }