blob: d63a429a86d141027e25b9a2c1e7fd66a70406b3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ant.internal.launching.debug.model;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.ant.internal.launching.debug.IAntDebugConstants;
import org.eclipse.ant.internal.launching.debug.IAntDebugController;
import org.eclipse.core.externaltools.internal.IExternalToolConstants;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IBreakpointManager;
import org.eclipse.debug.core.IBreakpointManagerListener;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.ILineBreakpoint;
import org.eclipse.debug.core.model.IMemoryBlock;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.core.model.IThread;
/**
* Ant Debug Target
*/
public class AntDebugTarget extends AntDebugElement implements IDebugTarget, IDebugEventSetListener, IBreakpointManagerListener {
// associated system process (Ant Build)
private IProcess fProcess;
// containing launch object
private ILaunch fLaunch;
// Build file name
private String fName;
// suspend state
private boolean fSuspended = false;
// terminated state
private boolean fTerminated = false;
// threads
private AntThread fThread;
private IThread[] fThreads;
private IAntDebugController fController;
private List<IBreakpoint> fRunToLineBreakpoints;
/**
* Constructs a new debug target in the given launch for the associated Ant build process.
*
* @param launch
* containing launch
* @param process
* Ant build process
* @param controller
* the controller to communicate to the Ant build
*/
public AntDebugTarget(ILaunch launch, IProcess process, IAntDebugController controller) {
super(null);
fLaunch = launch;
fProcess = process;
fController = controller;
fThread = new AntThread(this);
fThreads = new IThread[] { fThread };
DebugPlugin.getDefault().getBreakpointManager().addBreakpointManagerListener(this);
DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(this);
DebugPlugin.getDefault().addDebugEventListener(this);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#getProcess()
*/
@Override
public IProcess getProcess() {
return fProcess;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#getThreads()
*/
@Override
public IThread[] getThreads() {
return fThreads;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#hasThreads()
*/
@Override
public boolean hasThreads() throws DebugException {
return !fTerminated && fThreads.length > 0;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#getName()
*/
@Override
public String getName() throws DebugException {
if (fName == null) {
try {
fName = getLaunch().getLaunchConfiguration().getAttribute(IExternalToolConstants.ATTR_LOCATION, DebugModelMessages.AntDebugTarget_0);
fName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(fName);
}
catch (CoreException e) {
fName = DebugModelMessages.AntDebugTarget_0;
}
}
return fName;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint)
*/
@Override
public boolean supportsBreakpoint(IBreakpoint breakpoint) {
if (breakpoint.getModelIdentifier().equals(IAntDebugConstants.ID_ANT_DEBUG_MODEL)) {
// need to consider all breakpoints as no way to tell which set
// of build files will be executed (ant task)
return true;
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget()
*/
@Override
public IDebugTarget getDebugTarget() {
return this;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDebugElement#getLaunch()
*/
@Override
public ILaunch getLaunch() {
return fLaunch;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ITerminate#canTerminate()
*/
@Override
public boolean canTerminate() {
return !fTerminated;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ITerminate#isTerminated()
*/
@Override
public boolean isTerminated() {
return fTerminated;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ITerminate#terminate()
*/
@Override
public void terminate() throws DebugException {
terminated();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#canResume()
*/
@Override
public boolean canResume() {
return !fTerminated && fSuspended;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#canSuspend()
*/
@Override
public boolean canSuspend() {
return !fTerminated && !fSuspended;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#isSuspended()
*/
@Override
public boolean isSuspended() {
return fSuspended;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#resume()
*/
@Override
public void resume() throws DebugException {
fSuspended = false;
fController.resume();
if (fThread.isSuspended()) {
fThread.resumedByTarget();
}
fireResumeEvent(DebugEvent.CLIENT_REQUEST);
}
/**
* Notification the target has suspended for the given reason
*
* @param detail
* reason for the suspend
*/
public void suspended(int detail) {
fSuspended = true;
fThread.setStepping(false);
fThread.fireSuspendEvent(detail);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.ISuspendResume#suspend()
*/
@Override
public void suspend() throws DebugException {
fController.suspend();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
*/
@Override
public void breakpointAdded(IBreakpoint breakpoint) {
if (!fTerminated) {
fController.handleBreakpoint(breakpoint, true);
if (breakpoint instanceof AntLineBreakpoint) {
if (((AntLineBreakpoint) breakpoint).isRunToLine()) {
if (fRunToLineBreakpoints == null) {
fRunToLineBreakpoints = new ArrayList<>();
}
fRunToLineBreakpoints.add(breakpoint);
}
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint,
* org.eclipse.core.resources.IMarkerDelta)
*/
@Override
public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
if (!fTerminated) {
fController.handleBreakpoint(breakpoint, false);
if (fRunToLineBreakpoints != null) {
if (fRunToLineBreakpoints.remove(breakpoint) && fRunToLineBreakpoints.isEmpty()) {
fRunToLineBreakpoints = null;
}
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint,
* org.eclipse.core.resources.IMarkerDelta)
*/
@Override
public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
if (supportsBreakpoint(breakpoint)) {
try {
if (breakpoint.isEnabled() && DebugPlugin.getDefault().getBreakpointManager().isEnabled()) {
breakpointAdded(breakpoint);
} else {
breakpointRemoved(breakpoint, null);
}
}
catch (CoreException e) {
// do nothing
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
*/
@Override
public boolean canDisconnect() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDisconnect#disconnect()
*/
@Override
public void disconnect() throws DebugException {
// do nothing
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IDisconnect#isDisconnected()
*/
@Override
public boolean isDisconnected() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval()
*/
@Override
public boolean supportsStorageRetrieval() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long)
*/
@Override
public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException {
return null;
}
/**
* Notification we have connected to the Ant build logger and it has started. Resume the build.
*/
public void buildStarted() {
fireCreationEvent();
installDeferredBreakpoints();
try {
resume();
}
catch (DebugException e) {
// do nothing
}
}
/**
* Install breakpoints that are already registered with the breakpoint manager if the breakpoint manager is enabled and the breakpoint is enabled.
*/
private void installDeferredBreakpoints() {
IBreakpointManager manager = DebugPlugin.getDefault().getBreakpointManager();
if (!manager.isEnabled()) {
return;
}
IBreakpoint[] breakpoints = manager.getBreakpoints(IAntDebugConstants.ID_ANT_DEBUG_MODEL);
for (int i = 0; i < breakpoints.length; i++) {
IBreakpoint breakpoint = breakpoints[i];
try {
if (breakpoint.isEnabled()) {
breakpointAdded(breakpoints[i]);
}
}
catch (CoreException e) {
// do nothing
}
}
}
/**
* Called when this debug target terminates.
*/
public synchronized void terminated() {
if (!fTerminated) {
fThreads = new IThread[0];
fTerminated = true;
fSuspended = false;
fController.terminate();
if (DebugPlugin.getDefault() != null) {
DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(this);
DebugPlugin.getDefault().removeDebugEventListener(this);
DebugPlugin.getDefault().getBreakpointManager().removeBreakpointManagerListener(this);
}
if (!getProcess().isTerminated()) {
try {
fProcess.terminate();
}
catch (DebugException e) {
// do nothing
}
}
if (DebugPlugin.getDefault() != null) {
fireTerminateEvent();
}
}
}
/**
* Single step the Ant build.
*/
public void stepOver() {
fSuspended = false;
fController.stepOver();
fireResumeEvent(DebugEvent.CLIENT_REQUEST);
}
/**
* Step-into the Ant build.
*/
public void stepInto() {
fSuspended = false;
fController.stepInto();
fireResumeEvent(DebugEvent.CLIENT_REQUEST);
}
/**
* Notification a breakpoint was encountered. Determine which breakpoint was hit and fire a suspend event.
*
* @param event
* debug event
*/
public void breakpointHit(String event) {
// determine which breakpoint was hit, and set the thread's breakpoint
String[] datum = event.split(DebugMessageIds.MESSAGE_DELIMITER);
String fileName = datum[1];
int lineNumber = Integer.parseInt(datum[2]);
IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(IAntDebugConstants.ID_ANT_DEBUG_MODEL);
boolean found = false;
for (int i = 0; i < breakpoints.length; i++) {
ILineBreakpoint lineBreakpoint = (ILineBreakpoint) breakpoints[i];
if (setThreadBreakpoint(lineBreakpoint, lineNumber, fileName)) {
found = true;
break;
}
}
if (!found && fRunToLineBreakpoints != null) {
Iterator<IBreakpoint> iter = fRunToLineBreakpoints.iterator();
while (iter.hasNext()) {
ILineBreakpoint lineBreakpoint = (ILineBreakpoint) iter.next();
if (setThreadBreakpoint(lineBreakpoint, lineNumber, fileName)) {
break;
}
}
}
suspended(DebugEvent.BREAKPOINT);
}
private boolean setThreadBreakpoint(ILineBreakpoint lineBreakpoint, int lineNumber, String fileName) {
try {
if (lineBreakpoint.getLineNumber() == lineNumber && fileName.equals(lineBreakpoint.getMarker().getResource().getLocation().toOSString())) {
fThread.setBreakpoints(new IBreakpoint[] { lineBreakpoint });
return true;
}
}
catch (CoreException e) {
// do nothing
}
return false;
}
public void breakpointHit(IBreakpoint breakpoint) {
fThread.setBreakpoints(new IBreakpoint[] { breakpoint });
suspended(DebugEvent.BREAKPOINT);
}
public void getStackFrames() {
if (isSuspended()) {
fController.getStackFrames();
}
}
public void getProperties() {
if (!fTerminated) {
fController.getProperties();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse.debug.core.DebugEvent[])
*/
@Override
public void handleDebugEvents(DebugEvent[] events) {
for (int i = 0; i < events.length; i++) {
DebugEvent event = events[i];
if (event.getKind() == DebugEvent.TERMINATE && event.getSource().equals(fProcess)) {
terminated();
}
}
}
/**
* When the breakpoint manager disables, remove all registered breakpoints requests from the VM. When it enables, reinstall them.
*
* @see org.eclipse.debug.core.IBreakpointManagerListener#breakpointManagerEnablementChanged(boolean)
*/
@Override
public void breakpointManagerEnablementChanged(boolean enabled) {
IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(IAntDebugConstants.ID_ANT_DEBUG_MODEL);
for (int i = 0; i < breakpoints.length; i++) {
IBreakpoint breakpoint = breakpoints[i];
if (enabled) {
breakpointAdded(breakpoint);
} else {
breakpointRemoved(breakpoint, null);
}
}
}
public IAntDebugController getAntDebugController() {
return fController;
}
}