KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > debug > internal > core > BreakpointManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.debug.internal.core;
12
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Enumeration JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Set JavaDoc;
21 import java.util.Vector JavaDoc;
22
23 import org.eclipse.core.resources.IMarker;
24 import org.eclipse.core.resources.IMarkerDelta;
25 import org.eclipse.core.resources.IProject;
26 import org.eclipse.core.resources.IResource;
27 import org.eclipse.core.resources.IResourceChangeEvent;
28 import org.eclipse.core.resources.IResourceChangeListener;
29 import org.eclipse.core.resources.IResourceDelta;
30 import org.eclipse.core.resources.IResourceDeltaVisitor;
31 import org.eclipse.core.resources.IWorkspace;
32 import org.eclipse.core.resources.IWorkspaceRunnable;
33 import org.eclipse.core.resources.ResourcesPlugin;
34 import org.eclipse.core.runtime.CoreException;
35 import org.eclipse.core.runtime.IConfigurationElement;
36 import org.eclipse.core.runtime.IExtensionPoint;
37 import org.eclipse.core.runtime.IProgressMonitor;
38 import org.eclipse.core.runtime.ISafeRunnable;
39 import org.eclipse.core.runtime.IStatus;
40 import org.eclipse.core.runtime.ListenerList;
41 import org.eclipse.core.runtime.Platform;
42 import org.eclipse.core.runtime.SafeRunner;
43 import org.eclipse.core.runtime.Status;
44 import org.eclipse.core.runtime.jobs.Job;
45 import org.eclipse.debug.core.DebugException;
46 import org.eclipse.debug.core.DebugPlugin;
47 import org.eclipse.debug.core.IBreakpointListener;
48 import org.eclipse.debug.core.IBreakpointManager;
49 import org.eclipse.debug.core.IBreakpointManagerListener;
50 import org.eclipse.debug.core.IBreakpointsListener;
51 import org.eclipse.debug.core.model.IBreakpoint;
52
53 import com.ibm.icu.text.MessageFormat;
54
55 /**
56  * The breakpoint manager manages all registered breakpoints
57  * for the debug plug-in. It is instantiated by the debug plug-in at startup.
58  *
59  * @see IBreakpointManager
60  */

