KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > debug > core > JDIDebugPlugin


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;
12
13 import org.eclipse.core.resources.ISaveContext;
14 import org.eclipse.core.resources.ISaveParticipant;
15 import org.eclipse.core.resources.ResourcesPlugin;
16 import org.eclipse.core.runtime.CoreException;
17 import org.eclipse.core.runtime.ISafeRunnable;
18 import org.eclipse.core.runtime.IStatus;
19 import org.eclipse.core.runtime.ListenerList;
20 import org.eclipse.core.runtime.Plugin;
21 import org.eclipse.core.runtime.Preferences;
22 import org.eclipse.core.runtime.SafeRunner;
23 import org.eclipse.core.runtime.Status;
24 import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
25 import org.eclipse.debug.core.DebugException;
26 import org.eclipse.debug.core.DebugPlugin;
27 import org.eclipse.debug.core.ILaunchManager;
28 import org.eclipse.debug.core.model.IDebugTarget;
29 import org.eclipse.jdi.Bootstrap;
30 import org.eclipse.jdt.core.IJavaProject;
31 import org.eclipse.jdt.core.dom.Message;
32 import org.eclipse.jdt.debug.core.IJavaBreakpoint;
33 import org.eclipse.jdt.debug.core.IJavaBreakpointListener;
34 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
35 import org.eclipse.jdt.debug.core.IJavaHotCodeReplaceListener;
36 import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
37 import org.eclipse.jdt.debug.core.IJavaThread;
38 import org.eclipse.jdt.debug.core.IJavaType;
39 import org.eclipse.jdt.debug.core.JDIDebugModel;
40 import org.eclipse.jdt.debug.eval.IAstEvaluationEngine;
41 import org.eclipse.jdt.internal.debug.core.hcr.JavaHotCodeReplaceManager;
42 import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
43 import org.eclipse.jdt.internal.debug.eval.JavaEvaluationEngineManager;
44 import org.osgi.framework.BundleContext;
45
46 import com.sun.jdi.VirtualMachineManager;
47
48 /**
49  * The plugin class for the JDI Debug Model plug-in.
50  */

