blob: 65bffb0275e72874464bb3c298e97816e43230f7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ant.internal.ui.antsupport.logger.debug;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.Location;
import org.apache.tools.ant.Task;
import org.eclipse.ant.internal.ui.antsupport.logger.RemoteAntBuildLogger;
/**
* Parts adapted from org.eclipse.jdt.internal.junit.runner.RemoteTestRunner
* A build logger that reports via a socket connection.
* See DebugMessageIds and MessageIds for more information about the protocol.
*/
public class RemoteAntDebugBuildLogger extends RemoteAntBuildLogger {
private ServerSocket fServerSocket;
private Socket fRequestSocket;
private PrintWriter fRequestWriter;
private BufferedReader fRequestReader;
protected boolean fStepOverSuspend= false;
protected boolean fStepIntoSuspend= false;
protected boolean fClientSuspend= false;
protected boolean fShouldSuspend= false;
private Stack fTasks= new Stack();
private Task fCurrentTask;
private Task fStepOverTask;
private Task fLastTaskFinished;
private List fBreakpoints= null;
private Map fProperties= null;
/**
* Request port to connect to.
* Used for debug connections
*/
protected int fRequestPort= -1;
/**
* Reader thread that processes requests from the debug client.
*/
private class ReaderThread extends Thread {
public ReaderThread() {
super("ReaderThread"); //$NON-NLS-1$
setDaemon(true);
}
public void run(){
try {
String message= null;
while (fRequestReader != null) {
if ((message= fRequestReader.readLine()) != null) {
if (message.startsWith(DebugMessageIds.STEP_INTO)){
synchronized(RemoteAntDebugBuildLogger.this) {
fStepIntoSuspend= true;
RemoteAntDebugBuildLogger.this.notifyAll();
}
} if (message.startsWith(DebugMessageIds.STEP_OVER)){
synchronized(RemoteAntDebugBuildLogger.this) {
fStepOverSuspend= true;
fStepOverTask= fCurrentTask;
RemoteAntDebugBuildLogger.this.notifyAll();
}
} else if (message.startsWith(DebugMessageIds.SUSPEND)) {
synchronized(RemoteAntDebugBuildLogger.this) {
fClientSuspend= true;
}
} else if (message.startsWith(DebugMessageIds.RESUME)) {
synchronized(RemoteAntDebugBuildLogger.this) {
RemoteAntDebugBuildLogger.this.notifyAll();
}
} else if (message.startsWith(DebugMessageIds.TERMINATE)) {
sendRequestResponse(DebugMessageIds.TERMINATED);
shutDown();
} else if (message.startsWith(DebugMessageIds.STACK)) {
marshallStack();
} else if (message.startsWith(DebugMessageIds.ADD_BREAKPOINT)) {
addBreakpoint(message);
} else if (message.startsWith(DebugMessageIds.REMOVE_BREAKPOINT)) {
removeBreakpoint(message);
} else if (message.startsWith(DebugMessageIds.PROPERTIES)) {
marshallProperties();
}
}
}
} catch (Exception e) {
RemoteAntDebugBuildLogger.this.shutDown();
}
}
}
private void requestConnect() {
if (fDebugMode) {
System.out.println("RemoteAntDebugBuildLogger: trying to connect" + fHost + ":" + fRequestPort); //$NON-NLS-1$ //$NON-NLS-2$
}
try{
fRequestSocket= fServerSocket.accept();
fRequestWriter= new PrintWriter(fRequestSocket.getOutputStream(), true);
fRequestReader = new BufferedReader(new InputStreamReader(fRequestSocket.getInputStream()));
ReaderThread readerThread= new ReaderThread();
readerThread.setDaemon(true);
readerThread.start();
return;
} catch(IOException e){
}
shutDown();
//throw new BUildExection()
}
/* (non-Javadoc)
* @see org.eclipse.ant.internal.ui.antsupport.logger.RemoteAntBuildLogger#shutDown()
*/
protected void shutDown() {
if (fRequestWriter != null) {
fRequestWriter.close();
fRequestWriter= null;
}
if (fRequestReader != null) {
try {
fRequestReader.close();
} catch (IOException e) {
}
fRequestReader= null;
}
if (fRequestSocket != null) {
try {
fRequestSocket.close();
} catch(IOException e) {
}
}
fRequestSocket= null;
super.shutDown();
}
/* (non-Javadoc)
* @see org.apache.tools.ant.BuildListener#buildStarted(org.apache.tools.ant.BuildEvent)
*/
public void buildStarted(BuildEvent event) {
super.buildStarted(event);
marshalMessage(-1, DebugMessageIds.BUILD_STARTED);
String requestPortProperty= event.getProject().getProperty("eclipse.connect.request_port"); //$NON-NLS-1$
if (requestPortProperty != null) {
fRequestPort= Integer.parseInt(requestPortProperty);
try {
fServerSocket= new ServerSocket(fRequestPort);
} catch (IOException ioe) {
//throw new buildexection();
shutDown();
}
requestConnect();
} else {
shutDown();
}
fShouldSuspend= true;
waitIfSuspended();
}
/* (non-Javadoc)
* @see org.apache.tools.ant.BuildListener#taskStarted(org.apache.tools.ant.BuildEvent)
*/
public void taskStarted(BuildEvent event) {
super.taskStarted(event);
fCurrentTask= event.getTask();
fTasks.push(fCurrentTask);
waitIfSuspended();
}
/* (non-Javadoc)
* @see org.apache.tools.ant.BuildListener#taskFinished(org.apache.tools.ant.BuildEvent)
*/
public void taskFinished(BuildEvent event) {
super.taskFinished(event);
fLastTaskFinished= (Task)fTasks.pop();
fCurrentTask= null;
waitIfSuspended();
}
private synchronized void waitIfSuspended() {
if (fCurrentTask != null) {
String detail= null;
boolean shouldSuspend= true;
RemoteAntBreakpoint breakpoint= breakpointAtLineNumber(fCurrentTask.getLocation());
if (breakpoint != null) {
detail= breakpoint.toMarshallString();
} else if (fStepIntoSuspend) {
detail= DebugMessageIds.STEP;
fStepIntoSuspend= false;
} else if (fStepOverSuspend) {
if (fLastTaskFinished == fStepOverTask) {
detail= DebugMessageIds.STEP;
fStepOverSuspend= false;
fStepOverTask= null;
} else {
shouldSuspend= false;
}
} else if (fClientSuspend) {
detail= DebugMessageIds.CLIENT_REQUEST;
fClientSuspend= false;
} else {
shouldSuspend= false;
}
if (shouldSuspend) {
StringBuffer message= new StringBuffer(DebugMessageIds.SUSPENDED);
message.append(detail);
sendRequestResponse(message.toString());
try {
wait();
} catch (InterruptedException e) {
}
}
} else if (fShouldSuspend) {
try {
fShouldSuspend= false;
wait();
} catch (InterruptedException e) {
}
}
}
private RemoteAntBreakpoint breakpointAtLineNumber(Location location) {
if (fBreakpoints == null) {
return null;
}
for (int i = 0; i < fBreakpoints.size(); i++) {
RemoteAntBreakpoint breakpoint = (RemoteAntBreakpoint) fBreakpoints.get(i);
if (breakpoint.isAt(location)) {
return breakpoint;
}
}
return null;
}
private void sendRequestResponse(String message) {
if (fRequestWriter == null) {
return;
}
fRequestWriter.println(message);
}
protected void marshallStack() {
StringBuffer stackRepresentation= new StringBuffer();
stackRepresentation.append(DebugMessageIds.STACK);
stackRepresentation.append(DebugMessageIds.MESSAGE_DELIMITER);
for (int i = fTasks.size() - 1; i >= 0 ; i--) {
Task task = (Task) fTasks.get(i);
stackRepresentation.append(task.getOwningTarget().getName());
stackRepresentation.append(DebugMessageIds.MESSAGE_DELIMITER);
stackRepresentation.append(task.getTaskName());
stackRepresentation.append(DebugMessageIds.MESSAGE_DELIMITER);
Location location= task.getLocation();
stackRepresentation.append(location.getFileName());
stackRepresentation.append(DebugMessageIds.MESSAGE_DELIMITER);
stackRepresentation.append(location.getLineNumber());
stackRepresentation.append(DebugMessageIds.MESSAGE_DELIMITER);
}
sendRequestResponse(stackRepresentation.toString());
}
protected void marshallProperties() {
StringBuffer propertiesRepresentation= new StringBuffer();
propertiesRepresentation.append(DebugMessageIds.PROPERTIES);
propertiesRepresentation.append(DebugMessageIds.MESSAGE_DELIMITER);
Map currentProperties= null;
if (!fTasks.isEmpty()) {
currentProperties= ((Task)fTasks.peek()).getProject().getProperties();
if (fProperties != null && currentProperties.size() == fProperties.size()) {
//no new properties
sendRequestResponse(propertiesRepresentation.toString());
return;
}
Iterator iter= currentProperties.keySet().iterator();
String propertyName;
String propertyValue;
while (iter.hasNext()) {
propertyName = (String) iter.next();
if (propertyName.equals("line.separator")) { //$NON-NLS-1$
continue;
}
if (fProperties == null || fProperties.get(propertyName) == null) { //new property
propertiesRepresentation.append(propertyName.length());
propertiesRepresentation.append(DebugMessageIds.MESSAGE_DELIMITER);
propertiesRepresentation.append(propertyName);
propertiesRepresentation.append(DebugMessageIds.MESSAGE_DELIMITER);
propertyValue= (String) currentProperties.get(propertyName);
propertiesRepresentation.append(propertyValue.length());
propertiesRepresentation.append(DebugMessageIds.MESSAGE_DELIMITER);
propertiesRepresentation.append(propertyValue);
propertiesRepresentation.append(DebugMessageIds.MESSAGE_DELIMITER);
}
}
}
propertiesRepresentation.deleteCharAt(propertiesRepresentation.length() - 1);
fProperties= currentProperties;
sendRequestResponse(propertiesRepresentation.toString());
}
protected void addBreakpoint(String breakpointRepresentation) {
if (fBreakpoints == null) {
fBreakpoints= new ArrayList();
}
fBreakpoints.add(new RemoteAntBreakpoint(breakpointRepresentation));
}
protected void removeBreakpoint(String breakpointRepresentation) {
if (fBreakpoints == null) {
return;
}
RemoteAntBreakpoint equivalentBreakpoint= new RemoteAntBreakpoint(breakpointRepresentation);
for (Iterator iter = fBreakpoints.iterator(); iter.hasNext(); ) {
RemoteAntBreakpoint breakpoint = (RemoteAntBreakpoint) iter.next();
if (breakpoint.equals(equivalentBreakpoint)) {
iter.remove();
return;
}
}
}
}