61 public class BreakpointManager implements IBreakpointManager, IResourceChangeListener {
62     
63     /**
64      * Constants for breakpoint add/remove/change updates
65      */

66     private final static int ADDED = 0;
67     private final static int REMOVED = 1;
68     private final static int CHANGED = 2;
69     
70     /**
71      * String constants corresponding to XML extension keys
72      */

73     private final static String JavaDoc CLASS = "class"; //$NON-NLS-1$
74

75     /**
76      * Attribute name for the <code>"markerType"</code> attribute of
77      * a breakpoint extension.
78      */

79     private static final String JavaDoc MARKER_TYPE= "markerType"; //$NON-NLS-1$
80

81     /**
82      * Attribute name for the <code>"name"</code> attribute of a
83      * breakpoint extension.
84      */

85     private static final String JavaDoc TYPE_NAME= "name"; //$NON-NLS-1$
86

87     /**
88      * A collection of breakpoints registered with this manager.
89      */

90     private Vector JavaDoc fBreakpoints= null;
91     
92     /**
93      * A collection of breakpoint markers that have received a POST_CHANGE notification
94      * that they have changed before a POST_BUILD notification of add. This allows us
95      * to tell if a marker has been created & changed since the breakpoint has been
96      * registered (see bug 138473).
97      */

98     private Set JavaDoc fPostChangMarkersChanged = new HashSet JavaDoc();
99     
100     /**
101      * A collection of breakpoint markers that have received a POST_BUILD notification
102      * of being added.
103      */

104     private Set JavaDoc fPostBuildMarkersAdded = new HashSet JavaDoc();
105     
106     /**
107      * Collection of breakpoints being added currently. Used to
108      * suppress change notification of "REGISTERED" attribute when
109      * being added.
110      */

111     private List JavaDoc fSuppressChange = new ArrayList JavaDoc();
112     
113     /**
114      * A table of breakpoint extension points, keyed by
115      * marker type
116      * key: a marker type
117      * value: the breakpoint extension which corresponds to that marker type
118      */

119     private HashMap JavaDoc fBreakpointExtensions;
120     
121     /**
122      * Collection of markers that associates markers to breakpoints
123      * key: a marker
124      * value: the breakpoint which contains that marker
125      */

126     private HashMap JavaDoc fMarkersToBreakpoints;
127
128     /**
129      * Collection of breakpoint listeners.
130      */

131     private ListenerList fBreakpointListeners= new ListenerList();
132         
133     /**
134      * Collection of (plural) breakpoint listeners.
135      */

136     private ListenerList fBreakpointsListeners= new ListenerList();
137     
138     /**
139      * Singleton resource delta visitor which handles marker
140      * additions, changes, and removals.
141      */

142     private static BreakpointManagerVisitor fgVisitor;
143     
144     /**
145      * Whether or not this breakpoint manager is enabled.
146      */

147     private boolean fEnabled= true;
148     
149     /**
150      * Collection of breakpoint manager listeners which are
151      * notified when this manager's state changes.
152      */

153     private ListenerList fBreakpointManagerListeners= new ListenerList();
154
155     /**
156      * Listens to POST_CHANGE notifications of breakpoint markers to detect when
157      * a breakpoint is added & changed before the POST_BUILD add notification is
158      * sent.
159      */

160     class PostChangeListener implements IResourceChangeListener {
161         
162         private PostChangeVisitor fVisitor = new PostChangeVisitor();
163
164         /* (non-Javadoc)
165          * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent)
166          */

167         public void resourceChanged(IResourceChangeEvent event) {
168             IResourceDelta delta= event.getDelta();
169             if (delta != null) {
170                 try {
171                     delta.accept(fVisitor);
172                 } catch (CoreException ce) {
173                     DebugPlugin.log(ce);
174                 }
175             }
176         }
177         
178     }
179     
180     /**
181      * The listener
182      */

183     private PostChangeListener fPostChangeListener = new PostChangeListener();
184     
185     class PostChangeVisitor implements IResourceDeltaVisitor {
186
187         /* (non-Javadoc)
188          * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
189          */

190         public boolean visit(IResourceDelta delta) throws CoreException {
191             if (delta == null) {
192                 return false;
193             }
194             IMarkerDelta[] markerDeltas= delta.getMarkerDeltas();
195             for (int i= 0; i < markerDeltas.length; i++) {
196                 IMarkerDelta markerDelta= markerDeltas[i];
197                 if (markerDelta.isSubtypeOf(IBreakpoint.BREAKPOINT_MARKER)) {
198                     switch (markerDelta.getKind()) {
199                         case IResourceDelta.ADDED :
200                             break;
201                         case IResourceDelta.REMOVED :
202                             break;
203                         case IResourceDelta.CHANGED :
204                             IMarker marker = markerDelta.getMarker();
205                             synchronized (fPostChangMarkersChanged) {
206                                 if (!fPostBuildMarkersAdded.contains(marker)) {
207                                     fPostChangMarkersChanged.add(marker);
208                                 }
209                             }
210                             break;
211                     }
212                 }
213             }
214             return true;
215         }
216         
217     }
218     
219     /**
220      * Constructs a new breakpoint manager.
221      */

222     public BreakpointManager() {
223         fMarkersToBreakpoints= new HashMap JavaDoc(10);
224         fBreakpointExtensions= new HashMap JavaDoc(15);
225     }
226     
227     /**
228      * Loads all the breakpoints on the given resource.
229      *
230      * @param resource the resource which contains the breakpoints
231      * @param notify whether to notify of the breakpoint additions
232      */

233     private void loadBreakpoints(IResource resource, boolean notify) throws CoreException {
234         initBreakpointExtensions();
235         IMarker[] markers= getPersistedMarkers(resource);
236         List JavaDoc added = new ArrayList JavaDoc();
237         for (int i = 0; i < markers.length; i++) {
238             IMarker marker= markers[i];
239             try {
240                 IBreakpoint breakpoint = createBreakpoint(marker);
241                 synchronized (fPostChangMarkersChanged) {
242                     fPostBuildMarkersAdded.add(marker);
243                 }
244                 if (breakpoint.isRegistered()) {
245                     added.add(breakpoint);
246                 }
247             } catch (DebugException e) {
248                 DebugPlugin.log(e);
249             }
250         }
251         addBreakpoints((IBreakpoint[])added.toArray(new IBreakpoint[added.size()]), notify);
252     }
253     
254     /**
255      * Returns the persisted markers associated with the given resource.
256      *
257      * Delete any invalid breakpoint markers. This is done at startup rather
258      * than shutdown, since the changes made at shutdown are not persisted as
259      * the workspace state has already been saved. See bug 7683.
260      *
261      * Since the <code>TRANSIENT</code> marker attribute/feature has been added,
262      * we no longer have to manually delete non-persisted markers - the platform
263      * does this for us (at shutdown, transient markers are not saved). However,
264      * the code is still present to delete non-persisted markers from old
265      * workspaces.
266      */

267     protected IMarker[] getPersistedMarkers(IResource resource) throws CoreException {
268         IMarker[] markers= resource.findMarkers(IBreakpoint.BREAKPOINT_MARKER, true, IResource.DEPTH_INFINITE);
269         final List JavaDoc delete = new ArrayList JavaDoc();
270         List JavaDoc persisted= new ArrayList JavaDoc();
271         for (int i = 0; i < markers.length; i++) {
272             IMarker marker= markers[i];
273             // ensure the marker has a valid model identifier attribute
274
// and delete the breakpoint if not
275
String JavaDoc modelId = marker.getAttribute(IBreakpoint.ID, null);
276             if (modelId == null) {
277                 // marker with old/invalid format - delete
278
delete.add(marker);
279             } else if (!marker.getAttribute(IBreakpoint.PERSISTED, true)) {
280                 // the breakpoint is marked as not to be persisted,
281
// schedule for deletion
282
delete.add(marker);
283             } else {
284                 persisted.add(marker);
285             }
286         }
287         // delete any markers that are not to be restored
288
if (!delete.isEmpty()) {
289             final IMarker[] delMarkers = (IMarker[])delete.toArray(new IMarker[delete.size()]);
290             IWorkspaceRunnable wr = new IWorkspaceRunnable() {
291                 public void run(IProgressMonitor pm) throws CoreException {
292                     for (int i = 0; i < delMarkers.length; i++) {
293                         IMarker marker = delMarkers[i];
294                         marker.delete();
295                     }
296                 }
297             };
298             new BreakpointManagerJob(wr).schedule();
299         }
300         return (IMarker[])persisted.toArray(new IMarker[persisted.size()]);
301     }
302     
303     /**
304      * Removes this manager as a resource change listener
305      * and removes all breakpoint listeners.
306      */

307     public void shutdown() {
308         getWorkspace().removeResourceChangeListener(this);
309         getWorkspace().removeResourceChangeListener(fPostChangeListener);
310         fBreakpointListeners = null;
311         fBreakpointsListeners = null;
312         fBreakpointManagerListeners = null;
313     }
314
315     /**
316      * Find the defined breakpoint extensions and cache them for use in recreating
317      * breakpoints from markers.
318      */

319     private void initBreakpointExtensions() {
320         IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint(DebugPlugin.getUniqueIdentifier(), DebugPlugin.EXTENSION_POINT_BREAKPOINTS);
321         IConfigurationElement[] elements = ep.getConfigurationElements();
322         for (int i= 0; i < elements.length; i++) {
323             String JavaDoc markerType = elements[i].getAttribute(MARKER_TYPE);
324             String JavaDoc className = elements[i].getAttribute(CLASS);
325             if (markerType == null) {
326                 DebugPlugin.log(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, MessageFormat.format("Breakpoint extension {0} missing required attribute: markerType", new String JavaDoc[]{elements[i].getDeclaringExtension().getUniqueIdentifier()}), null)); //$NON-NLS-1$
327
} else if (className == null){
328                 DebugPlugin.log(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, MessageFormat.format("Breakpoint extension {0} missing required attribute: class", new String JavaDoc[]{elements[i].getDeclaringExtension().getUniqueIdentifier()}), null)); //$NON-NLS-1$
329
} else {
330                 fBreakpointExtensions.put(markerType, elements[i]);
331             }
332         }
333     }
334
335     /**
336      * Convenience method to get the workspace
337      */

