KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > debug > core > breakpoints > JavaBreakpoint


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.jdt.internal.debug.core.breakpoints;
12
13  
14 import java.util.ArrayList JavaDoc;
15 import java.util.Collection 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.Map JavaDoc;
21 import java.util.Set JavaDoc;
22
23 import org.eclipse.core.resources.IMarker;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.MultiStatus;
26 import org.eclipse.core.runtime.Preferences;
27 import org.eclipse.debug.core.DebugEvent;
28 import org.eclipse.debug.core.DebugPlugin;
29 import org.eclipse.debug.core.IDebugEventSetListener;
30 import org.eclipse.debug.core.model.Breakpoint;
31 import org.eclipse.debug.core.model.IDebugTarget;
32 import org.eclipse.jdt.debug.core.IJavaBreakpoint;
33 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
34 import org.eclipse.jdt.debug.core.IJavaObject;
35 import org.eclipse.jdt.debug.core.IJavaThread;
36 import org.eclipse.jdt.debug.core.IJavaType;
37 import org.eclipse.jdt.debug.core.JDIDebugModel;
38 import org.eclipse.jdt.internal.debug.core.IJDIEventListener;
39 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
40 import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
41 import org.eclipse.jdt.internal.debug.core.model.JDIObjectValue;
42 import org.eclipse.jdt.internal.debug.core.model.JDIThread;
43 import org.eclipse.jdt.internal.debug.core.model.JDIType;
44
45 import com.ibm.icu.text.MessageFormat;
46 import com.sun.jdi.ObjectReference;
47 import com.sun.jdi.ReferenceType;
48 import com.sun.jdi.ThreadReference;
49 import com.sun.jdi.VMDisconnectedException;
50 import com.sun.jdi.event.ClassPrepareEvent;
51 import com.sun.jdi.event.Event;
52 import com.sun.jdi.event.LocatableEvent;
53 import com.sun.jdi.request.ClassPrepareRequest;
54 import com.sun.jdi.request.EventRequest;
55 import com.sun.jdi.request.EventRequestManager;
56
57 public abstract class JavaBreakpoint extends Breakpoint implements IJavaBreakpoint, IJDIEventListener, IDebugEventSetListener {
58
59     /**
60      * Breakpoint attribute storing the expired value (value <code>"org.eclipse.jdt.debug.core.expired"</code>).
61      * This attribute is stored as a <code>boolean</code>. Once a hit count has
62      * been reached, a breakpoint is considered to be "expired".
63      */

64     protected static final String JavaDoc EXPIRED = "org.eclipse.jdt.debug.core.expired"; //$NON-NLS-1$
65
/**
66      * Breakpoint attribute storing a breakpoint's hit count value
67      * (value <code>"org.eclipse.jdt.debug.core.hitCount"</code>). This attribute is stored as an
68      * <code>int</code>.
69      */

70     protected static final String JavaDoc HIT_COUNT = "org.eclipse.jdt.debug.core.hitCount"; //$NON-NLS-1$
71
/**
72      * Breakpoint attribute storing the number of debug targets a
73      * breakpoint is installed in (value <code>"org.eclipse.jdt.debug.core.installCount"</code>).
74      * This attribute is a <code>int</code>.
75      */

76     protected static final String JavaDoc INSTALL_COUNT = "org.eclipse.jdt.debug.core.installCount"; //$NON-NLS-1$
77

78     /**
79      * Breakpoint attribute storing the fully qualified name of the type
80      * this breakpoint is located in.
81      * (value <code>"org.eclipse.jdt.debug.core.typeName"</code>). This attribute is a <code>String</code>.
82      */

83     protected static final String JavaDoc TYPE_NAME = "org.eclipse.jdt.debug.core.typeName"; //$NON-NLS-1$
84

85     /**
86      * Breakpoint attribute storing suspend policy code for
87      * this breakpoint.
88      * (value <code>"org.eclipse.jdt.debug.core.suspendPolicy</code>).
89      * This attribute is an <code>int</code> corresponding
90      * to <code>IJavaBreakpoint.SUSPEND_VM</code> or
91      * <code>IJavaBreakpoint.SUSPEND_THREAD</code>.
92      */

93     protected static final String JavaDoc SUSPEND_POLICY = "org.eclipse.jdt.debug.core.suspendPolicy"; //$NON-NLS-1$
94

95     /**
96      * Stores the collection of requests that this breakpoint has installed in
97      * debug targets.
98      * key: a debug target
99      * value: the requests this breakpoint has installed in that target
100      */

101     protected HashMap JavaDoc fRequestsByTarget;
102     
103     /**
104      * The list of threads (ThreadReference objects) in which this breakpoint will suspend,
105      * associated with the target in which each thread exists (JDIDebugTarget).
106      * key: targets the debug targets (IJavaDebugTarget)
107      * value: thread the filtered thread (IJavaThread) in the given target
108      */

109     protected Map JavaDoc fFilteredThreadsByTarget;
110     
111     /**
112      * Stores the type name that this breakpoint was last installed
113      * in. When a breakpoint is created, the TYPE_NAME attribute assigned to it
114      * is that of its top level enclosing type. When installed, the type
115      * may actually be an inner type. We need to keep track of the type
116      * type the breakpoint was installed in, in case we need to re-install
117      * the breakpoint for HCR (i.e. in case an inner type is HCR'd).
118      */

119     protected String JavaDoc fInstalledTypeName = null;
120     
121     /**
122      * List of targets in which this breakpoint is installed.
123      * Used to prevent firing of more than one install notification
124      * when a breakpoint's requests are re-created.
125      */

126     protected Set JavaDoc fInstalledTargets = null;
127     
128     /**
129      * List of active instance filters for this breakpoint
130      * (list of <code>IJavaObject</code>).
131      */

132     protected List JavaDoc fInstanceFilters = null;
133     
134     /**
135      * Empty instance filters array.
136      */

137     protected static final IJavaObject[] fgEmptyInstanceFilters = new IJavaObject[0];
138     
139     /**
140      * Property identifier for a breakpoint object on an event request
141      */

142     public static final String JavaDoc JAVA_BREAKPOINT_PROPERTY = "org.eclipse.jdt.debug.breakpoint"; //$NON-NLS-1$
143

144     /**
145      * JavaBreakpoint attributes
146      */

147     protected static final String JavaDoc[] fgExpiredEnabledAttributes= new String JavaDoc[]{EXPIRED, ENABLED};
148     
149     public JavaBreakpoint() {
150         fRequestsByTarget = new HashMap JavaDoc(1);
151         fFilteredThreadsByTarget= new HashMap JavaDoc(1);
152     }
153
154     /* (non-Javadoc)
155      * @see org.eclipse.debug.core.model.IBreakpoint#getModelIdentifier()
156      */

157     public String JavaDoc getModelIdentifier() {
158         return JDIDebugModel.getPluginIdentifier();
159     }
160
161     /* (non-Javadoc)
162      * @see org.eclipse.debug.core.model.Breakpoint#setMarker(org.eclipse.core.resources.IMarker)
163      */

164     public void setMarker(IMarker marker) throws CoreException {
165         super.setMarker(marker);
166         configureAtStartup();
167     }
168
169     /**
170      * Add this breakpoint to the breakpoint manager,
171      * or sets it as unregistered.
172      */

173     protected void register(boolean register) throws CoreException {
174         DebugPlugin plugin = DebugPlugin.getDefault();
175         if (plugin != null && register) {
176             plugin.getBreakpointManager().addBreakpoint(this);
177         } else {
178             setRegistered(false);
179         }
180     }
181     
182     /**
183      * Add the given event request to the given debug target. If
184      * the request is the breakpoint request associated with this
185      * breakpoint, increment the install count.
186      */

187     protected void registerRequest(EventRequest request, JDIDebugTarget target) throws CoreException {
188         if (request == null) {
189             return;
190         }
191         List JavaDoc reqs = getRequests(target);
192         if (reqs.isEmpty()) {
193             fRequestsByTarget.put(target, reqs);
194         }
195         reqs.add(request);
196         target.addJDIEventListener(this, request);
197         // update the install attribute on the breakpoint
198
if (!(request instanceof ClassPrepareRequest)) {
199             incrementInstallCount();
200             // notification
201
fireInstalled(target);
202         }
203     }
204     
205     /**
206      * Returns a String corresponding to the reference type
207      * name to the top enclosing type in which this breakpoint
208      * is located or <code>null</code> if no reference type could be
209      * found.
210      */

211     protected String JavaDoc getEnclosingReferenceTypeName() throws CoreException {
212         String JavaDoc name= getTypeName();
213         int index = name.indexOf('$');
214         if (index == -1) {
215             return name;
216         }
217         return name.substring(0, index);
218     }
219         
220     /**
221      * Returns the requests that this breakpoint has installed
222      * in the given target.
223      */

224     protected ArrayList JavaDoc getRequests(JDIDebugTarget target) {
225         ArrayList JavaDoc list= (ArrayList JavaDoc)fRequestsByTarget.get(target);
226         if (list == null) {
227             list= new ArrayList JavaDoc(2);
228         }
229         return list;
230     }
231     
232     /**
233      * Remove the given request from the given target. If the request
234      * is the breakpoint request associated with this breakpoint,
235      * decrement the install count.
236      */

237     protected void deregisterRequest(EventRequest request, JDIDebugTarget target) throws CoreException {
238         target.removeJDIEventListener(this, request);
239         // A request may be getting de-registered because the breakpoint has
240
// been deleted. It may be that this occurred because of a marker deletion.
241
// Don't try updating the marker (decrementing the install count) if
242
// it no longer exists.
243
if (!(request instanceof ClassPrepareRequest) && getMarker().exists()) {
244             decrementInstallCount();
245         }
246     }
247
248     /* (non-Javadoc)
249      * @see org.eclipse.jdt.internal.debug.core.IJDIEventListener#handleEvent(com.sun.jdi.event.Event, org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget)
250      */

251     public boolean handleEvent(Event event, JDIDebugTarget target) {
252         if (event instanceof ClassPrepareEvent) {
253             return handleClassPrepareEvent((ClassPrepareEvent)event, target);
254         }
255         ThreadReference threadRef= ((LocatableEvent)event).thread();
256         JDIThread thread= target.findThread(threadRef);
257         if (thread == null || thread.isIgnoringBreakpoints()) {
258             return true;
259         }
260         return handleBreakpointEvent(event, target, thread);
261     }
262     
263     /* (non-Javadoc)
264      * @see org.eclipse.jdt.internal.debug.core.IJDIEventListener#wonSuspendVote(com.sun.jdi.event.Event, org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget)
265      */

266     public void wonSuspendVote(Event event, JDIDebugTarget target) {
267         ThreadReference threadRef = null;
268         if (event instanceof ClassPrepareEvent) {
269             threadRef = ((ClassPrepareEvent)event).thread();
270         } else if (event instanceof LocatableEvent) {
271             threadRef = ((LocatableEvent)event).thread();
272         }
273         if (threadRef == null) {
274             return;
275         }
276         JDIThread thread= target.findThread(threadRef);
277         if (thread == null || thread.isIgnoringBreakpoints()) {
278             return;
279         }
280         thread.wonSuspendVote(this);
281     }
282
283     /**
284      * Handle the given class prepare event, which was generated by the
285      * class prepare event installed in the given target by this breakpoint.
286      *
287      * If the class which has been loaded is a class in which this breakpoint
288      * should install, create a breakpoint request for that class.
289      */

290     public boolean handleClassPrepareEvent(ClassPrepareEvent event, JDIDebugTarget target) {
291         try {
292             if (!installableReferenceType(event.referenceType(), target)) {
293                 // Don't install this breakpoint in an
294
// inappropriate type
295
return true;
296             }
297             createRequest(target, event.referenceType());
298         } catch (CoreException e) {
299             JDIDebugPlugin.log(e);
300         }
301         return true;
302     }
303     
304     /**
305      * @see IJDIEventListener#handleEvent(Event, JDIDebugTarget)
306      *
307      * Handle the given event, which was generated by the breakpoint request
308      * installed in the given target by this breakpoint.
309      */

310     public boolean handleBreakpointEvent(Event event, JDIDebugTarget target, JDIThread thread) {
311         expireHitCount(event);
312         return !suspend(thread); // Resume if suspend fails
313
}
314     
315     /**
316      * Delegates to the given thread to suspend, and
317      * returns whether the thread suspended
318      * It is possible that the thread will not suspend
319      * as directed by a Java breakpoint listener.
320      *
321      * @see IJavaBreakpointListener#breakpointHit(IJavaThread, IJavaBreakpoint)
322      */

323     protected boolean suspend(JDIThread thread) {
324         return thread.handleSuspendForBreakpoint(this, true);
325     }
326     
327     /**
328      * Returns whether the given reference type is appropriate for this
329      * breakpoint to be installed in the given target. Query registered
330      * breakpoint listeners.
331      */

332     protected boolean installableReferenceType(ReferenceType type, JDIDebugTarget target) throws CoreException {
333         String JavaDoc installableType= getTypeName();
334         String JavaDoc queriedType= type.name();
335         if (installableType == null || queriedType == null) {
336             return false;
337         }
338         int index= queriedType.indexOf('<');
339         if (index != -1) {
340             queriedType= queriedType.substring(0, index);
341         }
342         if (installableType.equals(queriedType)) {
343             return queryInstallListeners(target, type);
344         }
345         index= queriedType.indexOf('$', 0);
346         if (index == -1) {
347             return false;
348         }
349         if (installableType.regionMatches(0, queriedType, 0, index)) {
350             return queryInstallListeners(target, type);
351         }
352         return false;
353     }
354     
355     /**
356      * Called when a breakpoint event is encountered. Expires the
357      * hit count in the event's request and updates the marker.
358      * @param event the event whose request should have its hit count
359      * expired or <code>null</code> to only update the breakpoint marker.
360      */

361     protected void expireHitCount(Event event) {
362         Integer JavaDoc requestCount= null;
363         EventRequest request= null;
364         if (event != null) {
365             request= event.request();
366             requestCount= (Integer JavaDoc) request.getProperty(HIT_COUNT);
367         }
368         if (requestCount != null) {
369             if (request != null) {
370                 request.putProperty(EXPIRED, Boolean.TRUE);
371             }
372             try {
373                 setAttributes(fgExpiredEnabledAttributes, new Object JavaDoc[]{Boolean.TRUE, Boolean.FALSE});
374                 // make a note that we auto-disabled this breakpoint.
375
} catch (CoreException ce) {
376                 JDIDebugPlugin.log(ce);
377             }
378         }
379     }
380     
381     /**
382      * Returns whether this breakpoint should be "skipped". Breakpoints
383      * are skipped if the breakpoint manager is disabled and the breakpoint
384      * is registered with the manager
385      *
386      * @return whether this breakpoint should be skipped
387      */

388     public boolean shouldSkipBreakpoint() throws CoreException {
389         DebugPlugin plugin = DebugPlugin.getDefault();
390         return plugin != null && isRegistered() && !plugin.getBreakpointManager().isEnabled();
391     }
392
393     /**
394      * Attempts to create a breakpoint request for this breakpoint in the given
395      * reference type in the given target.
396      *
397      * @return Whether a request was created
398      */

399     protected boolean createRequest(JDIDebugTarget target, ReferenceType type) throws CoreException {
400         if (shouldSkipBreakpoint()) {
401             return false;
402         }
403         EventRequest[] requests= newRequests(target, type);
404         if (requests == null) {
405             return false;
406         }
407         fInstalledTypeName = type.name();
408         for (int i = 0; i < requests.length; i++) {
409             EventRequest request = requests[i];
410             registerRequest(request, target);
411         }
412         return true;
413     }
414     
415     /**
416      * Configure a breakpoint request with common properties:
417      * <ul>
418      * <li><code>JAVA_BREAKPOINT_PROPERTY</code></li>
419      * <li><code>HIT_COUNT</code></li>
420      * <li><code>EXPIRED</code></li>
421      * </ul>
422      * and sets the suspend policy of the request to suspend
423      * the event thread.
424      */

425     protected void configureRequest(EventRequest request, JDIDebugTarget target) throws CoreException {
426         request.setSuspendPolicy(getJDISuspendPolicy());
427         request.putProperty(JAVA_BREAKPOINT_PROPERTY, this);
428         configureRequestThreadFilter(request, target);
429         configureRequestHitCount(request);
430         configureInstanceFilters(request, target);
431         // Important: only enable a request after it has been configured
432
updateEnabledState(request, target);
433     }
434     
435     /**
436      * Adds an instance filter to the given request. Since the implementation is
437      * request specific, subclasses must override.
438      *
439      * @param request
440      * @param object instance filter
441      */

442     protected abstract void addInstanceFilter(EventRequest request, ObjectReference object);
443     
444     /**
445      * Configure the thread filter property of the given request.
446      */

447     protected void configureRequestThreadFilter(EventRequest request, JDIDebugTarget target) {
448         IJavaThread thread= (IJavaThread)fFilteredThreadsByTarget.get(target);
449         if (thread == null || (!(thread instanceof JDIThread))) {
450             return;
451         }
452         setRequestThreadFilter(request, ((JDIThread)thread).getUnderlyingThread());
453     }
454     
455     /**
456      * Configure the given request's hit count
457      */

458     protected void configureRequestHitCount(EventRequest request) throws CoreException {
459         int hitCount= getHitCount();
460         if (hitCount > 0) {
461             request.addCountFilter(hitCount);
462             request.putProperty(HIT_COUNT, new Integer JavaDoc(hitCount));
463         }
464     }
465     
466     protected void configureInstanceFilters(EventRequest request, JDIDebugTarget target) {
467         if (fInstanceFilters != null && !fInstanceFilters.isEmpty()) {
468             Iterator JavaDoc iter = fInstanceFilters.iterator();
469             while (iter.hasNext()) {
470                 IJavaObject object = (IJavaObject)iter.next();
471                 if (object.getDebugTarget().equals(target)) {
472                     addInstanceFilter(request, ((JDIObjectValue)object).getUnderlyingObject());
473                 }
474             }
475         }
476     }
477     
478     /**
479      * Creates, installs, and returns all event requests for this breakpoint
480      * in the given reference type and and target.
481      *
482      * @return the event requests created or <code>null</code> if creation failed
483      */

484     protected abstract EventRequest[] newRequests(JDIDebugTarget target, ReferenceType type) throws CoreException;
485     
486     /**
487      * Add this breakpoint to the given target. After it has been
488      * added to the given target, this breakpoint will suspend
489      * execution of that target as appropriate.
490      */

491     public void addToTarget(JDIDebugTarget target) throws CoreException {
492         fireAdding(target);
493         createRequests(target);
494     }
495     
496     /**
497      * Creates event requests for the given target
498      */

499     protected void createRequests(JDIDebugTarget target) throws CoreException {
500         if (target.isTerminated() || shouldSkipBreakpoint()) {
501             return;
502         }
503         String JavaDoc referenceTypeName= getTypeName();
504         String JavaDoc enclosingTypeName= getEnclosingReferenceTypeName();
505         if (referenceTypeName == null || enclosingTypeName == null) {
506             return;
507         }
508         // create request to listen to class loads
509
if (referenceTypeName.indexOf('$') == -1) {
510             registerRequest(target.createClassPrepareRequest(enclosingTypeName), target);
511             //register to ensure we hear about local and anonymous inner classes
512
registerRequest(target.createClassPrepareRequest(enclosingTypeName + "$*"), target); //$NON-NLS-1$
513
} else {
514             registerRequest(target.createClassPrepareRequest(referenceTypeName), target);
515             //register to ensure we hear about local and anonymous inner classes
516
registerRequest(target.createClassPrepareRequest(enclosingTypeName + "$*", referenceTypeName), target); //$NON-NLS-1$
517
}
518
519         // create breakpoint requests for each class currently loaded
520
List JavaDoc classes= target.jdiClassesByName(referenceTypeName);
521         if (classes.isEmpty() && enclosingTypeName.equals(referenceTypeName)) {
522             return;
523         }
524
525         boolean success= false;
526         Iterator JavaDoc iter = classes.iterator();
527         while (iter.hasNext()) {
528             ReferenceType type= (ReferenceType) iter.next();
529             if (createRequest(target, type)) {
530                 success= true;
531             }
532         }
533
534         if (!success) {
535             addToTargetForLocalType(target, enclosingTypeName);
536         }
537     }
538     
539     /**
540      * Local types (types defined in methods) are handled specially due to the
541      * different types that the local type is associated with as well as the
542      * performance problems of using ReferenceType#nestedTypes. From the Java
543      * model perspective a local type is defined within a method of a type.
544      * Therefore the type of a breakpoint placed in a local type is the type
545      * that encloses the method where the local type was defined.
546      * The local type is enclosed within the top level type according
547      * to the VM.
548      * So if "normal" attempts to create a request when a breakpoint is
549      * being added to a target fail, we must be dealing with a local type and therefore resort
550      * to looking up all of the nested types of the top level enclosing type.
551      */

552     protected void addToTargetForLocalType(JDIDebugTarget target, String JavaDoc enclosingTypeName) throws CoreException {
553         List JavaDoc classes= target.jdiClassesByName(enclosingTypeName);
554         if (!classes.isEmpty()) {
555             Iterator JavaDoc iter = classes.iterator();
556             while (iter.hasNext()) {
557                 ReferenceType type= (ReferenceType) iter.next();
558                 Iterator JavaDoc nestedTypes= type.nestedTypes().iterator();
559                 while (nestedTypes.hasNext()) {
560                     ReferenceType nestedType= (ReferenceType) nestedTypes.next();
561                     if (createRequest(target, nestedType)) {
562                         break;
563                     }
564                 }
565             }
566         }
567     }
568             
569     /**
570      * Returns the JDI suspend policy that corresponds to this
571      * breakpoint's suspend policy
572      *
573      * @return the JDI suspend policy that corresponds to this
574      * breakpoint's suspend policy
575      * @exception CoreException if unable to access this breakpoint's
576      * suspend policy setting
577      */

578     protected int getJDISuspendPolicy() throws CoreException {
579         int breakpointPolicy = getSuspendPolicy();
580         if (breakpointPolicy == IJavaBreakpoint.SUSPEND_THREAD) {
581             return EventRequest.SUSPEND_EVENT_THREAD;
582         }
583         return EventRequest.SUSPEND_ALL;
584     }
585
586     /**
587      * returns the default suspend policy based on the pref setting on the
588      * Java-Debug pref page
589      * @return the default suspend policy
590      * @since 3.2
591      */

592     protected int getDefaultSuspendPolicy() {
593         Preferences store = JDIDebugModel.getPreferences();
594         return store.getInt(JDIDebugPlugin.PREF_DEFAULT_BREAKPOINT_SUSPEND_POLICY);
595     }
596     
597     
598     /**
599      * Returns whether the hitCount of this breakpoint is equal to the hitCount of
600      * the associated request.
601      */

602     protected boolean hasHitCountChanged(EventRequest request) throws CoreException {
603         int hitCount= getHitCount();
604         Integer JavaDoc requestCount= (Integer JavaDoc) request.getProperty(HIT_COUNT);
605         int oldCount = -1;
606         if (requestCount != null) {
607             oldCount = requestCount.intValue();
608         }
609         return hitCount != oldCount;
610     }
611     
612     /**
613      * Removes this breakpoint from the given target.
614      */

615     public void removeFromTarget(final JDIDebugTarget target) throws CoreException {
616         removeRequests(target);
617         Object JavaDoc removed = fFilteredThreadsByTarget.remove(target);
618         boolean changed = removed != null;
619         boolean markerExists = markerExists();
620         if (!markerExists || (markerExists && getInstallCount() == 0)) {
621             fInstalledTypeName = null;
622         }
623         
624         // remove instance filters
625
if (fInstanceFilters != null && !fInstanceFilters.isEmpty()) {
626             for (int i = 0; i < fInstanceFilters.size(); i++) {
627                 IJavaObject object = (IJavaObject)fInstanceFilters.get(i);
628                 if (object.getDebugTarget().equals(target)) {
629                     fInstanceFilters.remove(i);
630                     changed = true;
631                 }
632             }
633         }
634         
635         // fire change notification if required
636
if (changed) {
637             fireChanged();
638         }
639         
640         // notification
641
fireRemoved(target);
642     }
643     
644     /**
645      * Remove all requests that this breakpoint has installed in the given
646      * debug target.
647      */

648     protected void removeRequests(final JDIDebugTarget target) throws CoreException {
649         // removing was previously done is a workspace runnable, but that is
650
// not possible since it can be a resource callback (marker deletion) that
651
// causes a breakpoint to be removed
652
ArrayList JavaDoc requests= (ArrayList JavaDoc)getRequests(target).clone();
653         // Iterate over a copy of the requests since this list of requests
654
// can be changed in other threads which would cause an ConcurrentModificationException
655
Iterator JavaDoc iter = requests.iterator();
656         EventRequest req;
657         while (iter.hasNext()) {
658             req = (EventRequest)iter.next();
659             try {
660                 if (target.isAvailable() && !isExpired(req)) { // cannot delete an expired request
661
EventRequestManager manager = target.getEventRequestManager();
662                     if (manager != null) {
663                         manager.deleteEventRequest(req); // disable & remove
664
}
665                 }
666             } catch (VMDisconnectedException e) {
667                 if (target.isAvailable()) {
668                     JDIDebugPlugin.log(e);
669                 }
670             } catch (RuntimeException JavaDoc e) {
671                 target.internalError(e);
672             } finally {
673                 deregisterRequest(req, target);
674             }
675         }
676         fRequestsByTarget.remove(target);
677     }
678         
679     /**
680      * Update the enabled state of the given request in the given target, which is associated
681      * with this breakpoint. Set the enabled state of the request
682      * to the enabled state of this breakpoint.
683      */

684     protected void updateEnabledState(EventRequest request, JDIDebugTarget target) throws CoreException {
685         internalUpdateEnabledState(request, isEnabled(), target);
686     }
687     
688     /**
689      * Set the enabled state of the given request to the given
690      * value, also taking into account instance filters.
691      */

692     protected void internalUpdateEnabledState(EventRequest request, boolean enabled, JDIDebugTarget target) {
693         if (request.isEnabled() != enabled) {
694             // change the enabled state
695
try {
696                 // if the request has expired, do not disable.
697
// BreakpointRequests that have expired cannot be deleted.
698
if (!isExpired(request)) {
699                     request.setEnabled(enabled);
700                 }
701             } catch (VMDisconnectedException e) {
702             } catch (RuntimeException JavaDoc e) {
703                 target.internalError(e);
704             }
705         }
706     }
707         
708     /**
709      * Returns whether this breakpoint has expired.
710      */

711     public boolean isExpired() throws CoreException {
712         return ensureMarker().getAttribute(EXPIRED, false);
713     }
714     
715     /**
716      * Returns whether the given request is expired
717      */

718     protected boolean isExpired(EventRequest request) {
719         Boolean JavaDoc requestExpired= (Boolean JavaDoc) request.getProperty(EXPIRED);
720         if (requestExpired == null) {
721                 return false;
722         }
723         return requestExpired.booleanValue();
724     }
725
726     /* (non-Javadoc)
727      * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#isInstalled()
728      */

729     public boolean isInstalled() throws CoreException {
730         return ensureMarker().getAttribute(INSTALL_COUNT, 0) > 0;
731     }
732     
733     /**
734      * Increments the install count of this breakpoint
735      */

736     protected void incrementInstallCount() throws CoreException {
737         int count = getInstallCount();
738         setAttribute(INSTALL_COUNT, count + 1);
739     }
740     
741     /**
742      * Returns the <code>INSTALL_COUNT</code> attribute of this breakpoint
743      * or 0 if the attribute is not set.
744      */

745     public int getInstallCount() throws CoreException {
746         return ensureMarker().getAttribute(INSTALL_COUNT, 0);
747     }
748
749     /**
750      * Decrements the install count of this breakpoint.
751      */

752     protected void decrementInstallCount() throws CoreException {
753         int count= getInstallCount();
754         if (count > 0) {
755             setAttribute(INSTALL_COUNT, count - 1);
756         }
757         if (count == 1) {
758             if (isExpired()) {
759                 // if breakpoint was auto-disabled, re-enable it
760
setAttributes(fgExpiredEnabledAttributes,
761                         new Object JavaDoc[]{Boolean.FALSE, Boolean.TRUE});
762             }
763         }
764     }
765     
766     /**
767      * Sets the type name in which to install this breakpoint.
768      */

769     protected void setTypeName(String JavaDoc typeName) throws CoreException {
770         setAttribute(TYPE_NAME, typeName);
771     }
772
773     /* (non-Javadoc)
774      * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getTypeName()
775      */

776     public String JavaDoc getTypeName() throws CoreException {
777         if (fInstalledTypeName == null) {
778             return ensureMarker().getAttribute(TYPE_NAME, null);
779         }
780         return fInstalledTypeName;
781     }
782     
783     /**
784      * Resets the install count attribute on this breakpoint's marker
785      * to "0". Resets the expired attribute on all breakpoint markers to <code>false</code>.
786      * Resets the enabled attribute on the breakpoint marker to <code>true</code>.
787      * If a workbench crashes, the attributes could have been persisted
788      * in an incorrect state.
789      */

790     private void configureAtStartup() throws CoreException {
791         List JavaDoc attributes= null;
792         List JavaDoc values= null;
793         if (isInstalled()) {
794             attributes= new ArrayList JavaDoc(3);
795             values= new ArrayList JavaDoc(3);
796             attributes.add(INSTALL_COUNT);
797             values.add(new Integer JavaDoc(0));
798         }
799         if (isExpired()) {
800             if (attributes == null) {
801                 attributes= new ArrayList JavaDoc(3);
802                 values= new ArrayList JavaDoc(3);
803             }
804             // if breakpoint was auto-disabled, re-enable it
805
attributes.add(EXPIRED);
806             values.add(Boolean.FALSE);
807             attributes.add(ENABLED);
808             values.add(Boolean.TRUE);
809         }
810         if (attributes != null) {
811             String JavaDoc[] strAttributes= new String JavaDoc[attributes.size()];
812             setAttributes((String JavaDoc[])attributes.toArray(strAttributes), values.toArray());
813         }
814     }
815
816     /* (non-Javadoc)
817      * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getHitCount()
818      */

819     public int getHitCount() throws CoreException {
820         return ensureMarker().getAttribute(HIT_COUNT, -1);
821     }
822     
823     /* (non-Javadoc)
824      * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#setHitCount(int)
825      */

826     public void setHitCount(int count) throws CoreException {
827         if (getHitCount() != count) {
828             if (!isEnabled() && count > -1) {
829                 setAttributes(new String JavaDoc []{ENABLED, HIT_COUNT, EXPIRED},
830                     new Object JavaDoc[]{Boolean.TRUE, new Integer JavaDoc(count), Boolean.FALSE});
831             } else {
832                 setAttributes(new String JavaDoc[]{HIT_COUNT, EXPIRED},
833                     new Object JavaDoc[]{new Integer JavaDoc(count), Boolean.FALSE});
834             }
835             recreate();
836         }
837     }
838     
839     protected String JavaDoc getMarkerMessage(int hitCount, int suspendPolicy) {
840         StringBuffer JavaDoc buff= new StringBuffer JavaDoc();
841         if (hitCount > 0){
842             buff.append(MessageFormat.format(JDIDebugBreakpointMessages.JavaBreakpoint___Hit_Count___0___1, new Object JavaDoc[]{Integer.toString(hitCount)}));
843             buff.append(' ');
844         }
845         String JavaDoc suspendPolicyString;
846         if (suspendPolicy == IJavaBreakpoint.SUSPEND_THREAD) {
847             suspendPolicyString= JDIDebugBreakpointMessages.JavaBreakpoint__suspend_policy__thread__1;
848         } else {
849             suspendPolicyString= JDIDebugBreakpointMessages.JavaBreakpoint__suspend_policy__VM__2;
850         }
851         
852         buff.append(suspendPolicyString);
853         return buff.toString();
854     }
855     
856     /**
857      * Sets whether this breakpoint's hit count has expired.
858      */

859     public void setExpired(boolean expired) throws CoreException {
860         setAttribute(EXPIRED, expired);
861     }
862
863     /* (non-Javadoc)
864      * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getSuspendPolicy()
865      */

866     public int getSuspendPolicy() throws CoreException {
867         return ensureMarker().getAttribute(SUSPEND_POLICY, IJavaBreakpoint.SUSPEND_THREAD);
868     }
869
870     /* (non-Javadoc)
871      * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#setSuspendPolicy(int)
872      */

873     public void setSuspendPolicy(int suspendPolicy) throws CoreException {
874         if(getSuspendPolicy() != suspendPolicy) {
875             setAttribute(SUSPEND_POLICY, suspendPolicy);
876             recreate();
877         }
878     }
879     
880     /**
881      * Notifies listeners this breakpoint is to be added to the
882      * given target.
883      *
884      * @param target debug target
885      */

886     protected void fireAdding(IJavaDebugTarget target) {
887         JDIDebugPlugin plugin = JDIDebugPlugin.getDefault();
888         if (plugin != null)
889             plugin.fireBreakpointAdding(target, this);
890     }
891     
892     /**
893      * Notifies listeners this breakpoint has been removed from the
894      * given target.
895      *
896      * @param target debug target
897      */

898     protected void fireRemoved(IJavaDebugTarget target) {
899         JDIDebugPlugin plugin = JDIDebugPlugin.getDefault();
900         if (plugin != null) {
901             plugin.fireBreakpointRemoved(target, this);
902             setInstalledIn(target, false);
903         }
904     }
905     
906     /**
907      * Notifies listeners this breakpoint has been installed in the
908      * given target.
909      *
910      * @param target debug target
911      */

912     protected void fireInstalled(IJavaDebugTarget target) {
913         JDIDebugPlugin plugin = JDIDebugPlugin.getDefault();
914         if (plugin!= null && !isInstalledIn(target)) {
915             plugin.fireBreakpointInstalled(target, this);
916             setInstalledIn(target, true);
917         }
918     }
919     
920     /**
921      * Returns whether this breakpoint is installed in the given target.
922      *
923      * @param target
924      * @return whether this breakpoint is installed in the given target
925      */

926     protected boolean isInstalledIn(IJavaDebugTarget target) {
927         return fInstalledTargets != null && fInstalledTargets.contains(target);
928     }
929     
930     /**
931      * Sets this breakpoint as installed in the given target
932      *
933      * @param target
934      * @param installed whether installed
935      */

936     protected void setInstalledIn(IJavaDebugTarget target, boolean installed) {
937         if (installed) {
938             if (fInstalledTargets == null) {
939                 fInstalledTargets = new HashSet JavaDoc();
940             }
941             fInstalledTargets.add(target);
942         } else {
943             if (fInstalledTargets != null) {
944                 fInstalledTargets.remove(target);
945             }
946         }
947     }
948     
949     /* (non-Javadoc)
950      * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#setThreadFilter(org.eclipse.jdt.debug.core.IJavaThread)
951      */

952     public void setThreadFilter(IJavaThread thread) throws CoreException {
953         if (!(thread.getDebugTarget() instanceof JDIDebugTarget) || !(thread instanceof JDIThread)) {
954             return;
955         }
956         JDIDebugTarget target= (JDIDebugTarget)thread.getDebugTarget();
957         if (thread != fFilteredThreadsByTarget.put(target, thread) ) {
958             // recreate the breakpoint only if it is not the same thread
959

960             // Other breakpoints set attributes on the underlying
961
// marker and the marker changes are eventually
962
// propagated to the target. The target then asks the
963
// breakpoint to update its request. Since thread filters
964
// are transient properties, they are not set on
965
// the marker. Thus we must update the request
966
// here.
967
recreate(target);
968             fireChanged();
969         }
970     }
971     
972     /* (non-Javadoc)
973      * @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse.debug.core.DebugEvent[])
974      */

975     public void handleDebugEvents(DebugEvent[] events) {
976         for (int i = 0; i < events.length; i++) {
977             DebugEvent event = events[i];
978             if (event.getKind() == DebugEvent.TERMINATE) {
979                 Object JavaDoc source= event.getSource();
980                 if (!(source instanceof JDIThread)) {
981                     return;
982                 }
983                 try {
984                     cleanupForThreadTermination((JDIThread)source);
985                 } catch (VMDisconnectedException exception) {
986                     // Thread death often occurs at shutdown.
987
// A VMDisconnectedException trying to
988
// update the breakpoint request is
989
// acceptable.
990
}
991             }
992         }
993     }
994     
995     /**
996      * Removes cached information relevant to this thread which has
997      * terminated.
998      *
999      * Remove thread filters for terminated threads
1000     *
1001     * Subclasses may override but need to call super.
1002     */

1003    protected void cleanupForThreadTermination(JDIThread thread) {
1004        JDIDebugTarget target= (JDIDebugTarget)thread.getDebugTarget();
1005        try {
1006            if (thread == getThreadFilter(target)) {
1007                removeThreadFilter(target);
1008            }
1009        } catch (CoreException exception) {
1010            JDIDebugPlugin.log(exception);
1011        }
1012    }
1013    
1014    /**
1015     * EventRequest does not support thread filters, so they
1016     * can't be set generically here. However, each of the breakpoint
1017     * subclasses of EventRequest do support thread filters. So
1018     * subclasses can set thread filters on their specific
1019     * request type.
1020     */

1021    protected abstract void setRequestThreadFilter(EventRequest request, ThreadReference thread);
1022    
1023    /* (non-Javadoc)
1024     * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getThreadFilter(org.eclipse.jdt.debug.core.IJavaDebugTarget)
1025     */

1026    public IJavaThread getThreadFilter(IJavaDebugTarget target) {
1027        return (IJavaThread)fFilteredThreadsByTarget.get(target);
1028    }
1029    
1030    /* (non-Javadoc)
1031     * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getThreadFilters()
1032     */

1033    public IJavaThread[] getThreadFilters() {
1034        IJavaThread[] threads= null;
1035        Collection JavaDoc values= fFilteredThreadsByTarget.values();
1036        threads= new IJavaThread[values.size()];
1037        values.toArray(threads);
1038        return threads;
1039    }
1040
1041    /* (non-Javadoc)
1042     * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#removeThreadFilter(org.eclipse.jdt.debug.core.IJavaDebugTarget)
1043     */

1044    public void removeThreadFilter(IJavaDebugTarget javaTarget) throws CoreException {
1045        if (!(javaTarget instanceof JDIDebugTarget)) {
1046            return;
1047        }
1048        JDIDebugTarget target= (JDIDebugTarget)javaTarget;
1049        if (fFilteredThreadsByTarget.remove(target) != null) {
1050            recreate(target);
1051            fireChanged();
1052        }
1053    }
1054    
1055    /**
1056     * Returns whether this breakpoint should be installed in the given reference
1057     * type in the given target according to registered breakpoint listeners.
1058     *
1059     * @param target debug target
1060     * @param type reference type or <code>null</code> if this breakpoint is
1061     * not installed in a specific type
1062     */

1063    protected boolean queryInstallListeners(JDIDebugTarget target, ReferenceType type) {
1064        JDIDebugPlugin plugin = JDIDebugPlugin.getDefault();
1065        if (plugin != null) {
1066            IJavaType jt = null;
1067            if (type != null) {
1068                jt = JDIType.createType(target, type);
1069            }
1070            return plugin.fireInstalling(target, this, jt);
1071        }
1072        return false;
1073    }
1074    
1075    /* (non-Javadoc)
1076     * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#addInstanceFilter(org.eclipse.jdt.debug.core.IJavaObject)
1077     */

1078    public void addInstanceFilter(IJavaObject object) throws CoreException {
1079        if (fInstanceFilters == null) {
1080            fInstanceFilters= new ArrayList JavaDoc();
1081        }
1082        if (!fInstanceFilters.contains(object)) {
1083            fInstanceFilters.add(object);
1084            recreate((JDIDebugTarget)object.getDebugTarget());
1085            fireChanged();
1086        }
1087    }
1088    
1089    /**
1090     * Change notification when there are no marker changes. If the marker
1091     * does not exist, do not fire a change notification (the marker may not
1092     * exist if the associated project was closed).
1093     */

1094    protected void fireChanged() {
1095        DebugPlugin plugin = DebugPlugin.getDefault();
1096        if (plugin != null && markerExists()) {
1097            plugin.getBreakpointManager().fireBreakpointChanged(this);
1098        }
1099    }
1100
1101    /* (non-Javadoc)
1102     * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#getInstanceFilters()
1103     */

1104    public IJavaObject[] getInstanceFilters() {
1105        if (fInstanceFilters == null || fInstanceFilters.isEmpty()) {
1106            return fgEmptyInstanceFilters;
1107        }
1108        return (IJavaObject[])fInstanceFilters.toArray(new IJavaObject[fInstanceFilters.size()]);
1109    }
1110
1111    /* (non-Javadoc)
1112     * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#removeInstanceFilter(org.eclipse.jdt.debug.core.IJavaObject)
1113     */

1114    public void removeInstanceFilter(IJavaObject object) throws CoreException {
1115        if (fInstanceFilters == null) {
1116            return;
1117        }
1118        if (fInstanceFilters.remove(object)) {
1119            recreate((JDIDebugTarget)object.getDebugTarget());
1120            fireChanged();
1121        }
1122    }
1123    
1124    /**
1125     * An attribute of this breakpoint has changed - recreate event requests in
1126     * all targets.
1127     */

1128    protected void recreate() throws CoreException {
1129        DebugPlugin plugin = DebugPlugin.getDefault();
1130        if (plugin != null) {
1131            IDebugTarget[] targets = plugin.getLaunchManager().getDebugTargets();
1132            for (int i = 0; i < targets.length; i++) {
1133                IDebugTarget target = targets[i];
1134                MultiStatus multiStatus = new MultiStatus(JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.INTERNAL_ERROR, JDIDebugBreakpointMessages.JavaBreakpoint_Exception, null);
1135                IJavaDebugTarget jdiTarget = (IJavaDebugTarget) target.getAdapter(IJavaDebugTarget.class);
1136                if (jdiTarget instanceof JDIDebugTarget) {
1137                    try {
1138                        recreate((JDIDebugTarget) jdiTarget);
1139                    } catch (CoreException e) {
1140                        multiStatus.add(e.getStatus());
1141                    }
1142                }
1143                if (!multiStatus.isOK()) {
1144                    throw new CoreException(multiStatus);
1145                }
1146            }
1147        }
1148    }
1149    
1150    /**
1151     * Recreate this breakpoint in the given target, as long as the
1152     * target already contains this breakpoint.
1153     *
1154     * @param target the target in which to re-create the breakpoint
1155     */

1156    protected void recreate(JDIDebugTarget target) throws CoreException {
1157        if (target.isAvailable() && target.getBreakpoints().contains(this)) {
1158            removeRequests(target);
1159            createRequests(target);
1160        }
1161    }
1162
1163    /* (non-Javadoc)
1164     * @see org.eclipse.debug.core.model.Breakpoint#setEnabled(boolean)
1165     */

1166    public void setEnabled(boolean enabled) throws CoreException {
1167        super.setEnabled(enabled);
1168        recreate();
1169    }
1170
1171    /* (non-Javadoc)
1172     * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#supportsInstanceFilters()
1173     */

1174    public boolean supportsInstanceFilters() {
1175        return true;
1176    }
1177    /* (non-Javadoc)
1178     * @see org.eclipse.jdt.debug.core.IJavaBreakpoint#supportsThreadFilters()
1179     */

1180    public boolean supportsThreadFilters() {
1181        return true;
1182    }
1183}
1184
Popular Tags