blob: 3587565bc040fbe681a90d034dfa1688e62cb2bb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2007 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.debug.internal.core;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IBreakpointListener;
import org.eclipse.debug.core.IBreakpointManager;
import org.eclipse.debug.core.IBreakpointManagerListener;
import org.eclipse.debug.core.IBreakpointsListener;
import org.eclipse.debug.core.model.IBreakpoint;
import com.ibm.icu.text.MessageFormat;
/**
* The breakpoint manager manages all registered breakpoints
* for the debug plug-in. It is instantiated by the debug plug-in at startup.
*
* @see IBreakpointManager
*/
public class BreakpointManager implements IBreakpointManager, IResourceChangeListener {
/**
* Constants for breakpoint add/remove/change updates
*/
private final static int ADDED = 0;
private final static int REMOVED = 1;
private final static int CHANGED = 2;
/**
* A collection of breakpoints registered with this manager.
*/
private Vector fBreakpoints= null;
/**
* A collection of breakpoint markers that have received a POST_CHANGE notification
* that they have changed before a POST_BUILD notification of add. This allows us
* to tell if a marker has been created & changed since the breakpoint has been
* registered (see bug 138473).
*/
private Set fPostChangMarkersChanged = new HashSet();
/**
* A collection of breakpoint markers that have received a POST_BUILD notification
* of being added.
*/
private Set fPostBuildMarkersAdded = new HashSet();
/**
* Collection of breakpoints being added currently. Used to
* suppress change notification of "REGISTERED" attribute when
* being added.
*/
private List fSuppressChange = new ArrayList();
/**
* A table of breakpoint extension points, keyed by
* marker type
* key: a marker type
* value: the breakpoint extension which corresponds to that marker type
*/
private HashMap fBreakpointExtensions;
/**
* Collection of markers that associates markers to breakpoints
* key: a marker
* value: the breakpoint which contains that marker
*/
private HashMap fMarkersToBreakpoints;
/**
* Collection of breakpoint listeners.
*/
private ListenerList fBreakpointListeners= new ListenerList();
/**
* Collection of (plural) breakpoint listeners.
*/
private ListenerList fBreakpointsListeners= new ListenerList();
/**
* Singleton resource delta visitor which handles marker
* additions, changes, and removals.
*/
private static BreakpointManagerVisitor fgVisitor;
/**
* Whether or not this breakpoint manager is enabled.
*/
private boolean fEnabled= true;
/**
* Collection of breakpoint manager listeners which are
* notified when this manager's state changes.
*/
private ListenerList fBreakpointManagerListeners= new ListenerList();
/**
* Listens to POST_CHANGE notifications of breakpoint markers to detect when
* a breakpoint is added & changed before the POST_BUILD add notification is
* sent.
*/
class PostChangeListener implements IResourceChangeListener {
private PostChangeVisitor fVisitor = new PostChangeVisitor();
/* (non-Javadoc)
* @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
*/
public void resourceChanged(IResourceChangeEvent event) {
IResourceDelta delta= event.getDelta();
if (delta != null) {
try {
delta.accept(fVisitor);
} catch (CoreException ce) {
DebugPlugin.log(ce);
}
}
}
}
/**
* The listener
*/
private PostChangeListener fPostChangeListener = new PostChangeListener();
class PostChangeVisitor implements IResourceDeltaVisitor {
/* (non-Javadoc)
* @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
*/
public boolean visit(IResourceDelta delta) throws CoreException {
if (delta == null) {
return false;
}
IMarkerDelta[] markerDeltas= delta.getMarkerDeltas();
for (int i= 0; i < markerDeltas.length; i++) {
IMarkerDelta markerDelta= markerDeltas[i];
if (markerDelta.isSubtypeOf(IBreakpoint.BREAKPOINT_MARKER)) {
switch (markerDelta.getKind()) {
case IResourceDelta.ADDED :
break;
case IResourceDelta.REMOVED :
break;
case IResourceDelta.CHANGED :
IMarker marker = markerDelta.getMarker();
synchronized (fPostChangMarkersChanged) {
if (!fPostBuildMarkersAdded.contains(marker)) {
fPostChangMarkersChanged.add(marker);
}
}
break;
}
}
}
return true;
}
}
/**
* Constructs a new breakpoint manager.
*/
public BreakpointManager() {
fMarkersToBreakpoints= new HashMap(10);
fBreakpointExtensions= new HashMap(15);
}
/**
* Loads all the breakpoints on the given resource.
*
* @param resource the resource which contains the breakpoints
* @param notify whether to notify of the breakpoint additions
*/
private void loadBreakpoints(IResource resource, boolean notify) throws CoreException {
initBreakpointExtensions();
IMarker[] markers= getPersistedMarkers(resource);
List added = new ArrayList();
for (int i = 0; i < markers.length; i++) {
IMarker marker= markers[i];
try {
IBreakpoint breakpoint = createBreakpoint(marker);
synchronized (fPostChangMarkersChanged) {
fPostBuildMarkersAdded.add(marker);
}
if (breakpoint.isRegistered()) {
added.add(breakpoint);
}
} catch (DebugException e) {
DebugPlugin.log(e);
}
}
addBreakpoints((IBreakpoint[])added.toArray(new IBreakpoint[added.size()]), notify);
}
/**
* Returns the persisted markers associated with the given resource.
*
* Delete any invalid breakpoint markers. This is done at startup rather
* than shutdown, since the changes made at shutdown are not persisted as
* the workspace state has already been saved. See bug 7683.
*
* Since the <code>TRANSIENT</code> marker attribute/feature has been added,
* we no longer have to manually delete non-persisted markers - the platform
* does this for us (at shutdown, transient markers are not saved). However,
* the code is still present to delete non-persisted markers from old
* workspaces.
*/
protected IMarker[] getPersistedMarkers(IResource resource) throws CoreException {
IMarker[] markers= resource.findMarkers(IBreakpoint.BREAKPOINT_MARKER, true, IResource.DEPTH_INFINITE);
final List delete = new ArrayList();
List persisted= new ArrayList();
for (int i = 0; i < markers.length; i++) {
IMarker marker= markers[i];
// ensure the marker has a valid model identifier attribute
// and delete the breakpoint if not
String modelId = marker.getAttribute(IBreakpoint.ID, null);
if (modelId == null) {
// marker with old/invalid format - delete
delete.add(marker);
} else if (!marker.getAttribute(IBreakpoint.PERSISTED, true)) {
// the breakpoint is marked as not to be persisted,
// schedule for deletion
delete.add(marker);
} else {
persisted.add(marker);
}
}
// delete any markers that are not to be restored
if (!delete.isEmpty()) {
final IMarker[] delMarkers = (IMarker[])delete.toArray(new IMarker[delete.size()]);
IWorkspaceRunnable wr = new IWorkspaceRunnable() {
public void run(IProgressMonitor pm) throws CoreException {
for (int i = 0; i < delMarkers.length; i++) {
IMarker marker = delMarkers[i];
marker.delete();
}
}
};
new BreakpointManagerJob(wr).schedule();
}
return (IMarker[])persisted.toArray(new IMarker[persisted.size()]);
}
/**
* Removes this manager as a resource change listener
* and removes all breakpoint listeners.
*/
public void shutdown() {
getWorkspace().removeResourceChangeListener(this);
getWorkspace().removeResourceChangeListener(fPostChangeListener);
fBreakpointListeners = null;
fBreakpointsListeners = null;
fBreakpointManagerListeners = null;
}
/**
* Find the defined breakpoint extensions and cache them for use in recreating
* breakpoints from markers.
*/
private void initBreakpointExtensions() {
IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_BREAKPOINTS);
IConfigurationElement[] elements = ep.getConfigurationElements();
for (int i= 0; i < elements.length; i++) {
String markerType = elements[i].getAttribute(IConfigurationElementConstants.MARKER_TYPE);
String className = elements[i].getAttribute(IConfigurationElementConstants.CLASS);
if (markerType == null) {
DebugPlugin.log(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "Breakpoint extension " + elements[i].getDeclaringExtension().getUniqueIdentifier() + " missing required attribute: markerType", null)); //$NON-NLS-1$ //$NON-NLS-2$
} else if (className == null){
DebugPlugin.log(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "Breakpoint extension " + elements[i].getDeclaringExtension().getUniqueIdentifier() + " missing required attribute: class", null)); //$NON-NLS-1$ //$NON-NLS-2$
} else {
fBreakpointExtensions.put(markerType, elements[i]);
}
}
}
/**
* Convenience method to get the workspace
*/
private IWorkspace getWorkspace() {
return ResourcesPlugin.getWorkspace();
}
/**
* @see IBreakpointManager#getBreakpoint(IMarker)
*/
public IBreakpoint getBreakpoint(IMarker marker) {
// ensure that breakpoints are initialized
getBreakpoints0();
return (IBreakpoint)fMarkersToBreakpoints.get(marker);
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IBreakpointManager#getBreakpoints()
*/
public IBreakpoint[] getBreakpoints() {
IBreakpoint[] temp = new IBreakpoint[0];
Vector breakpoints = getBreakpoints0();
synchronized (breakpoints) {
temp = new IBreakpoint[breakpoints.size()];
breakpoints.copyInto(temp);
}
return temp;
}
/**
* The BreakpointManager waits to load the breakpoints
* of the workspace until a request is made to retrieve the
* breakpoints.
*/
private synchronized Vector getBreakpoints0() {
if (fBreakpoints == null) {
initializeBreakpoints();
}
return fBreakpoints;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IBreakpointManager#getBreakpoints(java.lang.String)
*/
public IBreakpoint[] getBreakpoints(String modelIdentifier) {
Vector allBreakpoints= getBreakpoints0();
synchronized (allBreakpoints) {
ArrayList temp = new ArrayList(allBreakpoints.size());
Iterator breakpoints= allBreakpoints.iterator();
while (breakpoints.hasNext()) {
IBreakpoint breakpoint= (IBreakpoint) breakpoints.next();
String id= breakpoint.getModelIdentifier();
if (id != null && id.equals(modelIdentifier)) {
temp.add(breakpoint);
}
}
return (IBreakpoint[]) temp.toArray(new IBreakpoint[temp.size()]);
}
}
/**
* Loads the list of breakpoints from the breakpoint markers in the
* workspace. Start listening to resource deltas.
*/
private void initializeBreakpoints() {
setBreakpoints(new Vector(10));
try {
loadBreakpoints(getWorkspace().getRoot(), false);
getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_BUILD);
getWorkspace().addResourceChangeListener(fPostChangeListener, IResourceChangeEvent.POST_CHANGE);
} catch (CoreException ce) {
DebugPlugin.log(ce);
setBreakpoints(new Vector(0));
}
}
/**
* @see IBreakpointManager#isRegistered(IBreakpoint)
*/
public boolean isRegistered(IBreakpoint breakpoint) {
return getBreakpoints0().contains(breakpoint);
}
/**
* @see IBreakpointManager#removeBreakpoint(IBreakpoint, boolean)
*/
public void removeBreakpoint(IBreakpoint breakpoint, boolean delete) throws CoreException {
removeBreakpoints(new IBreakpoint[]{breakpoint}, delete);
}
/**
* @see IBreakpointManager#removeBreakpoints(IBreakpoint[], boolean)
*/
public void removeBreakpoints(IBreakpoint[] breakpoints, final boolean delete) throws CoreException {
final List remove = new ArrayList(breakpoints.length);
for (int i = 0; i < breakpoints.length; i++) {
IBreakpoint breakpoint = breakpoints[i];
if (getBreakpoints0().contains(breakpoint)) {
remove.add(breakpoint);
}
}
if (!remove.isEmpty()) {
Iterator iter = remove.iterator();
while (iter.hasNext()) {
IBreakpoint breakpoint = (IBreakpoint)iter.next();
getBreakpoints0().remove(breakpoint);
fMarkersToBreakpoints.remove(breakpoint.getMarker());
}
fireUpdate(remove, null, REMOVED);
IWorkspaceRunnable r = new IWorkspaceRunnable() {
public void run(IProgressMonitor montitor) throws CoreException {
Iterator innerIter = remove.iterator();
while (innerIter.hasNext()) {
IBreakpoint breakpoint = (IBreakpoint)innerIter.next();
if (delete) {
breakpoint.delete();
} else {
// if the breakpoint is being removed from the manager
// because the project is closing, the breakpoint should
// remain as registered, otherwise, the breakpoint should
// be marked as unregistered
IMarker marker = breakpoint.getMarker();
if (marker.exists()) {
IProject project = breakpoint.getMarker().getResource().getProject();
if (project == null || project.isOpen()) {
breakpoint.setRegistered(false);
}
}
}
}
}
};
getWorkspace().run(r, null, 0, null);
}
}
/**
* Create a breakpoint for the given marker. The created breakpoint
* is of the type specified in the breakpoint extension associated
* with the given marker type.
*
* @param marker marker to create a breakpoint for
* @return a breakpoint on this marker
* @exception DebugException if breakpoint creation fails. Reasons for
* failure include:
* <ol>
* <li>The breakpoint manager cannot determine what kind of breakpoint
* to instantiate for the given marker type</li>
* <li>A lower level exception occurred while accessing the given marker</li>
* </ol>
*/
public IBreakpoint createBreakpoint(IMarker marker) throws DebugException {
IBreakpoint breakpoint= (IBreakpoint) fMarkersToBreakpoints.get(marker);
if (breakpoint != null) {
return breakpoint;
}
try {
IConfigurationElement config = (IConfigurationElement)fBreakpointExtensions.get(marker.getType());
if (config == null) {
throw new DebugException(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.CONFIGURATION_INVALID, MessageFormat.format(DebugCoreMessages.BreakpointManager_Missing_breakpoint_definition, new String[] {marker.getType()}), null));
}
Object object = config.createExecutableExtension(IConfigurationElementConstants.CLASS);
if (object instanceof IBreakpoint) {
breakpoint = (IBreakpoint)object;
breakpoint.setMarker(marker);
} else {
DebugPlugin.log(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "Breakpoint extension " + config.getDeclaringExtension().getUniqueIdentifier() + " missing required attribute: class", null)); //$NON-NLS-1$ //$NON-NLS-2$
}
return breakpoint;
} catch (CoreException e) {
throw new DebugException(e.getStatus());
}
}
/**
* @see IBreakpointManager#addBreakpoint(IBreakpoint)
*/
public void addBreakpoint(IBreakpoint breakpoint) throws CoreException {
addBreakpoints(new IBreakpoint[]{breakpoint});
}
/**
* @see IBreakpointManager#addBreakpoints(IBreakpoint[])
*/
public void addBreakpoints(IBreakpoint[] breakpoints) throws CoreException {
addBreakpoints(breakpoints, true);
}
/**
* Registers the given breakpoints and notifies listeners if specified.
*
* @param breakpoints the breakpoints to register
* @param notify whether to notify listeners of the add
* @param loading whether the given breakpoints are being automatically loaded
* from previously persisted markers
*/
private void addBreakpoints(IBreakpoint[] breakpoints, boolean notify) throws CoreException {
List added = new ArrayList(breakpoints.length);
final List update = new ArrayList();
for (int i = 0; i < breakpoints.length; i++) {
IBreakpoint breakpoint = breakpoints[i];
if (!getBreakpoints0().contains(breakpoint)) {
verifyBreakpoint(breakpoint);
if (breakpoint.isRegistered()) {
// If notify == false, the breakpoints are just being added at startup
added.add(breakpoint);
getBreakpoints0().add(breakpoint);
fMarkersToBreakpoints.put(breakpoint.getMarker(), breakpoint);
} else {
// need to update the 'registered' and/or 'group' attributes
update.add(breakpoint);
}
}
}
if (notify) {
fireUpdate(added, null, ADDED);
}
if (!update.isEmpty()) {
IWorkspaceRunnable r = new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
Iterator iter = update.iterator();
while (iter.hasNext()) {
IBreakpoint breakpoint = (IBreakpoint)iter.next();
getBreakpoints0().add(breakpoint);
breakpoint.setRegistered(true);
fMarkersToBreakpoints.put(breakpoint.getMarker(), breakpoint);
}
}
};
// Need to suppress change notification, since this is really
// an add notification
fSuppressChange.addAll(update);
getWorkspace().run(r, null, 0, null);
fSuppressChange.removeAll(update);
if (notify) {
fireUpdate(update, null, ADDED);
}
}
}
/**
* Returns whether change notification is to be suppressed for the given breakpoint.
* Used when adding breakpoints and changing the "REGISTERED" attribute.
*
* @param breakpoint
* @return boolean whether change notification is suppressed
*/
protected boolean isChangeSuppressed(IBreakpoint breakpoint) {
return fSuppressChange.contains(breakpoint);
}
/**
* @see IBreakpointManager#fireBreakpointChanged(IBreakpoint)
*/
public void fireBreakpointChanged(IBreakpoint breakpoint) {
if (getBreakpoints0().contains(breakpoint)) {
List changed = new ArrayList();
changed.add(breakpoint);
fireUpdate(changed, null, CHANGED);
}
}
/**
* Verifies that the breakpoint marker has the minimal required attributes,
* and throws a debug exception if not.
*/
private void verifyBreakpoint(IBreakpoint breakpoint) throws DebugException {
try {
String id= breakpoint.getModelIdentifier();
if (id == null) {
throw new DebugException(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
DebugException.CONFIGURATION_INVALID, DebugCoreMessages.BreakpointManager_Missing_model_identifier, null));
}
} catch (CoreException e) {
throw new DebugException(e.getStatus());
}
}
/**
* A resource has changed. Traverses the delta for breakpoint changes.
*
* @param event resource change event
*/
public void resourceChanged(IResourceChangeEvent event) {
IResourceDelta delta= event.getDelta();
if (delta != null) {
try {
if (fgVisitor == null) {
fgVisitor= new BreakpointManagerVisitor();
}
delta.accept(fgVisitor);
fgVisitor.update();
} catch (CoreException ce) {
DebugPlugin.log(ce);
}
}
}
/**
* Visitor for handling resource deltas
*/
class BreakpointManagerVisitor implements IResourceDeltaVisitor {
/**
* Moved markers
*/
private List fMoved = new ArrayList();
/**
* Removed breakpoints
*/
private List fRemoved = new ArrayList();
/**
* Changed breakpoints and associated marker deltas
*/
private List fChanged = new ArrayList();
private List fChangedDeltas = new ArrayList();
/**
* Resets the visitor for a delta traversal - empties
* collections of removed/changed breakpoints.
*/
protected void reset() {
fMoved.clear();
fRemoved.clear();
fChanged.clear();
fChangedDeltas.clear();
}
/**
* Performs updates on accumulated changes, and fires change notification after
* a traversal. Accumulated updates are reset.
*/
public void update() {
if (!fMoved.isEmpty()) {
// delete moved markers
IWorkspaceRunnable wRunnable= new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
IMarker[] markers = (IMarker[])fMoved.toArray(new IMarker[fMoved.size()]);
for (int i = 0; i < markers.length; i++) {
markers[i].delete();
}
}
};
try {
getWorkspace().run(wRunnable, null, 0, null);
} catch (CoreException e) {
}
}
if (!fRemoved.isEmpty()) {
try {
removeBreakpoints((IBreakpoint[])fRemoved.toArray(new IBreakpoint[fRemoved.size()]), false);
} catch (CoreException e) {
DebugPlugin.log(e);
}
}
if (!fChanged.isEmpty()) {
fireUpdate(fChanged, fChangedDeltas, CHANGED);
}
reset();
}
/**
* @see IResourceDeltaVisitor#visit(IResourceDelta)
*/
public boolean visit(IResourceDelta delta) {
if (delta == null) {
return false;
}
if (0 != (delta.getFlags() & IResourceDelta.OPEN) && 0 == (delta.getFlags() & IResourceDelta.MOVED_FROM)) {
handleProjectResourceOpenStateChange(delta.getResource());
return false;
}
IMarkerDelta[] markerDeltas= delta.getMarkerDeltas();
for (int i= 0; i < markerDeltas.length; i++) {
IMarkerDelta markerDelta= markerDeltas[i];
if (markerDelta.isSubtypeOf(IBreakpoint.BREAKPOINT_MARKER)) {
switch (markerDelta.getKind()) {
case IResourceDelta.ADDED :
handleAddBreakpoint(delta, markerDelta.getMarker(), markerDelta);
break;
case IResourceDelta.REMOVED :
handleRemoveBreakpoint(markerDelta.getMarker());
break;
case IResourceDelta.CHANGED :
handleChangeBreakpoint(markerDelta.getMarker(), markerDelta);
break;
}
}
}
return true;
}
/**
* Wrapper for handling adds
*/
protected void handleAddBreakpoint(IResourceDelta rDelta, IMarker marker, IMarkerDelta mDelta) {
if (0 != (rDelta.getFlags() & IResourceDelta.MOVED_FROM)) {
// This breakpoint has actually been moved - already removed
// from the Breakpoint manager during the remove callback.
// Schedule the marker associated with the new resource for deletion.
if (getBreakpoint(marker) == null) {
fMoved.add(marker);
}
} else {
// check if the an add & change have be combined into one add notification
synchronized (fPostChangMarkersChanged) {
if (fPostChangMarkersChanged.contains(marker)) {
handleChangeBreakpoint(marker, mDelta);
fPostChangMarkersChanged.remove(marker);
}
fPostBuildMarkersAdded.add(marker);
}
}
}
/**
* Wrapper for handling removes
*/
protected void handleRemoveBreakpoint(IMarker marker) {
synchronized (fPostChangMarkersChanged) {
fPostChangMarkersChanged.remove(marker);
fPostBuildMarkersAdded.remove(marker);
}
IBreakpoint breakpoint= getBreakpoint(marker);
if (breakpoint != null) {
fRemoved.add(breakpoint);
}
}
/**
* Wrapper for handling changes
*/
protected void handleChangeBreakpoint(IMarker marker, IMarkerDelta delta) {
IBreakpoint breakpoint= getBreakpoint(marker);
if (breakpoint != null && isRegistered(breakpoint) && !isChangeSuppressed(breakpoint)) {
fChanged.add(breakpoint);
fChangedDeltas.add(delta);
}
}
/**
* A project has been opened or closed. Updates the breakpoints for
* that project
*/
private void handleProjectResourceOpenStateChange(final IResource project) {
if (!project.isAccessible()) {
//closed
Enumeration breakpoints= ((Vector)getBreakpoints0().clone()).elements();
while (breakpoints.hasMoreElements()) {
IBreakpoint breakpoint= (IBreakpoint) breakpoints.nextElement();
IResource markerResource= breakpoint.getMarker().getResource();
if (project.getFullPath().isPrefixOf(markerResource.getFullPath())) {
fRemoved.add(breakpoint);
}
}
return;
}
try {
loadBreakpoints(project, true);
} catch (CoreException e) {
DebugPlugin.log(e);
}
}
}
/**
* @see IBreakpointManager#addBreakpointListener(IBreakpointListener)
*/
public void addBreakpointListener(IBreakpointListener listener) {
fBreakpointListeners.add(listener);
}
/**
* @see IBreakpointManager#removeBreakpointListener(IBreakpointListener)
*/
public void removeBreakpointListener(IBreakpointListener listener) {
fBreakpointListeners.remove(listener);
}
/**
* Notifies listeners of the adds/removes/changes
*
* @param breakpoints associated breakpoints
* @param deltas or <code>null</code>
* @param update type of change
*/
private void fireUpdate(List breakpoints, List deltas, int update) {
if (breakpoints.isEmpty()) {
return;
}
IBreakpoint[] bpArray = (IBreakpoint[])breakpoints.toArray(new IBreakpoint[breakpoints.size()]);
IMarkerDelta[] deltaArray = new IMarkerDelta[bpArray.length];
if (deltas != null) {
deltaArray = (IMarkerDelta[])deltas.toArray(deltaArray);
}
// single listeners
getBreakpointNotifier().notify(bpArray, deltaArray, update);
// plural listeners
getBreakpointsNotifier().notify(bpArray, deltaArray, update);
}
protected void setBreakpoints(Vector breakpoints) {
fBreakpoints = breakpoints;
}
/**
* @see IBreakpointManager#hasBreakpoints()
*/
public boolean hasBreakpoints() {
return !getBreakpoints0().isEmpty();
}
/**
* @see org.eclipse.debug.core.IBreakpointManager#addBreakpointListener(org.eclipse.debug.core.IBreakpointsListener)
*/
public void addBreakpointListener(IBreakpointsListener listener) {
fBreakpointsListeners.add(listener);
}
/**
* @see org.eclipse.debug.core.IBreakpointManager#removeBreakpointListener(org.eclipse.debug.core.IBreakpointsListener)
*/
public void removeBreakpointListener(IBreakpointsListener listener) {
fBreakpointsListeners.remove(listener);
}
private BreakpointNotifier getBreakpointNotifier() {
return new BreakpointNotifier();
}
/**
* Notifies breakpoint listener (single breakpoint) in a safe runnable to
* handle exceptions.
*/
class BreakpointNotifier implements ISafeRunnable {
private IBreakpointListener fListener;
private int fType;
private IMarkerDelta fDelta;
private IBreakpoint fBreakpoint;
/**
* @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
*/
public void handleException(Throwable exception) {
IStatus status = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "An exception occurred during breakpoint change notification.", exception); //$NON-NLS-1$
DebugPlugin.log(status);
}
/**
* @see org.eclipse.core.runtime.ISafeRunnable#run()
*/
public void run() throws Exception {
switch (fType) {
case ADDED:
fListener.breakpointAdded(fBreakpoint);
break;
case REMOVED:
fListener.breakpointRemoved(fBreakpoint, fDelta);
break;
case CHANGED:
fListener.breakpointChanged(fBreakpoint, fDelta);
break;
}
}
/**
* Notifies the listeners of the add/change/remove
*
* @param breakpoints the breakpoints that changed
* @param deltas the deltas associated with the change
* @param update the type of change
*/
public void notify(IBreakpoint[] breakpoints, IMarkerDelta[] deltas, int update) {
fType = update;
Object[] copiedListeners= fBreakpointListeners.getListeners();
for (int i= 0; i < copiedListeners.length; i++) {
fListener = (IBreakpointListener)copiedListeners[i];
for (int j = 0; j < breakpoints.length; j++) {
fBreakpoint = breakpoints[j];
fDelta = deltas[j];
SafeRunner.run(this);
}
}
fListener = null;
fDelta = null;
fBreakpoint = null;
}
}
private BreakpointsNotifier getBreakpointsNotifier() {
return new BreakpointsNotifier();
}
/**
* Notifies breakpoint listener (multiple breakpoints) in a safe runnable to
* handle exceptions.
*/
class BreakpointsNotifier implements ISafeRunnable {
private IBreakpointsListener fListener;
private int fType;
private IMarkerDelta[] fDeltas;
private IBreakpoint[] fNotifierBreakpoints;
/**
* @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
*/
public void handleException(Throwable exception) {
IStatus status = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "An exception occurred during breakpoint change notification.", exception); //$NON-NLS-1$
DebugPlugin.log(status);
}
/**
* @see org.eclipse.core.runtime.ISafeRunnable#run()
*/
public void run() throws Exception {
switch (fType) {
case ADDED:
fListener.breakpointsAdded(fNotifierBreakpoints);
break;
case REMOVED:
fListener.breakpointsRemoved(fNotifierBreakpoints, fDeltas);
break;
case CHANGED:
fListener.breakpointsChanged(fNotifierBreakpoints, fDeltas);
break;
}
}
/**
* Notifies the listeners of the adds/changes/removes
*
* @param breakpoints the breakpoints that changed
* @param deltas the deltas associated with the changed breakpoints
* @param update the type of change
*/
public void notify(IBreakpoint[] breakpoints, IMarkerDelta[] deltas, int update) {
fType = update;
fNotifierBreakpoints = breakpoints;
fDeltas = deltas;
Object[] copiedListeners = fBreakpointsListeners.getListeners();
for (int i= 0; i < copiedListeners.length; i++) {
fListener = (IBreakpointsListener)copiedListeners[i];
SafeRunner.run(this);
}
fDeltas = null;
fNotifierBreakpoints = null;
fListener = null;
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IBreakpointManager#isEnabled()
*/
public boolean isEnabled() {
return fEnabled;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IBreakpointManager#setEnabled(boolean)
*/
public void setEnabled(final boolean enabled) {
if (fEnabled != enabled) {
fEnabled= enabled;
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
IBreakpoint[] breakpoints = getBreakpoints();
for (int i = 0; i < breakpoints.length; i++) {
IBreakpoint breakpoint = breakpoints[i];
// Touch the marker (but don't actually change anything) so that the icon in
// the editor ruler will be updated (editors listen to marker changes).
breakpoint.getMarker().setAttribute(IBreakpoint.ENABLED, breakpoint.isEnabled());
}
}
};
try {
ResourcesPlugin.getWorkspace().run(runnable, null, IWorkspace.AVOID_UPDATE ,null);
} catch (CoreException e) {
DebugPlugin.log(e);
}
new BreakpointManagerNotifier().notify(enabled);
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IBreakpointManager#addBreakpointManagerListener(org.eclipse.debug.core.IBreakpointManagerListener)
*/
public void addBreakpointManagerListener(IBreakpointManagerListener listener) {
fBreakpointManagerListeners.add(listener);
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IBreakpointManager#removeBreakpointManagerListener(org.eclipse.debug.core.IBreakpointManagerListener)
*/
public void removeBreakpointManagerListener(IBreakpointManagerListener listener) {
fBreakpointManagerListeners.remove(listener);
}
/**
* Notifies breakpoint manager listeners in a safe runnable to
* handle exceptions.
*/
class BreakpointManagerNotifier implements ISafeRunnable {
private IBreakpointManagerListener fListener;
private boolean fManagerEnabled;
/**
* @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
*/
public void handleException(Throwable exception) {
IStatus status = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "An exception occurred during breakpoint change notification.", exception); //$NON-NLS-1$
DebugPlugin.log(status);
}
/**
* @see org.eclipse.core.runtime.ISafeRunnable#run()
*/
public void run() throws Exception {
fListener.breakpointManagerEnablementChanged(fManagerEnabled);
}
/**
* Notifies the listeners of the enabled state change
*
* @param enabled whether the manager is enabled
*/
public void notify(boolean enabled) {
fManagerEnabled= enabled;
Object[] copiedListeners = fBreakpointManagerListeners.getListeners();
for (int i= 0; i < copiedListeners.length; i++) {
fListener = (IBreakpointManagerListener)copiedListeners[i];
SafeRunner.run(this);
}
fListener = null;
}
}
class BreakpointManagerJob extends Job {
private final IWorkspaceRunnable fRunnable;
public BreakpointManagerJob (IWorkspaceRunnable wRunnable) {
super("breakpoint manager job"); //$NON-NLS-1$
fRunnable= wRunnable;
setSystem(true);
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
*/
protected IStatus run(IProgressMonitor monitor) {
try {
getWorkspace().run(fRunnable, null, 0, null);
} catch (CoreException ce) {
DebugPlugin.log(ce);
}
return new Status(IStatus.OK, DebugPlugin.getUniqueIdentifier(), IStatus.OK, "", null); //$NON-NLS-1$
}
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.IBreakpointManager#getTypeName(org.eclipse.debug.core.model.IBreakpoint)
*/
public String getTypeName(IBreakpoint breakpoint) {
String typeName= null;
IMarker marker = breakpoint.getMarker();
if (marker != null) {
try {
IConfigurationElement element = (IConfigurationElement) fBreakpointExtensions.get(marker.getType());
if (element != null) {
typeName= element.getAttribute(IConfigurationElementConstants.NAME);
}
}
catch (CoreException e) {}
}
return typeName;
}
}