338     private IWorkspace getWorkspace() {
339         return ResourcesPlugin.getWorkspace();
340     }
341
342     /**
343      * @see IBreakpointManager#getBreakpoint(IMarker)
344      */

345     public IBreakpoint getBreakpoint(IMarker marker) {
346         // ensure that breakpoints are initialized
347
getBreakpoints0();
348         return (IBreakpoint)fMarkersToBreakpoints.get(marker);
349     }
350
351     /**
352      * @see IBreakpointManager#getBreakpoints()
353      */

354     public IBreakpoint[] getBreakpoints() {
355         Vector JavaDoc breakpoints= getBreakpoints0();
356         IBreakpoint[] temp= new IBreakpoint[breakpoints.size()];
357         breakpoints.copyInto(temp);
358         return temp;
359     }
360     
361     /**
362      * The BreakpointManager waits to load the breakpoints
363      * of the workspace until a request is made to retrieve the
364      * breakpoints.
365      */

366     private synchronized Vector JavaDoc getBreakpoints0() {
367         if (fBreakpoints == null) {
368             initializeBreakpoints();
369         }
370         return fBreakpoints;
371     }
372     
373     /**
374      * @see IBreakpointManager#getBreakpoints(String)
375      */

376     public IBreakpoint[] getBreakpoints(String JavaDoc modelIdentifier) {
377         Vector JavaDoc allBreakpoints= getBreakpoints0();
378         synchronized (allBreakpoints) {
379             ArrayList JavaDoc temp= new ArrayList JavaDoc(allBreakpoints.size());
380             Iterator JavaDoc breakpoints= allBreakpoints.iterator();
381             while (breakpoints.hasNext()) {
382                 IBreakpoint breakpoint= (IBreakpoint) breakpoints.next();
383                 String JavaDoc id= breakpoint.getModelIdentifier();
384                 if (id != null && id.equals(modelIdentifier)) {
385                     temp.add(breakpoint);
386                 }
387             }
388             return (IBreakpoint[]) temp.toArray(new IBreakpoint[temp.size()]);
389         }
390     }
391
392     /**
393      * Loads the list of breakpoints from the breakpoint markers in the
394      * workspace. Start listening to resource deltas.
395      */

396     private void initializeBreakpoints() {
397         setBreakpoints(new Vector JavaDoc(10));
398         try {
399             loadBreakpoints(getWorkspace().getRoot(), false);
400             getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_BUILD);
401             getWorkspace().addResourceChangeListener(fPostChangeListener, IResourceChangeEvent.POST_CHANGE);
402         } catch (CoreException ce) {
403             DebugPlugin.log(ce);
404             setBreakpoints(new Vector JavaDoc(0));
405         }
406     }
407     
408     /**
409      * @see IBreakpointManager#isRegistered(IBreakpoint)
410      */

411     public boolean isRegistered(IBreakpoint breakpoint) {
412         return getBreakpoints0().contains(breakpoint);
413     }
414
415     
416     /**
417      * @see IBreakpointManager#removeBreakpoint(IBreakpoint, boolean)
418      */

419     public void removeBreakpoint(IBreakpoint breakpoint, boolean delete) throws CoreException {
420         removeBreakpoints(new IBreakpoint[]{breakpoint}, delete);
421     }
422     
423     /**
424      * @see IBreakpointManager#removeBreakpoints(IBreakpoint[], boolean)
425      */

