Bug 290285 - API for custom JDWP commands and model state refresh
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
index ddc3675..b1e5b50 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
@@ -98,6 +98,7 @@
import org.eclipse.jdt.debug.tests.sourcelookup.SourceLocationTests;
import org.eclipse.jdt.debug.tests.sourcelookup.SourceLookupTests;
import org.eclipse.jdt.debug.tests.sourcelookup.TypeResolutionTests;
+import org.eclipse.jdt.debug.tests.state.RefreshStateTests;
import org.eclipse.jdt.debug.tests.ui.DetailPaneManagerTests;
import org.eclipse.jdt.debug.tests.ui.ViewMangementTests;
import org.eclipse.jdt.debug.tests.variables.TestLogicalStructures;
@@ -250,6 +251,8 @@
// JDWP tests
addTest(new TestSuite(JDWPTests.class));
+ // Refresh state tests
+ addTest(new TestSuite(RefreshStateTests.class));
// HCR tests are last - they modify resources
addTest(new TestSuite(HcrTests.class));
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ProjectCreationDecorator.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ProjectCreationDecorator.java
index da0cc7a..367c91c 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ProjectCreationDecorator.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ProjectCreationDecorator.java
@@ -167,6 +167,7 @@
createLaunchConfiguration("ThrowsNPE");
createLaunchConfiguration("ThrowsException");
createLaunchConfiguration("org.eclipse.debug.tests.targets.Watchpoint");
+ createLaunchConfiguration("org.eclipse.debug.tests.targets.CallLoop");
createLaunchConfiguration("A");
createLaunchConfiguration("HitCountLooper");
createLaunchConfiguration("CompileError");
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/JDWPTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/JDWPTests.java
index 5d2c234..0ac88e9 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/JDWPTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/JDWPTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 IBM Corporation and others.
+ * Copyright (c) 2007, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -19,6 +19,7 @@
import org.eclipse.jdi.internal.jdwp.JdwpPacket;
import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket;
import org.eclipse.jdi.internal.jdwp.JdwpString;
+import org.eclipse.jdt.debug.core.IJavaDebugTarget;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.tests.AbstractDebugTest;
import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
@@ -52,9 +53,9 @@
thread= launchToLineBreakpoint(typeName, bp);
IDebugTarget target = thread.getDebugTarget();
assertTrue("Wrong target", target instanceof JDIDebugTarget);
- JDIDebugTarget jdiTarget = (JDIDebugTarget) target;
+ IJavaDebugTarget jdiTarget = (IJavaDebugTarget) target;
// VM capabilities
- byte[] reply = jdiTarget.sendJDWPCommand((byte)1, (byte)12, null);
+ byte[] reply = jdiTarget.sendCommand((byte)1, (byte)12, null);
JdwpReplyPacket packet = (JdwpReplyPacket) JdwpPacket.build(reply);
assertEquals("Unexpected error code in reply packet", 0, packet.errorCode());
@@ -84,12 +85,12 @@
thread= launchToLineBreakpoint(typeName, bp);
IDebugTarget target = thread.getDebugTarget();
assertTrue("Wrong target", target instanceof JDIDebugTarget);
- JDIDebugTarget jdiTarget = (JDIDebugTarget) target;
+ IJavaDebugTarget jdiTarget = (IJavaDebugTarget) target;
// VM capabilities
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
DataOutputStream outData = new DataOutputStream(outBytes);
JdwpString.write("LBreakpoints;", outData);
- byte[] reply = jdiTarget.sendJDWPCommand((byte)1, (byte)2, outBytes.toByteArray());
+ byte[] reply = jdiTarget.sendCommand((byte)1, (byte)2, outBytes.toByteArray());
JdwpReplyPacket packet = (JdwpReplyPacket) JdwpPacket.build(reply);
assertEquals("Unexpected error code in reply packet", 0, packet.errorCode());
DataInputStream replyData = packet.dataInStream();
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/state/RefreshStateTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/state/RefreshStateTests.java
new file mode 100644
index 0000000..5be4b7f
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/state/RefreshStateTests.java
@@ -0,0 +1,312 @@
+/*******************************************************************************
+ * Copyright (c) 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests.state;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.model.ILineBreakpoint;
+import org.eclipse.debug.core.model.IThread;
+import org.eclipse.jdi.internal.jdwp.JdwpPacket;
+import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket;
+import org.eclipse.jdt.debug.core.IJavaBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaDebugTarget;
+import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaObject;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.testplugin.DebugElementEventWaiter;
+import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+
+/**
+ * Tests that state refresh works after modifying the target state
+ * with a custom JDWP command.
+ *
+ * @since 3.6
+ */
+public class RefreshStateTests extends AbstractDebugTest {
+
+ public RefreshStateTests(String name) {
+ super(name);
+ }
+
+ /**
+ * Resume a thread behind the scenes and ensure model state updates appropriately.
+ *
+ * @throws CoreException
+ */
+ public void testThreadHasResumed() throws Exception {
+ String typeName = "org.eclipse.debug.tests.targets.CallLoop";
+ ILineBreakpoint bp = createLineBreakpoint(16, "org.eclipse.debug.tests.targets.Looper");
+
+ IJavaThread thread = null;
+ try {
+ thread= launchToLineBreakpoint(typeName, bp);
+ IJavaDebugTarget jdiTarget = (IJavaDebugTarget) thread.getDebugTarget();
+ // Resume thread (set 11, command 3)
+ IJavaObject reference = thread.getThreadObject();
+ ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
+ DataOutputStream outData = new DataOutputStream(outBytes);
+ outData.writeLong(reference.getUniqueId());
+ byte[] reply = jdiTarget.sendCommand((byte)11, (byte)3, outBytes.toByteArray());
+ JdwpReplyPacket packet = (JdwpReplyPacket) JdwpPacket.build(reply);
+
+ assertEquals("Unexpected error code in reply packet", 0, packet.errorCode());
+
+ // model should still be suspended
+ assertTrue("Model should be in suspended state", thread.isSuspended());
+
+ // refresh the model, expect a resume event
+ DebugElementEventWaiter waiter = new DebugElementEventWaiter(DebugEvent.RESUME, thread);
+ jdiTarget.refreshState();
+ Object source = waiter.waitForEvent();
+ assertNotNull("Thread never sent resume event", source);
+ assertEquals("Wrong thread resumed", thread, source);
+ // model should now be in running state
+ assertFalse("Model should now be running", thread.isSuspended());
+ } finally {
+ terminateAndRemove(thread);
+ removeAllBreakpoints();
+ }
+ }
+
+ /**
+ * Resume all threads behind the scenes and ensure model state updates appropriately.
+ *
+ * @throws CoreException
+ */
+ public void testAllThreadsResumed() throws Exception {
+ String typeName = "org.eclipse.debug.tests.targets.CallLoop";
+ IJavaLineBreakpoint bp = createLineBreakpoint(16, "org.eclipse.debug.tests.targets.Looper");
+ bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_VM);
+
+ IJavaThread thread = null;
+ try {
+ thread= launchToLineBreakpoint(typeName, bp);
+ IJavaDebugTarget jdiTarget = (IJavaDebugTarget) thread.getDebugTarget();
+ // Resume each thread (set 11, command 3)
+ IThread[] threads = jdiTarget.getThreads();
+ for (int i = 0; i < threads.length; i++) {
+ IJavaThread jThread = (IJavaThread) threads[i];
+ IJavaObject reference = jThread.getThreadObject();
+ ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
+ DataOutputStream outData = new DataOutputStream(outBytes);
+ outData.writeLong(reference.getUniqueId());
+ byte[] reply = jdiTarget.sendCommand((byte)11, (byte)3, outBytes.toByteArray());
+ JdwpReplyPacket packet = (JdwpReplyPacket) JdwpPacket.build(reply);
+ assertEquals("Unexpected error code in reply packet", 0, packet.errorCode());
+ }
+
+ // model should still be suspended
+ assertTrue("Model should be in suspended state", jdiTarget.isSuspended());
+
+ // refresh the model, expect a resume event
+ DebugElementEventWaiter waiter = new DebugElementEventWaiter(DebugEvent.RESUME, jdiTarget);
+ jdiTarget.refreshState();
+ Object source = waiter.waitForEvent();
+ assertNotNull("Thread never sent resume event", source);
+ // model should now be in running state
+ assertFalse("Model should now be running", jdiTarget.isSuspended());
+ } finally {
+ terminateAndRemove(thread);
+ removeAllBreakpoints();
+ }
+ }
+
+ /**
+ * Suspend a thread behind the scenes and ensure model state updates appropriately.
+ *
+ * @throws CoreException
+ */
+ public void testThreadHasSuspended() throws Exception {
+ String typeName = "org.eclipse.debug.tests.targets.CallLoop";
+ ILineBreakpoint bp = createLineBreakpoint(16, "org.eclipse.debug.tests.targets.Looper");
+
+ IJavaThread thread = null;
+ try {
+ thread= launchToLineBreakpoint(typeName, bp);
+ IJavaDebugTarget jdiTarget = (IJavaDebugTarget) thread.getDebugTarget();
+ // resume the thread to get into running state
+ DebugElementEventWaiter waiter = new DebugElementEventWaiter(DebugEvent.RESUME, thread);
+ thread.resume();
+ waiter.waitForEvent();
+ // model should now be in running state
+ assertFalse("Model should now be running", thread.isSuspended());
+
+ // suspend the thread with a JDWP command (set 11, command 2)
+ IJavaObject reference = thread.getThreadObject();
+ ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
+ DataOutputStream outData = new DataOutputStream(outBytes);
+ outData.writeLong(reference.getUniqueId());
+ byte[] reply = jdiTarget.sendCommand((byte)11, (byte)2, outBytes.toByteArray());
+ JdwpReplyPacket packet = (JdwpReplyPacket) JdwpPacket.build(reply);
+
+ assertEquals("Unexpected error code in reply packet", 0, packet.errorCode());
+
+ // model should still be running
+ assertFalse("Model should be in running state", thread.isSuspended());
+
+ // refresh the model, expect a suspend event
+ waiter = new DebugElementEventWaiter(DebugEvent.SUSPEND, thread);
+ jdiTarget.refreshState();
+ Object source = waiter.waitForEvent();
+ assertNotNull("Thread never sent suspend event", source);
+ assertEquals("Wrong thread suspended", thread, source);
+
+ // model should be suspended now
+ assertTrue("Model should be in suspended state", thread.isSuspended());
+
+ } finally {
+ terminateAndRemove(thread);
+ removeAllBreakpoints();
+ }
+ }
+
+ /**
+ * Suspend all threads behind the scenes and ensure model state updates appropriately.
+ *
+ * @throws CoreException
+ */
+ public void testAllThreadsSuspended() throws Exception {
+ String typeName = "org.eclipse.debug.tests.targets.CallLoop";
+ ILineBreakpoint bp = createLineBreakpoint(16, "org.eclipse.debug.tests.targets.Looper");
+
+ IJavaThread thread = null;
+ try {
+ thread= launchToLineBreakpoint(typeName, bp);
+ IJavaDebugTarget jdiTarget = (IJavaDebugTarget) thread.getDebugTarget();
+ // resume the thread to get into running state
+ DebugElementEventWaiter waiter = new DebugElementEventWaiter(DebugEvent.RESUME, thread);
+ thread.resume();
+ waiter.waitForEvent();
+ // model should now be in running state
+ assertFalse("Model should now be running", thread.isSuspended());
+
+ IThread[] threads = jdiTarget.getThreads();
+ for (int i = 0; i < threads.length; i++) {
+ IJavaThread jThread = (IJavaThread) threads[i];
+ // suspend each thread with a JDWP command (set 11, command 2)
+ IJavaObject reference = jThread.getThreadObject();
+ ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
+ DataOutputStream outData = new DataOutputStream(outBytes);
+ outData.writeLong(reference.getUniqueId());
+ byte[] reply = jdiTarget.sendCommand((byte)11, (byte)2, outBytes.toByteArray());
+ JdwpReplyPacket packet = (JdwpReplyPacket) JdwpPacket.build(reply);
+ assertEquals("Unexpected error code in reply packet", 0, packet.errorCode());
+ }
+
+
+ // model should still be running
+ assertFalse("Model should be in running state", jdiTarget.isSuspended());
+
+ // refresh the model, expect a suspend event
+ waiter = new DebugElementEventWaiter(DebugEvent.SUSPEND, jdiTarget);
+ jdiTarget.refreshState();
+ Object source = waiter.waitForEvent();
+ assertNotNull("Target never sent suspend event", source);
+
+ // model should be suspended now
+ assertTrue("Model should be in suspended state", jdiTarget.isSuspended());
+
+ } finally {
+ terminateAndRemove(thread);
+ removeAllBreakpoints();
+ }
+ }
+
+ /**
+ * Suspend the entire target behind the scenes and ensure model state updates appropriately.
+ *
+ * @throws CoreException
+ */
+ public void testTargetHasSuspended() throws Exception {
+ String typeName = "org.eclipse.debug.tests.targets.CallLoop";
+ ILineBreakpoint bp = createLineBreakpoint(16, "org.eclipse.debug.tests.targets.Looper");
+
+ IJavaThread thread = null;
+ try {
+ thread= launchToLineBreakpoint(typeName, bp);
+ IJavaDebugTarget jdiTarget = (IJavaDebugTarget) thread.getDebugTarget();
+ // resume the thread to get into running state
+ DebugElementEventWaiter waiter = new DebugElementEventWaiter(DebugEvent.RESUME, thread);
+ thread.resume();
+ waiter.waitForEvent();
+ // model should now be in running state
+ assertFalse("Model should now be running", thread.isSuspended());
+
+ // suspend the target with a JDWP command (set 1, command 8)
+ IJavaObject reference = thread.getThreadObject();
+ ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
+ DataOutputStream outData = new DataOutputStream(outBytes);
+ outData.writeLong(reference.getUniqueId());
+ byte[] reply = jdiTarget.sendCommand((byte)1, (byte)8, outBytes.toByteArray());
+ JdwpReplyPacket packet = (JdwpReplyPacket) JdwpPacket.build(reply);
+
+ assertEquals("Unexpected error code in reply packet", 0, packet.errorCode());
+
+ // model should still be running
+ assertFalse("Model should be in running state", jdiTarget.isSuspended());
+
+ // refresh the model, expect a suspend event
+ waiter = new DebugElementEventWaiter(DebugEvent.SUSPEND, jdiTarget);
+ jdiTarget.refreshState();
+ Object source = waiter.waitForEvent();
+ assertNotNull("Target never sent suspend event", source);
+
+ // model should be suspended now
+ assertTrue("Model should be in suspended state", jdiTarget.isSuspended());
+
+ } finally {
+ terminateAndRemove(thread);
+ removeAllBreakpoints();
+ }
+ }
+
+ /**
+ * Resume a target behind the scenes and ensure model state updates appropriately.
+ *
+ * @throws CoreException
+ */
+ public void testTargetHasResumed() throws Exception {
+ String typeName = "org.eclipse.debug.tests.targets.CallLoop";
+ IJavaLineBreakpoint bp = createLineBreakpoint(16, "org.eclipse.debug.tests.targets.Looper");
+ bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_VM);
+
+ IJavaThread thread = null;
+ try {
+ thread= launchToLineBreakpoint(typeName, bp);
+ IJavaDebugTarget jdiTarget = (IJavaDebugTarget) thread.getDebugTarget();
+ // Resume target (set 1, command 9)
+ IJavaObject reference = thread.getThreadObject();
+ ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
+ DataOutputStream outData = new DataOutputStream(outBytes);
+ outData.writeLong(reference.getUniqueId());
+ byte[] reply = jdiTarget.sendCommand((byte)1, (byte)9, outBytes.toByteArray());
+ JdwpReplyPacket packet = (JdwpReplyPacket) JdwpPacket.build(reply);
+
+ assertEquals("Unexpected error code in reply packet", 0, packet.errorCode());
+
+ // model should still be suspended
+ assertTrue("Model should be in suspended state", jdiTarget.isSuspended());
+
+ // refresh the model, expect a resume event
+ DebugElementEventWaiter waiter = new DebugElementEventWaiter(DebugEvent.RESUME, jdiTarget);
+ jdiTarget.refreshState();
+ Object source = waiter.waitForEvent();
+ assertNotNull("Target never sent resume event", source);
+ // model should now be in running state
+ assertFalse("Model should now be running", jdiTarget.isSuspended());
+ } finally {
+ terminateAndRemove(thread);
+ removeAllBreakpoints();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
index d06fbef..a614e07 100644
--- a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.jdt.debug; singleton:=true
-Bundle-Version: 3.5.100.qualifier
+Bundle-Version: 3.6.0.qualifier
Bundle-ClassPath: jdi.jar,
jdimodel.jar,
tools.jar
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugTarget.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugTarget.java
index 7b4a1ec..2f7eada 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugTarget.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaDebugTarget.java
@@ -450,4 +450,34 @@
*/
public String getVersion() throws DebugException;
+ /**
+ * Refreshes the state of the Java debug model elements (client) with the current
+ * state of the debug target.
+ * <p>
+ * For example, a {@link IJavaThread} may currently have a suspended state, but was
+ * somehow resumed on the target. Calling this method will causes all threads to update
+ * their state based on the current state of the target. Elements will fire debug events
+ * associated with any state changes. For example, a thread would fire a resume event
+ * if it discovered it was in a running state when it thought it was suspended.
+ * </p>
+ * @throws DebugException if an exception occurs
+ * @since 3.6
+ */
+ public void refreshState() throws DebugException;
+
+ /**
+ * Sends a JDWP command to the back end and returns the JDWP reply packet as bytes.
+ * This method creates an appropriate command header and packet id, before sending
+ * to the back end.
+ *
+ * @param commandSet command set identifier as defined by JDWP
+ * @param commandId command identifier as defined by JDWP
+ * @param data any bytes required for the command that follow the command header
+ * or <code>null</code> for commands that have no data
+ * @return raw reply packet as bytes defined by JDWP
+ * @exception DebugException if an error occurs sending the packet or receiving the reply
+ * @since 3.6
+ */
+ public byte[] sendCommand(byte commandSet, byte commandId, byte[] data) throws DebugException;
+
}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java
index 8336d94..048386f 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/IJavaThread.java
@@ -271,5 +271,14 @@
* @since 3.3
*/
public int getFrameCount() throws DebugException;
+
+ /**
+ * Returns the object reference associated with this thread.
+ *
+ * @return thread object reference
+ * @throws DebugException if unable to retrieve an object reference
+ * @since 3.6
+ */
+ public IJavaObject getThreadObject() throws DebugException;
}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java
index c04a51f..6230881 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java
@@ -22,6 +22,7 @@
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
@@ -36,9 +37,14 @@
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchListener;
import org.eclipse.debug.core.model.IBreakpoint;
+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.IMemoryBlock;
+import org.eclipse.debug.core.model.IMemoryBlockRetrieval;
import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.ISuspendResume;
+import org.eclipse.debug.core.model.ITerminate;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.jdi.TimeoutException;
import org.eclipse.jdi.internal.VirtualMachineImpl;
@@ -61,6 +67,7 @@
import org.eclipse.jdt.internal.debug.core.breakpoints.JavaLineBreakpoint;
import com.ibm.icu.text.MessageFormat;
+import com.sun.jdi.InternalException;
import com.sun.jdi.ObjectCollectedException;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.ThreadGroupReference;
@@ -2526,5 +2533,122 @@
// #targetRequestFailed will throw an exception
return null;
}
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.debug.core.IJavaDebugTarget#refreshState()
+ */
+ public void refreshState() throws DebugException {
+ if (isTerminated() || isDisconnected()) {
+ return;
+ }
+ boolean prevSuspend = isSuspended();
+ int running = 0;
+ int suspended = 0;
+ List toSuspend = new ArrayList();
+ List toResume = new ArrayList();
+ List toRefresh = new ArrayList();
+ Iterator iterator = getThreadIterator();
+ while (iterator.hasNext()) {
+ JDIThread thread = (JDIThread) iterator.next();
+ boolean modelSuspended = thread.isSuspended();
+ ThreadReference reference = thread.getUnderlyingThread();
+ try {
+ boolean realSuspended = reference.isSuspended();
+ if (realSuspended) {
+ suspended++;
+ if (modelSuspended) {
+ // Even if the model is suspended, it might be in a different location so refresh
+ toRefresh.add(thread);
+ } else {
+ // The thread is actually suspended, refresh frames and fire suspend event.
+ toSuspend.add(thread);
+ }
+ } else {
+ running++;
+ if (modelSuspended) {
+ // thread is actually running, model is suspended, resume model
+ toResume.add(thread);
+ }
+ // else both are running - OK
+ }
+ } catch (InternalException e) {
+ requestFailed(e.getMessage(), e);
+ }
+ }
+ // if the entire target changed state/fire events at target level, else fire thread events
+ boolean targetLevelEvent = false;
+ if (prevSuspend) {
+ if (running > 0) {
+ // was suspended, but now a thread is running
+ targetLevelEvent = true;
+ }
+ } else {
+ if (running == 0) {
+ // was running, but now all threads are suspended
+ targetLevelEvent = true;
+ }
+ }
+ if (targetLevelEvent) {
+ iterator = toSuspend.iterator();
+ while (iterator.hasNext()) {
+ JDIThread thread = (JDIThread) iterator.next();
+ thread.suspendedByVM();
+ }
+ iterator = toResume.iterator();
+ while (iterator.hasNext()) {
+ JDIThread thread = (JDIThread) iterator.next();
+ thread.resumedByVM();
+ }
+ iterator = toRefresh.iterator();
+ while (iterator.hasNext()) {
+ JDIThread thread = (JDIThread) iterator.next();
+ thread.preserveStackFrames();
+ }
+ if (running == 0) {
+ synchronized (this) {
+ setSuspended(true);
+ }
+ fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
+ } else {
+ synchronized (this) {
+ setSuspended(false);
+ }
+ fireResumeEvent(DebugEvent.CLIENT_REQUEST);
+ }
+ } else {
+ iterator = toSuspend.iterator();
+ while (iterator.hasNext()) {
+ JDIThread thread = (JDIThread) iterator.next();
+ thread.preserveStackFrames();
+ thread.setRunning(false);
+ thread.fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
+ }
+ iterator = toResume.iterator();
+ while (iterator.hasNext()) {
+ JDIThread thread = (JDIThread) iterator.next();
+ thread.setRunning(true);
+ thread.fireResumeEvent(DebugEvent.CLIENT_REQUEST);
+ }
+ iterator = toRefresh.iterator();
+ while (iterator.hasNext()) {
+ JDIThread thread = (JDIThread) iterator.next();
+ thread.preserveStackFrames();
+ thread.fireSuspendEvent(DebugEvent.CLIENT_REQUEST);
+ }
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.debug.core.IJavaDebugTarget#sendCommand(byte, byte, byte[])
+ */
+ public byte[] sendCommand(byte commandSet, byte commandId, byte[] data) throws DebugException {
+ try {
+ return sendJDWPCommand(commandSet, commandId, data);
+ } catch (IOException e) {
+ requestFailed(e.getMessage(), e);
+ }
+ return null;
}
}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
index 389e18c..e674801 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
@@ -19,6 +19,7 @@
import java.util.Vector;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
@@ -31,7 +32,10 @@
import org.eclipse.debug.core.IStatusHandler;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.core.model.IStep;
+import org.eclipse.debug.core.model.ISuspendResume;
import org.eclipse.debug.core.model.ITerminate;
+import org.eclipse.debug.core.model.IThread;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.debug.core.IEvaluationRunnable;
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
@@ -2891,4 +2895,12 @@
public synchronized boolean isSuspendVoteInProgress() {
return fSuspendVoteInProgress;
}
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.debug.core.IJavaThread#getThreadObject()
+ */
+ public IJavaObject getThreadObject() throws DebugException {
+ return (IJavaObject) JDIValue.createValue(getJavaDebugTarget(), fThread);
+ }
+
}
\ No newline at end of file