blob: a40a6b9108f3718e8dd6045c5ead167a65208594 [file] [log] [blame]
package org.eclipse.jdt.internal.debug.core;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPluginDescriptor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.internal.core.ListenerList;
import org.eclipse.jdt.core.dom.Message;
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
import org.eclipse.jdt.debug.core.IJavaBreakpointListener;
import org.eclipse.jdt.debug.core.IJavaDebugTarget;
import org.eclipse.jdt.debug.core.IJavaHotCodeReplaceListener;
import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.core.IJavaType;
import org.eclipse.jdt.debug.core.JDIDebugModel;
import org.eclipse.jdt.internal.debug.core.hcr.JavaHotCodeReplaceManager;
import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
/**
* The plugin class for the JDI Debug Model plug-in.
*/
public class JDIDebugPlugin extends Plugin implements Preferences.IPropertyChangeListener {
/**
* Status code indicating an unexpected internal error.
*/
public static final int INTERNAL_ERROR = 120;
private static JDIDebugPlugin fgPlugin;
/**
* Breakpoint listener list.
*/
private ListenerList fBreakpointListeners = null;
/**
* Breakpoint notification types
*/
private static final int ADDING = 1;
private static final int INSTALLED = 2;
private static final int REMOVED = 3;
/**
* Whether this plug-in is in trace mode.
* Extra messages are logged in trace mode.
*/
private boolean fTrace = false;
/**
* Detected (speculated) JDI interface version
*/
private static float fJDIVersion;
/**
* Returns whether the debug UI plug-in is in trace
* mode.
*
* @return whether the debug UI plug-in is in trace
* mode
*/
public boolean isTraceMode() {
return fTrace;
}
/**
* Logs the given message if in trace mode.
*
* @param String message to log
*/
public static void logTraceMessage(String message) {
if (getDefault().isTraceMode()) {
IStatus s = new Status(IStatus.WARNING, JDIDebugPlugin.getUniqueIdentifier(), INTERNAL_ERROR, message, null);
getDefault().getLog().log(s);
}
}
/**
* Return the singleton instance of the JDI Debug Model plug-in.
* @return the singleton instance of JDIDebugPlugin
*/
public static JDIDebugPlugin getDefault() {
return fgPlugin;
}
/**
* Convenience method which returns the unique identifier of this plugin.
*/
public static String getUniqueIdentifier() {
if (getDefault() == null) {
// If the default instance is not yet initialized,
// return a static identifier. This identifier must
// match the plugin id defined in plugin.xml
return "org.eclipse.jdt.debug"; //$NON-NLS-1$
}
return getDefault().getDescriptor().getUniqueIdentifier();
}
/**
* Returns the detected version of JDI support. This
* is intended to distinguish between clients that support
* JDI 1.4 methods like hot code replace.
*
* @since 2.1
*/
public static float getJDIVersion() {
return fJDIVersion;
}
public JDIDebugPlugin(IPluginDescriptor descriptor) {
super(descriptor);
fgPlugin = this;
}
/**
* @see Plugin#startup()
*/
public void startup() throws CoreException {
fJDIVersion= (float)1.4;
try {
// JDI clients before version 1.4 do not support
// hot code replace.
Class clazz = Class.forName("com.sun.jdi.VirtualMachine"); //$NON-NLS-1$
clazz.getMethod("canRedefineClasses", new Class[0]); //$NON-NLS-1$
} catch (NoSuchMethodException e) {
fJDIVersion= (float)1.3;
} catch (ClassNotFoundException e) {
}
JavaHotCodeReplaceManager.getDefault().startup();
fBreakpointListeners = new ListenerList(5);
getPluginPreferences().setDefault(JDIDebugModel.PREF_REQUEST_TIMEOUT, JDIDebugModel.DEF_REQUEST_TIMEOUT);
getPluginPreferences().setDefault(JDIDebugModel.PREF_HCR_WITH_COMPILATION_ERRORS, true);
getPluginPreferences().addPropertyChangeListener(this);
}
/**
* Adds the given hot code replace listener to the collection of listeners
* that will be notified by the hot code replace manager in this plugin.
*/
public void addHotCodeReplaceListener(IJavaHotCodeReplaceListener listener) {
JavaHotCodeReplaceManager.getDefault().addHotCodeReplaceListener(listener);
}
/**
* Removes the given hot code replace listener from the collection of listeners
* that will be notified by the hot code replace manager in this plugin.
*/
public void removeHotCodeReplaceListener(IJavaHotCodeReplaceListener listener) {
JavaHotCodeReplaceManager.getDefault().removeHotCodeReplaceListener(listener);
}
/**
* Shutdown the HCR mgr and the Java debug targets.
*
* @see Plugin#shutdown()
*/
public void shutdown() throws CoreException {
getPluginPreferences().removePropertyChangeListener(this);
savePluginPreferences();
JavaHotCodeReplaceManager.getDefault().shutdown();
ILaunchManager launchManager= DebugPlugin.getDefault().getLaunchManager();
IDebugTarget[] targets= launchManager.getDebugTargets();
for (int i= 0 ; i < targets.length; i++) {
IDebugTarget target= targets[i];
if (target instanceof JDIDebugTarget) {
((JDIDebugTarget)target).shutdown();
}
}
fBreakpointListeners = null;
fgPlugin = null;
super.shutdown();
}
/**
* Logs the specified throwable with this plug-in's log.
*
* @param t throwable to log
*/
public static void log(Throwable t) {
Throwable top= t;
if (t instanceof DebugException) {
DebugException de = (DebugException)t;
IStatus status = de.getStatus();
if (status.getException() != null) {
top = status.getException();
}
}
// this message is intentionally not internationalized, as an exception may
// be due to the resource bundle itself
log(new Status(IStatus.ERROR, getUniqueIdentifier(), INTERNAL_ERROR, "Internal error logged from JDI Debug: ", top)); //$NON-NLS-1$
}
/**
* Logs the given message if in debug mode.
*
* @param String message to log
*/
public static void logDebugMessage(String message) {
if (getDefault().isDebugging()) {
// this message is intentionally not internationalized, as an exception may
// be due to the resource bundle itself
log(new Status(IStatus.ERROR, getUniqueIdentifier(), INTERNAL_ERROR, "Internal message logged from JDI Debug: " + message, null)); //$NON-NLS-1$
}
}
/**
* Logs the specified status with this plug-in's log.
*
* @param status status to log
*/
public static void log(IStatus status) {
getDefault().getLog().log(status);
}
/**
* @see IJavaBreakpointListener#breakpointHasRuntimeException(IJavaLineBreakpoint, DebugException)
*/
public void fireBreakpointHasCompilationErrors(IJavaLineBreakpoint breakpoint, Message[] errors) {
Object listeners[]= fBreakpointListeners.getListeners();
for (int i = 0; i < listeners.length; i++) {
((IJavaBreakpointListener)listeners[i]).breakpointHasCompilationErrors(breakpoint, errors);
}
}
/**
* @see IJavaBreakpointListener#breakpointHasCompilationErrors(IJavaLineBreakpoint, Message[])
*/
public void fireBreakpointHasRuntimeException(IJavaLineBreakpoint breakpoint, DebugException exception) {
Object listeners[]= fBreakpointListeners.getListeners();
for (int i = 0; i < listeners.length; i++) {
((IJavaBreakpointListener)listeners[i]).breakpointHasRuntimeException(breakpoint, exception);
}
}
/**
* Adds the given breakpoint listener to the JDI debug model.
*
* @param listener breakpoint listener
*/
public void addJavaBreakpointListener(IJavaBreakpointListener listener) {
fBreakpointListeners.add(listener);
}
/**
* Removes the given breakpoint listener from the JDI debug model.
*
* @param listener breakpoint listener
*/
public void removeJavaBreakpointListener(IJavaBreakpointListener listener) {
fBreakpointListeners.remove(listener);
}
/**
* Notifies listeners that the given breakpoint is about to be
* added.
*
* @param target Java debug target
* @param breakpoint Java breakpoint
*/
public void fireBreakpointAdding(IJavaDebugTarget target, IJavaBreakpoint breakpoint) {
notify(target, breakpoint, ADDING);
}
/**
* Notifies listeners that the given breakpoint has been installed.
*
* @param target Java debug target
* @param breakpoint Java breakpoint
*/
public void fireBreakpointInstalled(IJavaDebugTarget target, IJavaBreakpoint breakpoint) {
notify(target, breakpoint, INSTALLED);
}
/**
* Notifies listeners that the given breakpoint has been removed.
*
* @param target Java debug target
* @param breakpoint Java breakpoint
*/
public void fireBreakpointRemoved(IJavaDebugTarget target, IJavaBreakpoint breakpoint) {
notify(target, breakpoint, REMOVED);
}
/**
* Notifies listeners of the given addition, install, or
* remove.
*
* @param target debug target
* @param breakpoint the associated breakpoint
* @param kind one of ADDED, REMOVED, INSTALLED
*/
protected void notify(IJavaDebugTarget target, IJavaBreakpoint breakpoint, int kind) {
Object[] listeners = fBreakpointListeners.getListeners();
for (int i = 0; i < listeners.length; i++) {
IJavaBreakpointListener jbpl = (IJavaBreakpointListener)listeners[i];
switch (kind) {
case ADDING:
jbpl.addingBreakpoint(target, breakpoint);
break;
case INSTALLED:
jbpl.breakpointInstalled(target, breakpoint);
break;
case REMOVED:
jbpl.breakpointRemoved(target, breakpoint);
break;
}
}
}
/**
* Notifies listeners that the given breakpoint has been hit.
* Returns whether the thread should suspend.
*
* @param target Java debug target
* @param breakpoint Java breakpoint
*/
public boolean fireBreakpointHit(IJavaThread thread, IJavaBreakpoint breakpoint) {
Object[] listeners = fBreakpointListeners.getListeners();
boolean suspend = listeners.length == 0;
for (int i = 0; i < listeners.length; i++) {
IJavaBreakpointListener jbpl = (IJavaBreakpointListener)listeners[i];
suspend = suspend | jbpl.breakpointHit(thread, breakpoint);
}
return suspend;
}
/**
* Notifies listeners that the given breakpoint is about to be installed
* in the given type. Returns whether the breakpoint should be
* installed.
*
* @param target Java debug target
* @param breakpoint Java breakpoint
* @param type the type the breakpoint is about to be installed in
* @return whether the breakpoint should be installed
*/
public boolean fireInstalling(IJavaDebugTarget target, IJavaBreakpoint breakpoint, IJavaType type) {
Object[] listeners = fBreakpointListeners.getListeners();
for (int i = 0; i < listeners.length; i++) {
IJavaBreakpointListener jbpl = (IJavaBreakpointListener)listeners[i];
if (!jbpl.installingBreakpoint(target, breakpoint, type)) {
return false;
}
}
return true;
}
/**
* Save preferences and update all debug targets when the timeout changes.
*
* @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty().equals(JDIDebugModel.PREF_REQUEST_TIMEOUT)) {
savePluginPreferences();
int value = getPluginPreferences().getInt(JDIDebugModel.PREF_REQUEST_TIMEOUT);
IDebugTarget[] targets = DebugPlugin.getDefault().getLaunchManager().getDebugTargets();
for (int i = 0; i < targets.length; i++) {
if (targets[i] instanceof IJavaDebugTarget) {
((IJavaDebugTarget)targets[i]).setRequestTimeout(value);
}
}
}
}
}