426     public void removeBreakpoints(IBreakpoint[] breakpoints, final boolean delete) throws CoreException {
427         final List JavaDoc remove = new ArrayList JavaDoc(breakpoints.length);
428         for (int i = 0; i < breakpoints.length; i++) {
429             IBreakpoint breakpoint = breakpoints[i];
430             if (getBreakpoints0().contains(breakpoint)) {
431                 remove.add(breakpoint);
432             }
433         }
434         if (!remove.isEmpty()) {
435             Iterator JavaDoc iter = remove.iterator();
436             while (iter.hasNext()) {
437                 IBreakpoint breakpoint = (IBreakpoint)iter.next();
438                 getBreakpoints0().remove(breakpoint);
439                 fMarkersToBreakpoints.remove(breakpoint.getMarker());
440             }
441             fireUpdate(remove, null, REMOVED);
442             IWorkspaceRunnable r = new IWorkspaceRunnable() {
443                 public void run(IProgressMonitor montitor) throws CoreException {
444                     Iterator JavaDoc innerIter = remove.iterator();
445                     while (innerIter.hasNext()) {
446                         IBreakpoint breakpoint = (IBreakpoint)innerIter.next();
447                         if (delete) {
448                             breakpoint.delete();
449                         } else {
450                             // if the breakpoint is being removed from the manager
451
// because the project is closing, the breakpoint should
452
// remain as registered, otherwise, the breakpoint should
453
// be marked as unregistered
454
IMarker marker = breakpoint.getMarker();
455                             if (marker.exists()) {
456                                 IProject project = breakpoint.getMarker().getResource().getProject();
457                                 if (project == null || project.isOpen()) {
458                                     breakpoint.setRegistered(false);
459                                 }
460                             }
461                         }
462                     }
463                 }
464             };
465             getWorkspace().run(r, null, 0, null);
466         }
467     }
468     
469     /**
470      * Create a breakpoint for the given marker. The created breakpoint
471      * is of the type specified in the breakpoint extension associated
472      * with the given marker type.
473      *
474      * @param marker marker to create a breakpoint for
475      * @return a breakpoint on this marker
476      * @exception DebugException if breakpoint creation fails. Reasons for
477      * failure include:
478      * <ol>
479      * <li>The breakpoint manager cannot determine what kind of breakpoint
480      * to instantiate for the given marker type</li>
481      * <li>A lower level exception occurred while accessing the given marker</li>
482      * </ol>
483      */

484     public IBreakpoint createBreakpoint(IMarker marker) throws DebugException {
485         IBreakpoint breakpoint= (IBreakpoint) fMarkersToBreakpoints.get(marker);
486         if (breakpoint != null) {
487             return breakpoint;
488         }
489         try {
490             IConfigurationElement config = (IConfigurationElement)fBreakpointExtensions.get(marker.getType());
491             if (config == null) {
492                 throw new DebugException(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
493                     DebugException.CONFIGURATION_INVALID, MessageFormat.format(DebugCoreMessages.BreakpointManager_Missing_breakpoint_definition, new String JavaDoc[] {marker.getType()}), null));
494             }
495             Object JavaDoc object = config.createExecutableExtension(CLASS);
496             if (object instanceof IBreakpoint) {
497                 breakpoint = (IBreakpoint)object;
498                 breakpoint.setMarker(marker);
499             } else {
500                 DebugPlugin.log(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, MessageFormat.format("Breakpoint extension {0} missing required attribute: class", new String JavaDoc[]{config.getAttribute(CLASS), config.getDeclaringExtension().getUniqueIdentifier()}), null)); //$NON-NLS-1$
501
}
502             return breakpoint;
503         } catch (CoreException e) {
504             throw new DebugException(e.getStatus());
505         }
506     }
507
508     /**
509      * @see IBreakpointManager#addBreakpoint(IBreakpoint)
510      */

511     public void addBreakpoint(IBreakpoint breakpoint) throws CoreException {
512         addBreakpoints(new IBreakpoint[]{breakpoint});
513     }
514     
515     /**
516      * @see IBreakpointManager#addBreakpoints(IBreakpoint[])
517      */

518     public void addBreakpoints(IBreakpoint[] breakpoints) throws CoreException {
519         addBreakpoints(breakpoints, true);
520     }
521     
522     /**
523      * Registers the given breakpoints and notifies listeners if specified.
524      *
525      * @param breakpoints the breakpoints to register
526      * @param notify whether to notify listeners of the add
527      * @param loading whether the given breakpoints are being automatically loaded
528      * from previously persisted markers
529      */

