1 package net.sourceforge.phpeclipse.xdebug.core;
3 import java.io.ByteArrayInputStream;
4 import java.io.DataInputStream;
5 import java.io.EOFException;
6 import java.io.IOException;
7 import java.io.OutputStreamWriter;
8 import java.net.ServerSocket;
9 import java.net.Socket;
10 import java.net.UnknownHostException;
11 import java.util.HashMap;
12 import java.util.LinkedList;
15 import javax.xml.parsers.DocumentBuilder;
16 import javax.xml.parsers.DocumentBuilderFactory;
17 import javax.xml.parsers.ParserConfigurationException;
20 import net.sourceforge.phpeclipse.xdebug.php.model.XDebugLineBreakpoint;
21 import net.sourceforge.phpeclipse.xdebug.php.model.XDebugTarget;
22 import net.sourceforge.phpeclipse.xdebug.php.model.XDebugThread;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.core.runtime.IStatus;
27 import org.eclipse.core.runtime.Status;
28 import org.eclipse.core.runtime.jobs.Job;
29 import org.eclipse.debug.core.DebugEvent;
30 import org.eclipse.debug.core.DebugException;
31 import org.eclipse.debug.core.model.IBreakpoint;
32 import org.eclipse.debug.core.model.IThread;
33 import org.w3c.dom.Document;
34 import org.w3c.dom.NamedNodeMap;
35 import org.w3c.dom.Node;
36 import org.xml.sax.SAXException;
38 public class DebugConnection {
40 private ServerSocket fDebugServerSocket;
41 private DebugResponse lastResponse;
42 private Socket fDebugSocket;
43 private OutputStreamWriter fDebugWriter;
44 private DataInputStream fDebugReader;
45 private ResponseListenerJob fResponseListener;
47 // Settings for Debug Process
48 private int fTransactionID=0;
49 private String fileuri = "";
50 private String appID="";
51 private String lastCommand = "";
52 private XDebugTarget fDebugTarget;
53 private HashMap ResponseList;
55 public class DebugResponse {
57 private Node parentNode;
58 private int fTransactionID=-1;
59 private String fCommand="";
60 private String fStatus;
61 private String fReason;
63 private boolean fError;
65 public synchronized void setParentNode (String xmlInput){
66 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
67 DocumentBuilder builder=null;
70 builder = factory.newDocumentBuilder();
71 } catch (ParserConfigurationException e) {
72 // TODO Auto-generated catch block
75 ByteArrayInputStream InputXMLStream = new ByteArrayInputStream(xmlInput.getBytes());
78 doc = builder.parse(InputXMLStream);
79 } catch (SAXException e) {
80 // TODO Auto-generated catch block
82 } catch (IOException e) {
83 // TODO Auto-generated catch block
86 parentNode=doc.getFirstChild();
87 fName=parentNode.getNodeName();
88 String idStr = getAttributeValue("transaction_id");
90 fTransactionID = Integer.parseInt(idStr);
91 fCommand = getAttributeValue("command");
92 fStatus = getAttributeValue("status");
93 fReason = getAttributeValue("reason");
97 public String getAttributeValue (String AttributeName) {
99 if (parentNode.hasAttributes()) {
100 NamedNodeMap listAttribute = parentNode.getAttributes();
101 Node attribute = listAttribute.getNamedItem(AttributeName);
102 if (attribute !=null)
103 strValue = attribute.getNodeValue();
108 public synchronized Node getParentNode(){
112 public synchronized String getCommand() {
115 public synchronized String getName() {
128 DebugResponse (String XMLInput) {
129 setParentNode(XMLInput);
132 public synchronized String getReason() {
136 public synchronized String getStatus() {
140 public synchronized int getTransactionID() {
141 return fTransactionID;
144 private synchronized DebugResponse waitforTransactionID(int id) {
145 while (fTransactionID!= id) {
148 } catch (InterruptedException e) {
151 // XDebugCorePlugin.log(IStatus.INFO,"got TransID: "+id);
156 public boolean isError() {
160 public void setError(boolean error) {
164 protected synchronized void notifyWait() {
171 * Listens to events from the XDebug and fires corresponding
174 class ResponseListenerJob extends Job {
176 public ResponseListenerJob() {
177 super("XDebug Event Dispatch");
185 private void checkResponse(DebugResponse response) {
186 Node node=response.getParentNode();
187 if (node.hasChildNodes()) {
188 Node child=node.getFirstChild();
189 if (child.getNodeName().equals("error")) {
190 int code = Integer.parseInt(PHPDebugUtils.getAttributeValue(child, "code"));
191 String text=(child.getFirstChild()).getNodeValue();
192 XDebugCorePlugin.log(IStatus.ERROR,lastCommand+" ERROR "+code+": "+text);
193 lastResponse.setError(true);
197 lastResponse.setError(false);
198 if (response.getStatus().equals("stopped"))
200 else if (response.getStatus().equals("break") && response.getReason().equals("ok")){
201 if (response.getCommand().equals("run")) { // breakpoint hit
204 id=sendRequest("stack_get");
205 } catch (DebugException e) {
206 // TODO Auto-generated catch block
209 String InputXML = readData();
210 if (InputXML != null) {
211 XDebugCorePlugin.log(IStatus.INFO, InputXML);
212 lastResponse.setParentNode(InputXML);
213 fDebugTarget.breakpointHit(lastResponse.getParentNode());
216 } else if (response.getCommand().equals("step_into")) { // step_into
217 fDebugTarget.suspended(DebugEvent.STEP_END);
218 // XDebugCorePlugin.log(IStatus.INFO,response.getCommand()+" STEP_END sent");
219 } else if (response.getCommand().equals("step_over")) { // step_over
220 fDebugTarget.suspended(DebugEvent.STEP_END);
221 // XDebugCorePlugin.log(IStatus.INFO,response.getCommand()+" STEP_END sent");
222 } else if (response.getCommand().equals("step_out")) { // step_over
223 fDebugTarget.suspended(DebugEvent.STEP_END);
224 // XDebugCorePlugin.log(IStatus.INFO,response.getCommand()+" STEP_END sent");
226 } else if (response.getCommand().equals("breakpoint_set")) { // step_over
227 String idStr=response.getAttributeValue("id");
229 int targetID=response.getTransactionID();
230 BreakpointResponseData ResponseData= new BreakpointResponseData(response.getTransactionID(),Integer.parseInt(idStr));
232 fDebugTarget.fireDebugResponseEvent(ResponseData);
233 IBreakpoint[] breakpoints=XDebugCorePlugin.getBreakpoints();
234 for(int i=0;i< breakpoints.length;i++) {
235 XDebugLineBreakpoint breakpoint=(XDebugLineBreakpoint)breakpoints[i];
237 if (breakpoint.getID()==targetID)
238 breakpoint.setID(Integer.parseInt(idStr));
239 } catch (NumberFormatException e) {
240 // TODO Auto-generated catch block
242 } catch (CoreException e) {
243 // TODO Auto-generated catch block
253 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
255 protected IStatus run(IProgressMonitor monitor) {
256 String InputXML = "";
257 while (!fDebugTarget.isTerminated() && (InputXML != null)) {
258 InputXML = readData();
259 if (InputXML != null) {
260 XDebugCorePlugin.log(IStatus.INFO, InputXML);
261 lastResponse.setParentNode(InputXML);
262 if (lastResponse.getName() == "init") {
263 Node myNode=lastResponse.getParentNode();
264 appID = PHPDebugUtils.getAttributeValue(myNode, "appid");
265 fileuri = PHPDebugUtils.getAttributeValue(myNode, "fileuri");
266 // fDebugTarget.started();
267 fDebugTarget.fireCreationEvent();
268 } else if (lastResponse.getName() == "response") {
269 checkResponse(lastResponse);
271 ResponseList.put(new Integer(lastResponse.getTransactionID()),lastResponse);
272 lastResponse.notifyWait();
275 return Status.OK_STATUS;
281 public DebugConnection (XDebugTarget debugTarget,int debugPort) {
282 fDebugTarget=debugTarget;
283 lastResponse=new DebugResponse();
284 ResponseList= new HashMap();
287 fDebugServerSocket = new ServerSocket(debugPort);
288 fDebugSocket = fDebugServerSocket.accept();
289 fDebugWriter = new OutputStreamWriter(fDebugSocket.getOutputStream(), "UTF8");
290 fDebugReader = new DataInputStream(fDebugSocket.getInputStream());
291 // fDebugReader = new BufferedReader(new InputStreamReader(fDebugSocket.getInputStream()));
293 } catch (UnknownHostException e) {
294 // abort("Unable to connect to PHP Debuger", e);
295 } catch (IOException e) {
296 // abort("Unable to connect to PHP Debuger", e);
298 fResponseListener = new ResponseListenerJob();
299 fResponseListener.schedule();
303 private void terminated() {
305 fDebugReader.close();
306 fDebugWriter.close();
307 fDebugSocket.close();
308 fDebugServerSocket.close();
309 } catch (IOException e) {
310 // TODO Auto-generated catch block
313 fDebugTarget.terminated();
317 private String readData()
319 byte byteBuffer[]=null,b;
323 while ( (b =fDebugReader.readByte())!=0)
325 count=count*10+b-'0';
326 // count=count*10+Integer.parseInt(b);
328 // System.out.println(count);
329 byteBuffer = new byte[count];
332 while ((count >0) && (attempts <5)) {
333 int rc=fDebugReader.read(byteBuffer,readCount,count);
338 if((b= fDebugReader.readByte())!=0) // reads the NULL Byte at the end;
339 System.out.println("NULL-Byte missing!!");
340 } catch (IOException e) {
341 // TODO Auto-generated catch block
342 if (e instanceof EOFException==false)
346 return new String(byteBuffer);
351 * Sends a request to the Debugengine and waits for an OK.
353 * @param command debug command
354 * @throws DebugException if the request fails
358 public int sendRequest(String command) throws DebugException {
359 return sendRequest(command,"");
363 * Sends a request to the Debugengine and waits for an OK.
365 * @param command debug command
366 * @arguments arguments for the command
367 * @throws DebugException if the request fails
370 public synchronized int sendRequest(String command, String arguments) throws DebugException {
372 // System.out.println(command+" -i "+transactionID+" "+arguments);
373 XDebugCorePlugin.log(IStatus.INFO,command+" -i "+fTransactionID+" "+arguments);
374 synchronized (fDebugSocket) {
376 fDebugWriter.write(command);
377 fDebugWriter.write(" -i " + fTransactionID);
379 fDebugWriter.write(" " + arguments);
380 fDebugWriter.write(0);
381 fDebugWriter.flush();
382 } catch (IOException e) {
386 return fTransactionID++;
389 public DebugResponse waitforTransID(int id) {
390 if (ResponseList.containsKey(new Integer(id)))
392 // return (DebugResponse)ResponseList.get(new Integer(id));
393 return (DebugResponse)ResponseList.remove(new Integer(id));
396 return lastResponse.waitforTransactionID(id);
399 public DebugResponse getResponse(int id) {
400 if (ResponseList.containsKey(new Integer(id)))
401 return (DebugResponse)ResponseList.get(new Integer(id));
403 return waitforTransID(id);