51 public class JDIDebugPlugin extends Plugin implements Preferences.IPropertyChangeListener {
52     
53     /**
54      * integer preference controlling if we should, by default, suspend the VM instead of the thread
55      *
56      * @since 3.2
57      * @TODO make API once the freeze is over (post 3.2)
58      */

59     public static final String JavaDoc PREF_DEFAULT_BREAKPOINT_SUSPEND_POLICY = JDIDebugPlugin.getUniqueIdentifier() + ".default_breakpoint_suspend_policy"; //$NON-NLS-1$
60

61     /**
62      * Boolean preference controlling if references should be displayed as variables in the variables and expressions view
63      *
64      * @since 3.3
65      */

66     public static final String JavaDoc PREF_SHOW_REFERENCES_IN_VAR_VIEW = JDIDebugPlugin.getUniqueIdentifier() + ".show_references_in_var_view"; //$NON-NLS-1$
67

68     /**
69      * Integer preference determining the maximum number of references that should be returned to the user when displaying reference information
70      *
71      * @since 3.3
72      */

73     public static final String JavaDoc PREF_ALL_REFERENCES_MAX_COUNT = JDIDebugPlugin.getUniqueIdentifier() + "._all_references_max_count"; //$NON-NLS-1$
74

75     /**
76      * Integer preference determining the maximum number of instances that should be returned to the user when displaying instance information
77      *
78      * @since 3.3
79      */

80     public static final String JavaDoc PREF_ALL_INSTANCES_MAX_COUNT = JDIDebugPlugin.getUniqueIdentifier() + ".all_instances_max_count"; //$NON-NLS-1$
81

82     /**
83      * Extension point for java logical structures.
84      *
85      * @since 3.1
86      */

87     public static final String JavaDoc EXTENSION_POINT_JAVA_LOGICAL_STRUCTURES= "javaLogicalStructures"; //$NON-NLS-1$
88

89     /**
90      * Status code indicating an unexpected internal error.
91      */

92     public static final int INTERNAL_ERROR = 120;
93     
94     private static JDIDebugPlugin fgPlugin;
95     
96     /**
97      * Breakpoint listener list.
98      */

99     private ListenerList fBreakpointListeners = null;
100     
101     /**
102      * Breakpoint notification types
103      */

104     private static final int ADDING = 1;
105     private static final int INSTALLED = 2;
106     private static final int REMOVED = 3;
107     private static final int COMPILATION_ERRORS = 4;
108     private static final int RUNTIME_EXCEPTION = 5;
109     
110     /**
111      * Whether this plug-in is in trace mode.
112      * Extra messages are logged in trace mode.
113      */

114     private boolean fTrace = false;
115     
116     /**
117      * Detected (speculated) JDI interface version
118      */

119     private static int[] fJDIVersion = null;
120     
121     private JavaEvaluationEngineManager fEvaluationEngineManager;
122
123     /**
124      * Status code used by the debug model to retrieve a thread to use
125      * for evaluations, via a status handler. A status handler is contributed by
126      * the Java debug UI. When not present, the debug model uses any suspended thread.
127      *
128      * @since 3.0
129      */

130     public static final int INFO_EVALUATION_THREAD = 110;
131     
132     /**
133      * Associated status to retrieve a thread.
134      */

135     public static final IStatus STATUS_GET_EVALUATION_THREAD = new Status(IStatus.INFO, getUniqueIdentifier(), INFO_EVALUATION_THREAD, "Provides thread context for an evaluation", null); //$NON-NLS-1$
136

137     /**
138      * Status code used by the debug model to retrieve a frame to use
139      * for evaluations, via a status handler. A status handler is contributed by
140      * the Java debug UI. When not present, the debug model uses any suspended thread.
141      *
142      * @since 3.0
143      */

144     public static final int INFO_EVALUATION_STACK_FRAME = 111;
145
146     /**
147      * Associated status to retrieve a stack frame.
148      */

149     public static IStatus STATUS_GET_EVALUATION_FRAME = new Status(IStatus.INFO, getUniqueIdentifier(), INFO_EVALUATION_STACK_FRAME, "Provides thread context for an evaluation", null); //$NON-NLS-1$
150

151     /**
152      * Returns whether the debug UI plug-in is in trace
153      * mode.
154      *
155      * @return whether the debug UI plug-in is in trace
156      * mode
157      */

158     public boolean isTraceMode() {
159         return fTrace;
160     }
161     
162     /**
163      * Logs the given message if in trace mode.
164      *
165      * @param String message to log
166      */

167     public static void logTraceMessage(String JavaDoc message) {
168         if (getDefault().isTraceMode()) {
169             IStatus s = new Status(IStatus.WARNING, JDIDebugPlugin.getUniqueIdentifier(), INTERNAL_ERROR, message, null);
170             getDefault().getLog().log(s);
171         }
172     }
173     
174     /**
175      * Return the singleton instance of the JDI Debug Model plug-in.
176      * @return the singleton instance of JDIDebugPlugin
177      */

178     public static JDIDebugPlugin getDefault() {
179         return fgPlugin;
180     }
181     
182     /**
183      * Convenience method which returns the unique identifier of this plugin.
184      */

185     public static String JavaDoc getUniqueIdentifier() {
186         // TODO review this change. Unclear how the plugin id could ever be different
187
// should likely just be a constant reference.
188
return "org.eclipse.jdt.debug"; //$NON-NLS-1$
189
}
190     
191     /**
192      * Returns the detected version of JDI support. This
193      * is intended to distinguish between clients that support
194      * JDI 1.4 methods like hot code replace.
195      *
196      * @return an array of version numbers, major followed by minor
197      * @since 2.1
198      */

199     public static int[] getJDIVersion() {
200         if (fJDIVersion == null) {
201             fJDIVersion = new int[2];
202             VirtualMachineManager mgr = Bootstrap.virtualMachineManager();
203             fJDIVersion[0] = mgr.majorInterfaceVersion();
204             fJDIVersion[1] = mgr.minorInterfaceVersion();
205         }
206         return fJDIVersion;
207     }
208     
209     /**
210      * Returns if the JDI version being used is greater than or equal to the
211      * given version (major, minor).
212      *
213      * @param version
214      * @return boolean
215      */

216     public static boolean isJdiVersionGreaterThanOrEqual(int[] version) {
217         int[] runningVersion = getJDIVersion();
218         return runningVersion[0] > version[0] || (runningVersion[0] == version[0] && runningVersion[1] >= version[1]);
219     }
220         
221     public JDIDebugPlugin() {
222         super();
223         fgPlugin = this;
224     }
225     
226     public void start(BundleContext context) throws Exception JavaDoc {
227         super.start(context);
228         ResourcesPlugin.getWorkspace().addSaveParticipant(this, new ISaveParticipant() {
229             public void doneSaving(ISaveContext context) {}
230             public void prepareToSave(ISaveContext context) throws CoreException {}
231             public void rollback(ISaveContext context) {}
232             public void saving(ISaveContext context) throws CoreException {
233                 savePluginPreferences();
234             }
235         });
236         JavaHotCodeReplaceManager.getDefault().startup();
237         fBreakpointListeners = new ListenerList();
238         fEvaluationEngineManager= new JavaEvaluationEngineManager();
239     }
240     
241     /**
242      * Adds the given hot code replace listener to the collection of listeners
243      * that will be notified by the hot code replace manager in this plugin.
244      */

245     public void addHotCodeReplaceListener(IJavaHotCodeReplaceListener listener) {
246         JavaHotCodeReplaceManager.getDefault().addHotCodeReplaceListener(listener);
247     }
248
249     /**
250      * Removes the given hot code replace listener from the collection of listeners
251      * that will be notified by the hot code replace manager in this plugin.
252      */

253     public void removeHotCodeReplaceListener(IJavaHotCodeReplaceListener listener) {
254         JavaHotCodeReplaceManager.getDefault().removeHotCodeReplaceListener(listener);
255     }
256
257     /**
258      * Shutdown the HCR manager and the Java debug targets.
259      *
260      * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)@see org.eclipse.core.runtime.Plugin#shutdown()
261      */

262     public void stop(BundleContext context) throws Exception JavaDoc {
263         try {
264             getPluginPreferences().removePropertyChangeListener(this); //added in the preference initializer
265
JavaHotCodeReplaceManager.getDefault().shutdown();
266             fEvaluationEngineManager.dispose();
267             ILaunchManager launchManager= DebugPlugin.getDefault().getLaunchManager();
268             IDebugTarget[] targets= launchManager.getDebugTargets();
269             for (int i= 0 ; i < targets.length; i++) {
270                 IDebugTarget target= targets[i];
271                 if (target instanceof JDIDebugTarget) {
272                     ((JDIDebugTarget)target).shutdown();
273                 }
274             }
275             fBreakpointListeners = null;
276             ResourcesPlugin.getWorkspace().removeSaveParticipant(this);
277         } finally {
278             fgPlugin = null;
279             super.stop(context);
280         }
281     }
282     
283     /**
284      * Logs the specified throwable with this plug-in's log.
285      *
286      * @param t throwable to log
287      */

288     public static void log(Throwable JavaDoc t) {
289         Throwable JavaDoc top= t;
290         if (t instanceof DebugException) {
291             DebugException de = (DebugException)t;
292             IStatus status = de.getStatus();
293             if (status.getException() != null) {
294                 top = status.getException();
295             }
296         }
297         // this message is intentionally not internationalized, as an exception may
298
// be due to the resource bundle itself
299
log(new Status(IStatus.ERROR, getUniqueIdentifier(), INTERNAL_ERROR, "Internal error logged from JDI Debug: ", top)); //$NON-NLS-1$
300
}
301     
302     /**
303      * Logs the specified status with this plug-in's log.
304      *
305      * @param status status to log
306      */

307     public static void log(IStatus status) {
308         getDefault().getLog().log(status);
309     }
310         
311     /**
312      * @see IJavaBreakpointListener#breakpointHasRuntimeException(IJavaLineBreakpoint, DebugException)
313      */

314     public void fireBreakpointHasCompilationErrors(IJavaLineBreakpoint breakpoint, Message[] errors) {
315         getBreakpointNotifier().notify(null, breakpoint, COMPILATION_ERRORS, errors, null);
316     }
317     
318     /**
319      * @see IJavaBreakpointListener#breakpointHasCompilationErrors(IJavaLineBreakpoint, Message[])
320      */

321     public void fireBreakpointHasRuntimeException(IJavaLineBreakpoint breakpoint, DebugException exception) {
322         getBreakpointNotifier().notify(null, breakpoint, RUNTIME_EXCEPTION, null, exception);
323     }
324     
325     /**
326      * Adds the given breakpoint listener to the JDI debug model.
327      *
328      * @param listener breakpoint listener
329      */

330     public void addJavaBreakpointListener(IJavaBreakpointListener listener) {
331         fBreakpointListeners.add(listener);
332     }
333
334     /**
335      * Removes the given breakpoint listener from the JDI debug model.
336      *
337      * @param listener breakpoint listener
338      */

339     public void removeJavaBreakpointListener(IJavaBreakpointListener listener) {
340         fBreakpointListeners.remove(listener);
341     }
342     
343     /**
344      * Notifies listeners that the given breakpoint is about to be
345      * added.
346      *
347      * @param target Java debug target
348      * @param breakpoint Java breakpoint
349      */

350     public void fireBreakpointAdding(IJavaDebugTarget target, IJavaBreakpoint breakpoint) {
351         getBreakpointNotifier().notify(target, breakpoint, ADDING, null, null);
352     }
353     
354     /**
355      * Notifies listeners that the given breakpoint has been installed.
356      *
357      * @param target Java debug target
358      * @param breakpoint Java breakpoint
359      */

360     public void fireBreakpointInstalled(IJavaDebugTarget target, IJavaBreakpoint breakpoint) {
361         getBreakpointNotifier().notify(target, breakpoint, INSTALLED, null, null);
362     }
363     
364     /**
365      * Notifies listeners that the given breakpoint has been removed.
366      *
367      * @param target Java debug target
368      * @param breakpoint Java breakpoint
369      */

370     public void fireBreakpointRemoved(IJavaDebugTarget target, IJavaBreakpoint breakpoint) {
371         getBreakpointNotifier().notify(target, breakpoint, REMOVED, null, null);
372     }
373     
374     /**
375      * Notifies listeners that the given breakpoint has been hit.
376      * Returns whether the thread should suspend.
377      *
378      * @param target Java debug target
379      * @param breakpoint Java breakpoint
380      */

381     public boolean fireBreakpointHit(IJavaThread thread, IJavaBreakpoint breakpoint) {
382         return getHitNotifier().notifyHit(thread, breakpoint);
383     }
384     
385     /**
386      * Notifies listeners that the given breakpoint is about to be installed
387      * in the given type. Returns whether the breakpoint should be
388      * installed.
389      *
390      * @param target Java debug target
391      * @param breakpoint Java breakpoint
392      * @param type the type the breakpoint is about to be installed in
393      * @return whether the breakpoint should be installed
394      */

395     public boolean fireInstalling(IJavaDebugTarget target, IJavaBreakpoint breakpoint, IJavaType type) {
396         return getInstallingNotifier().notifyInstalling(target, breakpoint, type);
397     }
398     
399     /**
400      * Save preferences and update all debug targets when the timeout changes.
401      *
402      * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
403      */

404     public void propertyChange(PropertyChangeEvent event) {
405         if (event.getProperty().equals(JDIDebugModel.PREF_REQUEST_TIMEOUT)) {
406             int value = getPluginPreferences().getInt(JDIDebugModel.PREF_REQUEST_TIMEOUT);
407             IDebugTarget[] targets = DebugPlugin.getDefault().getLaunchManager().getDebugTargets();
408             for (int i = 0; i < targets.length; i++) {
409                 if (targets[i] instanceof IJavaDebugTarget) {
410                     ((IJavaDebugTarget)targets[i]).setRequestTimeout(value);
411                 }
412             }
413         }
414     }
415     
416     private BreakpointNotifier getBreakpointNotifier() {
417         return new BreakpointNotifier();
418     }
419
420     class BreakpointNotifier implements ISafeRunnable {
421         
422         private IJavaDebugTarget fTarget;
423         private IJavaBreakpoint fBreakpoint;
424         private int fKind;
425         private Message[] fErrors;
426         private DebugException fException;
427         private IJavaBreakpointListener fListener;
428         
429         /**
430          * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
431          */

432         public void handleException(Throwable JavaDoc exception) {
433         }
434
435         /**
436          * @see org.eclipse.core.runtime.ISafeRunnable#run()
437          */

438         public void run() throws Exception JavaDoc {
439             switch (fKind) {
440                 case ADDING:
441                     fListener.addingBreakpoint(fTarget, fBreakpoint);
442                     break;
443                 case INSTALLED:
444                     fListener.breakpointInstalled(fTarget, fBreakpoint);
445                     break;
446                 case REMOVED:
447                     fListener.breakpointRemoved(fTarget, fBreakpoint);
448                     break;
449                 case COMPILATION_ERRORS:
450                     fListener.breakpointHasCompilationErrors((IJavaLineBreakpoint)fBreakpoint, fErrors);
451                     break;
452                 case RUNTIME_EXCEPTION:
453                     fListener.breakpointHasRuntimeException((IJavaLineBreakpoint)fBreakpoint, fException);
454                     break;
455             }
456         }
457
458         /**
459          * Notifies listeners of the given addition, install, or
460          * remove.
461          *
462          * @param target debug target
463          * @param breakpoint the associated breakpoint
464          * @param kind one of ADDED, REMOVED, INSTALLED
465          * @param errors associated errors, or <code>null</code> if none
466          * @param exception associated exception, or <code>null</code> if none
467          */

468         public void notify(IJavaDebugTarget target, IJavaBreakpoint breakpoint, int kind, Message[] errors, DebugException exception) {
469             fTarget = target;
470             fBreakpoint = breakpoint;
471             fKind = kind;
472             fErrors = errors;
473             fException = exception;
474             Object JavaDoc[] listeners = fBreakpointListeners.getListeners();
475             for (int i = 0; i < listeners.length; i++) {
476                 fListener = (IJavaBreakpointListener)listeners[i];
477                 SafeRunner.run(this);
478             }
479             fTarget = null;
480             fBreakpoint = null;
481             fErrors = null;
482             fException = null;
483             fListener = null;
484         }
485     }
486     
487     private InstallingNotifier getInstallingNotifier() {
488         return new InstallingNotifier();
489     }
490         
491     class InstallingNotifier implements ISafeRunnable {
492         
493         private IJavaDebugTarget fTarget;
494         private IJavaBreakpoint fBreakpoint;
495         private IJavaType fType;
496         private IJavaBreakpointListener fListener;
497         private int fInstall;
498         
499         /**
500          * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
501          */

502         public void handleException(Throwable JavaDoc exception) {
503         }
504
505         /**
506          * @see org.eclipse.core.runtime.ISafeRunnable#run()
507          */

508         public void run() throws Exception JavaDoc {
509             fInstall = fInstall | fListener.installingBreakpoint(fTarget, fBreakpoint, fType);
510         }
511         
512         private void dispose() {
513             fTarget = null;
514             fBreakpoint = null;
515             fType = null;
516             fListener = null;
517         }
518
519         /**
520          * Notifies listeners that the given breakpoint is about to be installed
521          * in the given type. Returns whether the breakpoint should be
522          * installed.
523          *
524          * @param target Java debug target
525          * @param breakpoint Java breakpoint
526          * @param type the type the breakpoint is about to be installed in
527          * @return whether the breakpoint should be installed
528          */

529         public boolean notifyInstalling(IJavaDebugTarget target, IJavaBreakpoint breakpoint, IJavaType type) {
530             fTarget = target;
531             fBreakpoint = breakpoint;
532             fType = type;
533             fInstall = IJavaBreakpointListener.DONT_CARE;
534             Object JavaDoc[] listeners = fBreakpointListeners.getListeners();
535             for (int i = 0; i < listeners.length; i++) {
536                 fListener = (IJavaBreakpointListener)listeners[i];
537                 SafeRunner.run(this);
538             }
539             dispose();
540             // install if any listener voted to install, or if no one voted to not install
541
return (fInstall & IJavaBreakpointListener.INSTALL) > 0 ||
542                 (fInstall & IJavaBreakpointListener.DONT_INSTALL) == 0;
543         }
544     }
545     
546     private HitNotifier getHitNotifier() {
547         return new HitNotifier();
548     }
549         
550     class HitNotifier implements ISafeRunnable {
551         
552         private IJavaThread fThread;
553         private IJavaBreakpoint fBreakpoint;
554         private IJavaBreakpointListener fListener;
555         private int fSuspend;
556         
557         /**
558          * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable)
559          */

560         public void handleException(Throwable JavaDoc exception) {
561         }
562
563         /**
564          * @see org.eclipse.core.runtime.ISafeRunnable#run()
565          */

566         public void run() throws Exception JavaDoc {
567             fSuspend = fSuspend | fListener.breakpointHit(fThread, fBreakpoint);
568         }
569
570         /**
571          * Notifies listeners that the given breakpoint has been hit.
572          * Returns whether the thread should suspend.
573          *
574          * @param thread thread in which the breakpoint was hit
575          * @param breakpoint Java breakpoint
576          * @return whether the thread should suspend
577          */

578         public boolean notifyHit(IJavaThread thread, IJavaBreakpoint breakpoint) {
579             fThread = thread;
580             fBreakpoint = breakpoint;
581             Object JavaDoc[] listeners = fBreakpointListeners.getListeners();
582             fSuspend = IJavaBreakpointListener.DONT_CARE;
583             for (int i = 0; i < listeners.length; i++) {
584                 fListener = (IJavaBreakpointListener)listeners[i];
585                 SafeRunner.run(this);
586             }
587             fThread = null;
588             fBreakpoint = null;
589             fListener = null;
590             // Suspend if any listener voted to suspend or no one voted "don't suspend"
591
return (fSuspend & IJavaBreakpointListener.SUSPEND) > 0 ||
592                     (fSuspend & IJavaBreakpointListener.DONT_SUSPEND) == 0;
593         }
594     }
595     
596     /**
597      * Returns an evaluation engine for the given project in the given debug target.
598      *
599      * @see JavaEvaluationEngineManager#getEvaluationEngine(IJavaProject, IJavaDebugTarget)
600      *
601      * @param project java project
602      * @param target the debug target
603      * @return evaluation engine
604      */

605     public IAstEvaluationEngine getEvaluationEngine(IJavaProject project, IJavaDebugTarget target) {
606         return fEvaluationEngineManager.getEvaluationEngine(project, target);
607     }
608 }
609
Popular Tags