530     private void addBreakpoints(IBreakpoint[] breakpoints, boolean notify) throws CoreException {
531         List JavaDoc added = new ArrayList JavaDoc(breakpoints.length);
532         final List JavaDoc update = new ArrayList JavaDoc();
533         for (int i = 0; i < breakpoints.length; i++) {
534             IBreakpoint breakpoint = breakpoints[i];
535             if (!getBreakpoints0().contains(breakpoint)) {
536                 verifyBreakpoint(breakpoint);
537                 if (breakpoint.isRegistered()) {
538                     // If notify == false, the breakpoints are just being added at startup
539
added.add(breakpoint);
540                     getBreakpoints0().add(breakpoint);
541                     fMarkersToBreakpoints.put(breakpoint.getMarker(), breakpoint);
542                 } else {
543                     // need to update the 'registered' and/or 'group' attributes
544
update.add(breakpoint);
545                 }
546             }
547         }
548         if (notify) {
549             fireUpdate(added, null, ADDED);
550         }
551         if (!update.isEmpty()) {
552             IWorkspaceRunnable r = new IWorkspaceRunnable() {
553                 public void run(IProgressMonitor monitor) throws CoreException {
554                     Iterator JavaDoc iter = update.iterator();
555                     while (iter.hasNext()) {
556                         IBreakpoint breakpoint = (IBreakpoint)iter.next();
557                         getBreakpoints0().add(breakpoint);
558                         breakpoint.setRegistered(true);
559                         fMarkersToBreakpoints.put(breakpoint.getMarker(), breakpoint);
560                     }
561                 }
562             };
563             // Need to suppress change notification, since this is really
564
// an add notification
565
fSuppressChange.addAll(update);
566             getWorkspace().run(r, null, 0, null);
567             fSuppressChange.removeAll(update);
568             if (notify) {
569                 fireUpdate(update, null, ADDED);
570             }
571         }
572     }
573     
574     /**
575      * Returns whether change notification is to be suppressed for the given breakpoint.
576      * Used when adding breakpoints and changing the "REGISTERED" attribute.
577      *
578      * @param breakpoint
579      * @return boolean whether change notification is suppressed
580      */

581     protected boolean isChangeSuppressed(IBreakpoint breakpoint) {
582         return fSuppressChange.contains(breakpoint);
583     }
584     
585     /**
586      * @see IBreakpointManager#fireBreakpointChanged(IBreakpoint)
587      */

588     public void fireBreakpointChanged(IBreakpoint breakpoint) {
589         if (getBreakpoints0().contains(breakpoint)) {
590             List JavaDoc changed = new ArrayList JavaDoc();
591             changed.add(breakpoint);
592             fireUpdate(changed, null, CHANGED);
593         }
594     }
595
596     /**
597      * Verifies that the breakpoint marker has the minimal required attributes,
598      * and throws a debug exception if not.
599      */

600     private void verifyBreakpoint(IBreakpoint breakpoint) throws DebugException {
601         try {
602             String JavaDoc id= breakpoint.getModelIdentifier();
603             if (id == null) {
604                 throw new DebugException(new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(),
605                     DebugException.CONFIGURATION_INVALID, DebugCoreMessages.BreakpointManager_Missing_model_identifier, null));
606             }
607         } catch (CoreException e) {
608             throw new DebugException(e.getStatus());
609         }
610     }
611
612     /**
613      * A resource has changed. Traverses the delta for breakpoint changes.
614      *
615      * @param event resource change event
616      */

617     public void resourceChanged(IResourceChangeEvent event) {
618         IResourceDelta delta= event.getDelta();
619         if (delta != null) {
620             try {
621                 if (fgVisitor == null) {
622                     fgVisitor= new BreakpointManagerVisitor();
623                 }
624                 delta.accept(fgVisitor);
625                 fgVisitor.update();
626             } catch (CoreException ce) {
627                 DebugPlugin.log(ce);
628             }
629         }
630     }
631
632     /**
633      * Visitor for handling resource deltas
634      */

