blob: 478f25153cb1101b0df8753744cf3b3499b0c859 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.debug.core.model;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IDebugElement;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IDisconnect;
import org.eclipse.debug.core.model.IStepFilters;
import org.eclipse.jdi.TimeoutException;
import org.eclipse.jdi.hcr.OperationRefusedException;
import org.eclipse.jdt.debug.core.JDIDebugModel;
import org.eclipse.jdt.internal.debug.core.EventDispatcher;
import org.eclipse.jdt.internal.debug.core.IJDIEventListener;
import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
import com.sun.jdi.ClassNotPreparedException;
import com.sun.jdi.InconsistentDebugInfoException;
import com.sun.jdi.InternalException;
import com.sun.jdi.InvalidCodeIndexException;
import com.sun.jdi.InvalidLineNumberException;
import com.sun.jdi.InvalidStackFrameException;
import com.sun.jdi.NativeMethodException;
import com.sun.jdi.ObjectCollectedException;
import com.sun.jdi.VMDisconnectedException;
import com.sun.jdi.VMMismatchException;
import com.sun.jdi.VMOutOfMemoryException;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.request.DuplicateRequestException;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
import com.sun.jdi.request.InvalidRequestStateException;
public abstract class JDIDebugElement extends PlatformObject implements IDebugElement, IDisconnect {
/**
* Collection of possible JDI exceptions (runtime)
*/
private static List fgJDIExceptions;
/**
* Debug target associated with this element
*/
private JDIDebugTarget fDebugTarget;
static {
fgJDIExceptions = new ArrayList(15);
// Runtime/unchecked exceptions
fgJDIExceptions.add(ClassNotPreparedException.class);
fgJDIExceptions.add(InconsistentDebugInfoException.class);
fgJDIExceptions.add(InternalException.class);
fgJDIExceptions.add(InvalidCodeIndexException.class);
fgJDIExceptions.add(InvalidLineNumberException.class);
fgJDIExceptions.add(InvalidStackFrameException.class);
fgJDIExceptions.add(NativeMethodException.class);
fgJDIExceptions.add(ObjectCollectedException.class);
fgJDIExceptions.add(TimeoutException.class);
fgJDIExceptions.add(VMDisconnectedException.class);
fgJDIExceptions.add(VMMismatchException.class);
fgJDIExceptions.add(VMOutOfMemoryException.class);
fgJDIExceptions.add(DuplicateRequestException.class);
fgJDIExceptions.add(InvalidRequestStateException.class);
fgJDIExceptions.add(OperationRefusedException.class);
}
/**
* Creates a JDI debug element associated with the
* specified debug target.
*
* @param target The associated debug target
*/
public JDIDebugElement(JDIDebugTarget target) {
setDebugTarget(target);
}
/**
* Convenience method to log errors
*/
protected void logError(Exception e) {
if (!((JDIDebugTarget)getDebugTarget()).isAvailable()) {
// Don't log VMDisconnectedExceptions that occur
// when the VM is unavailable.
if (e instanceof VMDisconnectedException ||
(e instanceof CoreException && ((CoreException)e).getStatus().getException() instanceof VMDisconnectedException)) {
return;
}
}
JDIDebugPlugin.log(e);
}
/**
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if (adapter == IDebugElement.class) {
return this;
}
if (adapter == IStepFilters.class) {
return getDebugTarget();
}
if (adapter == IDebugTarget.class) {
return getDebugTarget();
}
return super.getAdapter(adapter);
}
/**
* @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier()
*/
public String getModelIdentifier() {
return JDIDebugModel.getPluginIdentifier();
}
/**
* Fires a debug event marking the creation of this element.
*/
protected void fireCreationEvent() {
fireEvent(new DebugEvent(this, DebugEvent.CREATE));
}
/**
* Fires a debug event
*
* @param event The debug event to be fired to the listeners
* @see org.eclipse.debug.core.DebugEvent
*/
protected void fireEvent(DebugEvent event) {
DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] {event});
}
/**
* Queues a debug event with the event dispatcher to be fired
* as an event set when all event processing is complete.
*
* @param event the event to queue
*/
public void queueEvent(DebugEvent event) {
EventDispatcher dispatcher = ((JDIDebugTarget)getDebugTarget()).getEventDispatcher();
if (dispatcher != null) {
dispatcher.queue(event);
}
}
/**
* Fires a debug event marking the RESUME of this element with
* the associated detail.
*
* @param detail The int detail of the event
* @see org.eclipse.debug.core.DebugEvent
*/
public void fireResumeEvent(int detail) {
fireEvent(new DebugEvent(this, DebugEvent.RESUME, detail));
}
/**
* Fires a debug event marking the SUSPEND of this element with
* the associated detail.
*
* @param detail The int detail of the event
* @see org.eclipse.debug.core.DebugEvent
*/
public void fireSuspendEvent(int detail) {
getJavaDebugTarget().incrementSuspendCount();
fireEvent(new DebugEvent(this, DebugEvent.SUSPEND, detail));
}
/**
* Queues a debug event marking the SUSPEND of this element with
* the associated detail.
*
* @param detail The int detail of the event
* @see org.eclipse.debug.core.DebugEvent
*/
public void queueSuspendEvent(int detail) {
getJavaDebugTarget().incrementSuspendCount();
queueEvent(new DebugEvent(this, DebugEvent.SUSPEND, detail));
}
/**
* Fires a debug event marking the termination of this element.
*/
protected void fireTerminateEvent() {
fireEvent(new DebugEvent(this, DebugEvent.TERMINATE));
}
/**
* Fires a debug event marking the CHANGE of this element
* with the specifed detail code.
*
* @param detail one of <code>STATE</code> or <code>CONTENT</code>
*/
public void fireChangeEvent(int detail) {
fireEvent(new DebugEvent(this, DebugEvent.CHANGE, detail));
}
/**
* Throws a new debug exception with a status code of <code>REQUEST_FAILED</code>.
*
* @param message Failure message
* @param e Exception that has occurred (<code>can be null</code>)
* @throws DebugException The exception with a status code of <code>REQUEST_FAILED</code>
*/
public void requestFailed(String message, Exception e) throws DebugException {
requestFailed(message, e, DebugException.REQUEST_FAILED);
}
/**
* Throws a new debug exception with a status code of <code>TARGET_REQUEST_FAILED</code>
* with the given underlying exception. If the underlying exception is not a JDI
* exception, the original exception is thrown.
*
* @param message Failure message
* @param e underlying exception that has occurred
* @throws DebugException The exception with a status code of <code>TARGET_REQUEST_FAILED</code>
*/
public void targetRequestFailed(String message, RuntimeException e) throws DebugException {
if (e == null || fgJDIExceptions.contains(e.getClass())) {
requestFailed(message, e, DebugException.TARGET_REQUEST_FAILED);
} else {
throw e;
}
}
/**
* Throws a new debug exception with the given status code.
*
* @param message Failure message
* @param e Exception that has occurred (<code>can be null</code>)
* @param code status code
* @throws DebugException a new exception with given status code
*/
public void requestFailed(String message, Throwable e, int code) throws DebugException {
throwDebugException(message, code, e);
}
/**
* Throws a new debug exception with a status code of <code>TARGET_REQUEST_FAILED</code>.
*
* @param message Failure message
* @param e Throwable that has occurred
* @throws DebugException The exception with a status code of <code>TARGET_REQUEST_FAILED</code>
*/
public void targetRequestFailed(String message, Throwable e) throws DebugException {
throwDebugException(message, DebugException.TARGET_REQUEST_FAILED, e);
}
/**
* Throws a new debug exception with a status code of <code>TARGET_REQUEST_FAILED</code>
* with the given underlying exception. The underlying exception is an exception thrown
* by a JDI request.
*
* @param message Failure message
* @param e throwable exception that has occurred
* @throws DebugException the exception with a status code of <code>TARGET_REQUEST_FAILED</code>
*/
public void jdiRequestFailed(String message, Throwable e) throws DebugException {
throwDebugException(message, DebugException.TARGET_REQUEST_FAILED, e);
}
/**
* Throws a new debug exception with a status code of <code>NOT_SUPPORTED</code>.
*
* @param message Failure message
* @throws DebugException The exception with a status code of <code>NOT_SUPPORTED</code>.
*/
public void notSupported(String message) throws DebugException {
throwDebugException(message, DebugException.NOT_SUPPORTED, null);
}
/**
* Throws a debug exception with the given message, error code, and underlying
* exception.
*/
protected void throwDebugException(String message, int code, Throwable exception) throws DebugException {
throw new DebugException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
code, message, exception));
}
/**
* Logs the given exception if it is a JDI exception, otherwise throws the
* runtime exception.
*
* @param e The internal runtime exception
*/
public void internalError(RuntimeException e) {
if (fgJDIExceptions.contains(e.getClass())) {
logError(e);
} else {
throw e;
}
}
/**
* Logs a debug exception with the given message,
* with a status code of <code>INTERNAL_ERROR</code>.
*
* @param message The internal error message
*/
protected void internalError(String message) {
logError(new DebugException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
DebugException.INTERNAL_ERROR, message, null)));
}
/**
* Returns the common "<unknown>" message.
*
* @return the unknown String
*/
protected String getUnknownMessage() {
return JDIDebugModelMessages.getString("JDIDebugElement.unknown"); //$NON-NLS-1$
}
/**
* @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget()
*/
public IDebugTarget getDebugTarget() {
return fDebugTarget;
}
/**
* Returns this elements debug target as its implementation
* class.
*
* @return Java debug target
*/
protected JDIDebugTarget getJavaDebugTarget() {
return fDebugTarget;
}
/**
* Returns the target VM associated with this element, or <code>null</code>
* if none.
*
* @return target VM or <code>null</code> if none
*/
protected VirtualMachine getVM() {
return ((JDIDebugTarget)getDebugTarget()).getVM();
}
/**
* Returns the underlying VM's event request manager, or <code>null</code>
* if none (disconnected/terminated)
*
* @return event request manager or <code>null</code>
*/
public EventRequestManager getEventRequestManager() {
VirtualMachine vm = getVM();
if (vm == null) {
return null;
} else {
return vm.eventRequestManager();
}
}
/**
* Adds the given listener to this target's event dispatcher's
* table of listeners for the specified event request. The listener
* will be notified each time the event occurs.
*
* @param listener the listener to register
* @param request the event request
*/
public void addJDIEventListener(IJDIEventListener listener, EventRequest request) {
EventDispatcher dispatcher = ((JDIDebugTarget)getDebugTarget()).getEventDispatcher();
if (dispatcher != null) {
dispatcher.addJDIEventListener(listener, request);
}
}
/**
* Removes the given listener from this target's event dispatcher's
* table of listeners for the specifed event request. The listener
* will no longer be notified when the event occurs. Listeners
* are responsible for deleting the event request if desired.
*
* @param listener the listener to remove
* @param request the event request
*/
public void removeJDIEventListener(IJDIEventListener listener, EventRequest request) {
EventDispatcher dispatcher = ((JDIDebugTarget)getDebugTarget()).getEventDispatcher();
if (dispatcher != null) {
dispatcher.removeJDIEventListener(listener, request);
}
}
/**
* @see IDebugElement#getLaunch()
*/
public ILaunch getLaunch() {
return getDebugTarget().getLaunch();
}
protected void setDebugTarget(JDIDebugTarget debugTarget) {
fDebugTarget = debugTarget;
}
/**
* The VM has disconnected. Notify the target.
*/
protected void disconnected() {
if (fDebugTarget != null) {
fDebugTarget.disconnected();
}
}
/**
* @see IJavaDebugTarget#setRequestTimeout(int)
*/
public void setRequestTimeout(int timeout) {
if (supportsRequestTimeout()) {
VirtualMachine vm = getVM();
if (vm != null) {
((org.eclipse.jdi.VirtualMachine)vm).setRequestTimeout(timeout);
}
}
}
/**
* @see IJavaDebugTarget#getRequestTimeout()
*/
public int getRequestTimeout() {
if (supportsRequestTimeout()) {
VirtualMachine vm = getVM();
if (vm != null) {
return ((org.eclipse.jdi.VirtualMachine)vm).getRequestTimeout();
}
}
return -1;
}
/**
* @see IJavaDebugTarget#supportsRequestTimeout()
*/
public boolean supportsRequestTimeout() {
return getJavaDebugTarget().isAvailable() && getVM() instanceof org.eclipse.jdi.VirtualMachine;
}
/**
* @see org.eclipse.debug.core.model.IDisconnect#canDisconnect()
*/
public boolean canDisconnect() {
return getDebugTarget().canDisconnect();
}
/**
* @see org.eclipse.debug.core.model.IDisconnect#disconnect()
*/
public void disconnect() throws DebugException {
getDebugTarget().disconnect();
}
/**
* @see org.eclipse.debug.core.model.IDisconnect#isDisconnected()
*/
public boolean isDisconnected() {
return getDebugTarget().isDisconnected();
}
/**
* @see org.eclipse.debug.core.model.IStepFilters#isStepFiltersEnabled()
*/
public boolean isStepFiltersEnabled() {
return getJavaDebugTarget().isStepFiltersEnabled();
}
}