blob: 131ff8d72bbf615b6a9f93ade2fe85a293a48277 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ant.internal.launching.debug.model;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import org.eclipse.ant.internal.launching.AntLaunching;
import org.eclipse.ant.internal.launching.debug.IAntDebugController;
import org.eclipse.ant.internal.launching.launchConfigurations.RemoteAntBuildListener;
import org.eclipse.core.runtime.CoreException;
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.model.IBreakpoint;
import org.eclipse.debug.core.model.ILineBreakpoint;
import org.eclipse.debug.core.model.IProcess;
public class RemoteAntDebugBuildListener extends RemoteAntBuildListener implements IAntDebugController {
// sockets to communicate with the remote Ant debug build logger
private Socket fRequestSocket;
private PrintWriter fRequestWriter;
private BufferedReader fResponseReader;
private int fRequestPort= -1;
private Thread fReaderThread;
private AntDebugTarget fTarget;
/**
* Reader thread that processes request responses from the remote Ant debug build logger
*/
private class ReaderThread extends Thread {
public ReaderThread() {
super("Ant Request Response Reader Thread"); //$NON-NLS-1$
setDaemon(true);
}
public void run(){
try {
String message= null;
while (fResponseReader != null) {
synchronized (RemoteAntDebugBuildListener.this) {
if (fResponseReader != null && (message= fResponseReader.readLine()) != null) {
receiveMessage(message);
}
}
}
} catch (IOException ie) { //the other end has shutdown
RemoteAntDebugBuildListener.this.shutDown();
} catch (Exception e) {
AntLaunching.log("Internal error processing remote response", e); //$NON-NLS-1$
RemoteAntDebugBuildListener.this.shutDown();
}
}
}
/**
* Constructor
*
* @param launch the backing launch to listen to
* @param encoding the encoding to use for communications
*/
public RemoteAntDebugBuildListener(ILaunch launch, String encoding) {
super(launch, encoding);
//fDebug= true;
}
protected void receiveMessage(String message) {
if (message.startsWith(DebugMessageIds.BUILD_STARTED)) {
buildStarted();
} else if (message.startsWith(DebugMessageIds.SUSPENDED)){
handleSuspendMessage(message);
} else if (message.startsWith(DebugMessageIds.TERMINATED)){
try {
fTarget.terminate();
} catch (DebugException e) {}
} else if (message.startsWith(DebugMessageIds.STACK)){
AntThread thread= (AntThread) fTarget.getThreads()[0];
thread.buildStack(message);
} else if (message.startsWith(DebugMessageIds.PROPERTIES)){
AntThread thread= (AntThread) fTarget.getThreads()[0];
thread.newProperties(message);
} else {
super.receiveMessage(message);
}
}
private void handleSuspendMessage(String message) {
if (message.endsWith(DebugMessageIds.CLIENT_REQUEST)) {
fTarget.suspended(DebugEvent.CLIENT_REQUEST);
} else if (message.endsWith(DebugMessageIds.STEP)) {
fTarget.suspended(DebugEvent.STEP_END);
} else if (message.indexOf(DebugMessageIds.BREAKPOINT) >= 0) {
fTarget.breakpointHit(message);
}
}
private void buildStarted() {
IProcess process= getProcess();
while(process == null) {
try {
synchronized (this) {
wait(400);
}
process= getProcess();
} catch (InterruptedException ie) {
}
}
fTarget= new AntDebugTarget(fLaunch, process, this);
fLaunch.addDebugTarget(fTarget);
if (!connectRequest()) {
RemoteAntDebugBuildListener.this.shutDown();
return;
}
fTarget.buildStarted();
}
private boolean connectRequest() {
Exception exception= null;
for (int i= 1; i < 20; i++) {
try {
fRequestSocket = new Socket("localhost", fRequestPort); //$NON-NLS-1$
fRequestWriter = new PrintWriter(fRequestSocket.getOutputStream(), true);
fResponseReader = new BufferedReader(new InputStreamReader(fRequestSocket.getInputStream(), getEncoding()));
fReaderThread= new ReaderThread();
fReaderThread.start();
return true;
} catch (UnknownHostException e) {
exception= e;
break;
} catch (IOException e) {
exception= e;
}
try {
Thread.sleep(500);
} catch(InterruptedException e) {
}
}
AntLaunching.log("Internal error attempting to connect to debug target", exception); //$NON-NLS-1$
return false;
}
/**
* Start listening to an Ant build. Start a server connection that
* the RemoteAntDebugBuildLogger can connect to.
*
* @param eventPort The port number to create the server connection on
* @param requestPort The port number to use for sending requests to the remote logger
*/
public synchronized void startListening(int eventPort, int requestPort) {
super.startListening(eventPort);
fRequestPort= requestPort;
}
/**
* Sends a request to the Ant build
*
* @param request debug command
*/
protected void sendRequest(String request) {
if (fRequestWriter == null) {
return;
}
synchronized (fRequestWriter) {
fRequestWriter.println(request);
}
}
protected synchronized void shutDown() {
if (fTarget != null) {
try {
fTarget.terminate();
fTarget= null;
} catch (DebugException e) {}
}
fLaunch= null;
if (DebugPlugin.getDefault() != null) {
DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this);
}
try {
if (fReaderThread != null) {
// interrupt reader thread so that we don't block on close
// on a lock held by the BufferedReader
// see bug: 38955
fReaderThread.interrupt();
}
if (fResponseReader != null) {
fResponseReader.close();
fResponseReader= null;
}
} catch(IOException e) {
}
if (fRequestWriter != null) {
fRequestWriter.close();
fRequestWriter= null;
}
try{
if(fRequestSocket != null) {
fRequestSocket.close();
fRequestSocket= null;
}
} catch(IOException e) {
}
super.shutDown();
}
/* (non-Javadoc)
* @see org.eclipse.ant.internal.ui.debug.IAntDebugController#resume()
*/
public void resume() {
sendRequest(DebugMessageIds.RESUME);
}
/* (non-Javadoc)
* @see org.eclipse.ant.internal.launching.debug.IAntDebugController#terminate()
*/
public void terminate() {
}
/* (non-Javadoc)
* @see org.eclipse.ant.internal.ui.debug.IAntDebugController#suspend()
*/
public void suspend() {
sendRequest(DebugMessageIds.SUSPEND);
}
/* (non-Javadoc)
* @see org.eclipse.ant.internal.ui.debug.IAntDebugController#stepInto()
*/
public void stepInto() {
sendRequest(DebugMessageIds.STEP_INTO);
}
/* (non-Javadoc)
* @see org.eclipse.ant.internal.ui.debug.IAntDebugController#stepOver()
*/
public void stepOver() {
sendRequest(DebugMessageIds.STEP_OVER);
}
/* (non-Javadoc)
* @see org.eclipse.ant.internal.ui.debug.IAntDebugController#handleBreakpoint(IBreakpoint, boolean)
*/
public void handleBreakpoint(IBreakpoint breakpoint, boolean add) {
if (fTarget == null || !fTarget.supportsBreakpoint(breakpoint)) {
return;
}
StringBuffer message= new StringBuffer();
if (add) {
try {
if (!breakpoint.isEnabled()) {
return;
}
} catch (CoreException e) {
AntLaunching.log(e);
return;
}
message.append(DebugMessageIds.ADD_BREAKPOINT);
} else {
message.append(DebugMessageIds.REMOVE_BREAKPOINT);
}
message.append(DebugMessageIds.MESSAGE_DELIMITER);
message.append(breakpoint.getMarker().getResource().getLocation().toOSString());
message.append(DebugMessageIds.MESSAGE_DELIMITER);
try {
message.append(((ILineBreakpoint)breakpoint).getLineNumber());
sendRequest(message.toString());
} catch (CoreException ce) {
AntLaunching.log(ce);
}
}
/* (non-Javadoc)
* @see org.eclipse.ant.internal.ui.debug.IAntDebugController#getProperties()
*/
public void getProperties() {
sendRequest(DebugMessageIds.PROPERTIES);
}
/* (non-Javadoc)
* @see org.eclipse.ant.internal.ui.debug.IAntDebugController#getStackFrames()
*/
public void getStackFrames() {
sendRequest(DebugMessageIds.STACK);
}
/* (non-Javadoc)
* @see org.eclipse.ant.internal.ui.debug.IAntDebugController#unescapeString(java.lang.StringBuffer)
*/
public StringBuffer unescapeString(StringBuffer property) {
if (property.indexOf("\\r") == -1 && property.indexOf("\\n") == -1) { //$NON-NLS-1$ //$NON-NLS-2$
return property;
}
for (int i= 0; i < property.length(); i++) {
if ('\\' == property.charAt(i)) {
String newString= ""; //$NON-NLS-1$
if ('r' == property.charAt(i + 1)) {
if (i-1 > - 1 && '\\' == property.charAt(i-1)) {
newString= "r"; //$NON-NLS-1$
} else {
newString+= '\r';
}
} else if ('n' == property.charAt(i + 1)) {
if (i-1 > - 1 && '\\' == property.charAt(i-1)) {
newString= "n"; //$NON-NLS-1$
} else {
newString+= '\n';
}
}
if (newString.length() > 0) {
property.replace(i, i + 2, newString);
}
}
}
return property;
}
}