635     class BreakpointManagerVisitor implements IResourceDeltaVisitor {
636         /**
637          * Moved markers
638          */

639         private List JavaDoc fMoved = new ArrayList JavaDoc();
640         /**
641          * Removed breakpoints
642          */

643         private List JavaDoc fRemoved = new ArrayList JavaDoc();
644         /**
645          * Changed breakpoints and associated marker deltas
646          */

647         private List JavaDoc fChanged = new ArrayList JavaDoc();
648         private List JavaDoc fChangedDeltas = new ArrayList JavaDoc();
649         
650         /**
651          * Resets the visitor for a delta traversal - empties
652          * collections of removed/changed breakpoints.
653          */

654         protected void reset() {
655             fMoved.clear();
656             fRemoved.clear();
657             fChanged.clear();
658             fChangedDeltas.clear();
659         }
660         
661         /**
662          * Performs updates on accumulated changes, and fires change notification after
663          * a traversal. Accumulated updates are reset.
664          */

665         public void update() {
666             if (!fMoved.isEmpty()) {
667                 // delete moved markers
668
IWorkspaceRunnable wRunnable= new IWorkspaceRunnable() {
669                     public void run(IProgressMonitor monitor) throws CoreException {
670                         IMarker[] markers = (IMarker[])fMoved.toArray(new IMarker[fMoved.size()]);
671                         for (int i = 0; i < markers.length; i++) {
672                             markers[i].delete();
673                         }
674                     }
675                 };
676                 try {
677                     getWorkspace().run(wRunnable, null, 0, null);
678                 } catch (CoreException e) {
679                 }
680             }
681             if (!fRemoved.isEmpty()) {
682                 try {
683                     removeBreakpoints((IBreakpoint[])fRemoved.toArray(new IBreakpoint[fRemoved.size()]), false);
684                 } catch (CoreException e) {
685                     DebugPlugin.log(e);
686                 }
687             }
688             if (!fChanged.isEmpty()) {
689                 fireUpdate(fChanged, fChangedDeltas, CHANGED);
690             }
691             reset();
692         }
693                 
694         /**
695          * @see IResourceDeltaVisitor#visit(IResourceDelta)
696          */

697         public boolean visit(IResourceDelta delta) {
698             if (delta == null) {
699                 return false;
700             }
701             if (0 != (delta.getFlags() & IResourceDelta.OPEN) && 0 == (delta.getFlags() & IResourceDelta.MOVED_FROM)) {
702                 handleProjectResourceOpenStateChange(delta.getResource());
703                 return false;
704             }
705             IMarkerDelta[] markerDeltas= delta.getMarkerDeltas();
706             for (int i= 0; i < markerDeltas.length; i++) {
707                 IMarkerDelta markerDelta= markerDeltas[i];
708                 if (markerDelta.isSubtypeOf(IBreakpoint.BREAKPOINT_MARKER)) {
709                     switch (markerDelta.getKind()) {
710                         case IResourceDelta.ADDED :
711                             handleAddBreakpoint(delta, markerDelta.getMarker(), markerDelta);
712                             break;
713                         case IResourceDelta.REMOVED :
714                             handleRemoveBreakpoint(markerDelta.getMarker());
715                             break;
716                         case IResourceDelta.CHANGED :
717                             handleChangeBreakpoint(markerDelta.getMarker(), markerDelta);
718                             break;
719                     }
720                 }
721             }
722
723             return true;
724         }
725
726         /**
727          * Wrapper for handling adds
728          */

729         protected void handleAddBreakpoint(IResourceDelta rDelta, IMarker marker, IMarkerDelta mDelta) {
730             if (0 != (rDelta.getFlags() & IResourceDelta.MOVED_FROM)) {
731                 // This breakpoint has actually been moved - already removed
732
// from the Breakpoint manager during the remove callback.
733
// Schedule the marker associated with the new resource for deletion.
734
if (getBreakpoint(marker) == null) {
735                     fMoved.add(marker);
736                 }
737             } else {
738                 // check if the an add & change have be combined into one add notification
739
synchronized (fPostChangMarkersChanged) {
740                     if (fPostChangMarkersChanged.contains(marker)) {
741                         handleChangeBreakpoint(marker, mDelta);
742                         fPostChangMarkersChanged.remove(marker);
743                     }
744                     fPostBuildMarkersAdded.add(marker);
745                 }
746             }
747         }
748         
749         /**
750          * Wrapper for handling removes
751          */

752         protected void handleRemoveBreakpoint(IMarker marker) {
753             synchronized (fPostChangMarkersChanged) {
754                 fPostChangMarkersChanged.remove(marker);
755                 fPostBuildMarkersAdded.remove(marker);
756             }
757             IBreakpoint breakpoint= getBreakpoint(marker);
758             if (breakpoint != null) {
759                 fRemoved.add(breakpoint);
760             }
761         }
762
763         /**
764          * Wrapper for handling changes
765          */

766         protected void handleChangeBreakpoint(IMarker marker, IMarkerDelta delta) {
767             IBreakpoint breakpoint= getBreakpoint(marker);
768             if (breakpoint != null && isRegistered(breakpoint) && !isChangeSuppressed(breakpoint)) {
769                 fChanged.add(breakpoint);
770                 fChangedDeltas.add(delta);
771             }
772         }
773         
774         /**
775          * A project has been opened or closed. Updates the breakpoints for
776          * that project
777          */

778         private void handleProjectResourceOpenStateChange(final IResource project) {
779             if (!project.isAccessible()) {
780                 //closed
781
Enumeration JavaDoc breakpoints= ((Vector JavaDoc)getBreakpoints0().clone()).elements();
782                 while (breakpoints.hasMoreElements()) {
783                     IBreakpoint breakpoint= (IBreakpoint) breakpoints.nextElement();
784                     IResource markerResource= breakpoint.getMarker().getResource();
785                     if (project.getFullPath().isPrefixOf(markerResource.getFullPath())) {
786                         fRemoved.add(breakpoint);
787                     }
788                 }
789                 return;
790             }
791             try {
792                 loadBreakpoints(project, true);
793             } catch (CoreException e) {
794                 DebugPlugin.log(e);
795             }
796         }
797     }
798
799     /**
800      * @see IBreakpointManager#addBreakpointListener(IBreakpointListener)
801      */

802     public void addBreakpointListener(IBreakpointListener listener) {
803         fBreakpointListeners.add(listener);
804     }
805
806     /**
807      * @see IBreakpointManager#removeBreakpointListener(IBreakpointListener)
808      */

809     public void removeBreakpointListener(IBreakpointListener listener) {
810         fBreakpointListeners.remove(listener);
811     }
812     
813     /**
814      * Notifies listeners of the adds/removes/changes
815      *
816      * @param breakpoints associated breakpoints
817      * @param deltas or <code>null</code>
818      * @param update type of change
819      */

820     private void fireUpdate(List JavaDoc breakpoints, List JavaDoc deltas, int update) {
821         if (breakpoints.isEmpty()) {
822             return;
823         }
824         IBreakpoint[] bpArray = (IBreakpoint[])breakpoints.toArray(new IBreakpoint[breakpoints.size()]);
825         IMarkerDelta[] deltaArray = new IMarkerDelta[bpArray.length];
826         if (deltas != null) {
827             deltaArray = (IMarkerDelta[])deltas.toArray(deltaArray);
828         }
829         // single listeners
830
getBreakpointNotifier().notify(bpArray, deltaArray, update);
831         
832         // plural listeners
833
getBreakpointsNotifier().notify(bpArray, deltaArray, update);
834     }
835
836     protected void setBreakpoints(Vector JavaDoc breakpoints) {
837         fBreakpoints = breakpoints;
838     }
839     
840     /**
841      * @see IBreakpointManager#hasBreakpoints()
842      */

843     public boolean hasBreakpoints() {
844         return !getBreakpoints0().isEmpty();
845     }
846     
847     /**
848      * @see org.eclipse.debug.core.IBreakpointManager#addBreakpointListener(org.eclipse.debug.core.IBreakpointsListener)
849      */

850     public void addBreakpointListener(IBreakpointsListener listener) {
851         fBreakpointsListeners.add(listener);
852     }
853
854     /**
855      * @see org.eclipse.debug.core.IBreakpointManager#removeBreakpointListener(org.eclipse.debug.core.IBreakpointsListener)
856      */

857     public void removeBreakpointListener(IBreakpointsListener listener) {
858         fBreakpointsListeners.remove(listener);
859     }
860
861     private BreakpointNotifier getBreakpointNotifier() {
862         return new BreakpointNotifier();
863     }
864     
865     /**
866      * Notifies breakpoint listener (single breakpoint) in a safe runnable to
867      * handle exceptions.
868      */

869     class BreakpointNotifier implements ISafeRunnable {
870         
871         private IBreakpointListener fListener;
872         private int fType;
873         private IMarkerDelta fDelta;
874         private IBreakpoint fBreakpoint;
875         
876         /**
877          * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
878          */

879         public void handleException(Throwable JavaDoc exception) {
880             IStatus status = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "An exception occurred during breakpoint change notification.", exception); //$NON-NLS-1$
881
DebugPlugin.log(status);
882         }
883
884         /**
885          * @see org.eclipse.core.runtime.ISafeRunnable#run()
886          */

887         public void run() throws Exception JavaDoc {
888             switch (fType) {
889                 case ADDED:
890                     fListener.breakpointAdded(fBreakpoint);
891                     break;
892                 case REMOVED:
893                     fListener.breakpointRemoved(fBreakpoint, fDelta);
894                     break;
895                 case CHANGED:
896                     fListener.breakpointChanged(fBreakpoint, fDelta);
897                     break;
898             }
899         }
900
901         /**
902          * Notifies the listeners of the add/change/remove
903          *
904          * @param breakpoints the breakpoints that changed
905          * @param deltas the deltas associated with the change
906          * @param update the type of change
907          */

908         public void notify(IBreakpoint[] breakpoints, IMarkerDelta[] deltas, int update) {
909             fType = update;
910             Object JavaDoc[] copiedListeners= fBreakpointListeners.getListeners();
911             for (int i= 0; i < copiedListeners.length; i++) {
912                 fListener = (IBreakpointListener)copiedListeners[i];
913                 for (int j = 0; j < breakpoints.length; j++) {
914                     fBreakpoint = breakpoints[j];
915                     fDelta = deltas[j];
916                     SafeRunner.run(this);
917                 }
918             }
919             fListener = null;
920             fDelta = null;
921             fBreakpoint = null;
922         }
923     }
924     
925     private BreakpointsNotifier getBreakpointsNotifier() {
926         return new BreakpointsNotifier();
927     }
928     
929     /**
930      * Notifies breakpoint listener (multiple breakpoints) in a safe runnable to
931      * handle exceptions.
932      */

933     class BreakpointsNotifier implements ISafeRunnable {
934         
935         private IBreakpointsListener fListener;
936         private int fType;
937         private IMarkerDelta[] fDeltas;
938         private IBreakpoint[] fNotifierBreakpoints;
939         
940         /**
941          * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
942          */

943         public void handleException(Throwable JavaDoc exception) {
944             IStatus status = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "An exception occurred during breakpoint change notification.", exception); //$NON-NLS-1$
945
DebugPlugin.log(status);
946         }
947
948         /**
949          * @see org.eclipse.core.runtime.ISafeRunnable#run()
950          */

951         public void run() throws Exception JavaDoc {
952             switch (fType) {
953                 case ADDED:
954                     fListener.breakpointsAdded(fNotifierBreakpoints);
955                     break;
956                 case REMOVED:
957                     fListener.breakpointsRemoved(fNotifierBreakpoints, fDeltas);
958                     break;
959                 case CHANGED:
960                     fListener.breakpointsChanged(fNotifierBreakpoints, fDeltas);
961                     break;
962             }
963         }
964
965         /**
966          * Notifies the listeners of the adds/changes/removes
967          *
968          * @param breakpoints the breakpoints that changed
969          * @param deltas the deltas associated with the changed breakpoints
970          * @param update the type of change
971          */

972         public void notify(IBreakpoint[] breakpoints, IMarkerDelta[] deltas, int update) {
973             fType = update;
974             fNotifierBreakpoints = breakpoints;
975             fDeltas = deltas;
976             Object JavaDoc[] copiedListeners = fBreakpointsListeners.getListeners();
977             for (int i= 0; i < copiedListeners.length; i++) {
978                 fListener = (IBreakpointsListener)copiedListeners[i];
979                 SafeRunner.run(this);
980             }
981             fDeltas = null;
982             fNotifierBreakpoints = null;
983             fListener = null;
984         }
985     }
986
987     /* (non-Javadoc)
988      * @see org.eclipse.debug.core.IBreakpointManager#isEnabled()
989      */

990     public boolean isEnabled() {
991         return fEnabled;
992     }
993
994     /* (non-Javadoc)
995      * @see org.eclipse.debug.core.IBreakpointManager#setEnabled(boolean)
996      */

997     public void setEnabled(final boolean enabled) {
998         if (fEnabled != enabled) {
999             fEnabled= enabled;
1000            IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
1001                public void run(IProgressMonitor monitor) throws CoreException {
1002                    IBreakpoint[] breakpoints = getBreakpoints();
1003                    for (int i = 0; i < breakpoints.length; i++) {
1004                        IBreakpoint breakpoint = breakpoints[i];
1005                        // Touch the marker (but don't actually change anything) so that the icon in
1006
// the editor ruler will be updated (editors listen to marker changes).
1007
breakpoint.getMarker().setAttribute(IBreakpoint.ENABLED, breakpoint.isEnabled());
1008                    }
1009                }
1010            };
1011            try {
1012                ResourcesPlugin.getWorkspace().run(runnable, null, IWorkspace.AVOID_UPDATE ,null);
1013            } catch (CoreException e) {
1014                DebugPlugin.log(e);
1015            }
1016            new BreakpointManagerNotifier().notify(enabled);
1017        }
1018    }
1019
1020    /* (non-Javadoc)
1021     * @see org.eclipse.debug.core.IBreakpointManager#addBreakpointManagerListener(org.eclipse.debug.core.IBreakpointManagerListener)
1022     */

1023    public void addBreakpointManagerListener(IBreakpointManagerListener listener) {
1024        fBreakpointManagerListeners.add(listener);
1025    }
1026
1027    /* (non-Javadoc)
1028     * @see org.eclipse.debug.core.IBreakpointManager#removeBreakpointManagerListener(org.eclipse.debug.core.IBreakpointManagerListener)
1029     */

1030    public void removeBreakpointManagerListener(IBreakpointManagerListener listener) {
1031        fBreakpointManagerListeners.remove(listener);
1032    }
1033    
1034    /**
1035     * Notifies breakpoint manager listeners in a safe runnable to
1036     * handle exceptions.
1037     */

1038    class BreakpointManagerNotifier implements ISafeRunnable {
1039        
1040        private IBreakpointManagerListener fListener;
1041        private boolean fManagerEnabled;
1042        
1043        /**
1044         * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
1045         */

1046        public void handleException(Throwable JavaDoc exception) {
1047            IStatus status = new Status(IStatus.ERROR, DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, "An exception occurred during breakpoint change notification.", exception); //$NON-NLS-1$
1048
DebugPlugin.log(status);
1049        }
1050
1051        /**
1052         * @see org.eclipse.core.runtime.ISafeRunnable#run()
1053         */

1054        public void run() throws Exception JavaDoc {
1055            fListener.breakpointManagerEnablementChanged(fManagerEnabled);
1056        }
1057
1058        /**
1059         * Notifies the listeners of the enabled state change
1060         *
1061         * @param enabled whether the manager is enabled
1062         */

1063        public void notify(boolean enabled) {
1064            fManagerEnabled= enabled;
1065            Object JavaDoc[] copiedListeners = fBreakpointManagerListeners.getListeners();
1066            for (int i= 0; i < copiedListeners.length; i++) {
1067                fListener = (IBreakpointManagerListener)copiedListeners[i];
1068                SafeRunner.run(this);
1069            }
1070            fListener = null;
1071        }
1072    }
1073    
1074    class BreakpointManagerJob extends Job {
1075        
1076        private final IWorkspaceRunnable fRunnable;
1077
1078        public BreakpointManagerJob (IWorkspaceRunnable wRunnable) {
1079            super("breakpoint manager job"); //$NON-NLS-1$
1080
fRunnable= wRunnable;
1081            setSystem(true);
1082        }
1083
1084        /* (non-Javadoc)
1085         * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
1086         */

1087        protected IStatus run(IProgressMonitor monitor) {
1088            try {
1089                getWorkspace().run(fRunnable, null, 0, null);
1090            } catch (CoreException ce) {
1091                DebugPlugin.log(ce);
1092            }
1093            return new Status(IStatus.OK, DebugPlugin.getUniqueIdentifier(), IStatus.OK, "", null); //$NON-NLS-1$
1094
}
1095    }
1096
1097    /* (non-Javadoc)
1098     * @see org.eclipse.debug.core.IBreakpointManager#getTypeName(org.eclipse.debug.core.model.IBreakpoint)
1099     */

1100    public String JavaDoc getTypeName(IBreakpoint breakpoint) {
1101        String JavaDoc typeName= null;
1102        IMarker marker = breakpoint.getMarker();
1103        if (marker != null) {
1104            try {
1105                IConfigurationElement element = (IConfigurationElement) fBreakpointExtensions.get(marker.getType());
1106                if (element != null) {
1107                    typeName= element.getAttribute(TYPE_NAME);
1108                }
1109            } catch (CoreException e) {
1110            }
1111        }
1112        return typeName;
1113    }
1114}
1115
1116
Popular Tags