From 1385e5e84da91b77f0ac875d25a80a3fe6490c82 Mon Sep 17 00:00:00 2001
From: eutarass
Date: Fri, 25 Apr 2008 18:39:50 +0000
Subject: Bug 227874: [tcf][api] breakpoint event and capabilities changes
---
docs/TCF Service - Breakpoints.html | 120 +++++++++++++++++++--
.../internal/tcf/debug/ui/launch/TCFSelfTest.java | 45 +++++++-
.../tcf/debug/model/TCFBreakpointsModel.java | 8 --
.../tcf/debug/model/TCFBreakpointsStatus.java | 42 +++++---
.../tcf/services/remote/BreakpointsProxy.java | 41 ++++++-
.../org/eclipse/tm/tcf/services/IBreakpoints.java | 63 ++++++++++-
6 files changed, 283 insertions(+), 36 deletions(-)
diff --git a/docs/TCF Service - Breakpoints.html b/docs/TCF Service - Breakpoints.html
index a49cdf3ab..4bf8ea0be 100644
--- a/docs/TCF Service - Breakpoints.html
+++ b/docs/TCF Service - Breakpoints.html
@@ -20,6 +20,7 @@
Get IDs
Get Properties
Get Status
+ Get Capabilities
Events
API
@@ -230,7 +231,7 @@ R
Ø <object>
-Breakpoint stat consists of a list of status properties. All properties are optional.
+
Breakpoint status consists of a list of status properties. All properties are optional.
Tools and targets can define additional properties. Predefined properties are:
@@ -241,15 +242,67 @@ Tools and targets can define additional properties. Predefined properties are:
"Column" : <int>
+
+
+
+C • <token> • Breakpoints • getCapabilities • <string: context ID> •
+
+
+The command reports breakpoint service capabilities to clients so they
+can adjust to different implementations of the service.
+When called with a null ("") context ID the global capabilities are returned,
+otherwise context specific capabilities are returned. A special capability
+property is used to indicate that all child contexts have the same
+capabilities..
+
+Reply:
+
+
+R • <token> • <error report> • <;service capabilities> •
+
+<service capabilities>
+ Ø <object>
+
+
+Service capabilities consist of a list of properties. All properties are optional.
+Tools and targets can define additional properties. Predefined properties are:
+
+
+ "ID" : <string: context ID>
+ - ID of a context that was used to query capabilities
+ "HasChildren" : <boolean>
+ - if true, children of the context can have different capabilities
+ "Address" : <boolean>
+ - if true, "Address" breakpoint property is supported
+ "Condition" : <boolean>
+ - if true, "Condition" breakpoint property is supported
+ "FileLine" : <boolean>
+ - if true, "File", "Line" and "Column" breakpoint properties are supported
+
+
+Breakpoints service events are user to notify clients about breakpoint properties and status changes.
+Note that contextAdded, contextChanged and contextRemoved events carry exactly same set
+of breakpoint properties that was sent by a client to a target. The purpose of these events is to
+let all clients know about breakpoints that were created by other clients.
+
E • Breakpoints • status • <string: breakpoint ID> • <breakpoint status> •
+E • Breakpoints • contextAdded • <array of breakpoints> •
+E • Breakpoints • contextChanged • <array of breakpoints> •
+E • Breakpoints • contextRemoved • <array of breakpoint IDs> •
- status
- is sent when breakpoint status changes.
+
- contextAdded
+
- is sent when a new breakpoints are added.
+
- contextChanged
+
- is sent when breakpoint properties change.
+
- contextRemoved
+
- is sent when breakpoints are removed.
@@ -259,12 +312,12 @@ E
* Breakpoint is represented by unique identifier and set of properties.
* Breakpoint identifier (String id) needs to be unique across all hosts and targets.
*
- * Breakpoint properties (Map) is extendable collection of named attributes,
+ * Breakpoint properties (Map<String,Object>) is extendible collection of named attributes,
* which define breakpoint location and behavior. This module defines some common
* attribute names (see PROP_*), host tools and target agents may support additional attributes.
*
- * For each breakpoint a target agent maintains another extendable collection of named attributes:
- * breakpoint status (Map, see STATUS_*). While breakpoint properties are
+ * For each breakpoint a target agent maintains another extendible collection of named attributes:
+ * breakpoint status (Map<String,Object>, see STATUS_*). While breakpoint properties are
* persistent and represent user input, breakpoint status reflects dynamic target agent reports
* about breakpoint current state, like actual addresses where breakpoint is planted or planting errors.
*/
@@ -297,6 +350,16 @@ E
STATUS_LINE = "Line", // Number
STATUS_COLUMN = "Column"; // Number
+ /**
+ * Breakpoint service capabilities.
+ */
+ static final String
+ CAPABILITY_CONTEXT_ID = "ID", // String
+ CAPABILITY_HAS_CHILDREN = "HasChildren", // Boolean
+ CAPABILITY_ADDRESS = "Address", // Boolean
+ CAPABILITY_CONDITION = "Condition", // Boolean
+ CAPABILITY_FILE_LINE = "FileLine"; // Boolean
+
/**
* Call back interface for breakpoint service commands.
*/
@@ -331,7 +394,7 @@ E
IToken change(Map<String,Object> properties, DoneCommand done);
/**
- * Tell target to change (only) PROP_ENABLED breakpoint property 'true'.
+ * Tell target to change (only) PROP_ENABLED breakpoint property to 'true'.
* @param ids - array of enabled breakpoint identifiers.
* @param done - command result call back object.
*/
@@ -345,7 +408,7 @@ E
IToken disable(String[] ids, DoneCommand done);
/**
- * Tell target to remove breakpoint.
+ * Tell target to remove breakpoints.
* @param id - unique breakpoint identifier.
* @param done - command result call back object.
*/
@@ -383,8 +446,27 @@ E
void doneGetStatus(IToken token, Exception error, Map<String,Object> status);
}
+ /**
+ * Report breakpoint service capabilities to clients so they
+ * can adjust to different implementations of the service.
+ * When called with a null ("") context ID the global capabilities are returned,
+ * otherwise context specific capabilities are returned. A special capability
+ * property is used to indicate that all child contexts have the same
+ * capabilities.
+ * @param id - a context ID or null.
+ * @param done - command result call back object.
+ */
+ IToken getCapabilities(String id, DoneGetCapabilities done);
+
+ interface DoneGetCapabilities {
+ void doneGetCapabilities(IToken token, Exception error, Map<String,Object> capabilities);
+ }
+
/**
* Breakpoints service events listener.
+ * Note that contextAdded, contextChanged and contextRemoved events carry exactly same set
+ * of breakpoint properties that was sent by a client to a target. The purpose of these events is to
+ * let all clients know about breakpoints that were created by other clients.
*/
interface BreakpointsListener {
@@ -394,10 +476,36 @@ E
* @param status - breakpoint status.
*/
void breakpointStatusChanged(String id, Map<String,Object> status);
+
+ /**
+ * Called when a new breakpoints are added.
+ * @param bps - array of breakpoints.
+ */
+ void contextAdded(Map<String,Object>[] bps);
+
+ /**
+ * Called when breakpoint properties change.
+ * @param bps - array of breakpoints.
+ */
+ void contextChanged(Map<String,Object>[] bps);
+
+ /**
+ * Called when breakpoints are removed.
+ * @param ids - array of breakpoint IDs.
+ */
+ void contextRemoved(String[] ids);
}
+ /**
+ * Add breakpoints service event listener.
+ * @param listener - object that implements BreakpointsListener interface.
+ */
void addListener(BreakpointsListener listener);
+ /**
+ * Remove breakpoints service event listener.
+ * @param listener - object that implements BreakpointsListener interface.
+ */
void removeListener(BreakpointsListener listener);
}
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFSelfTest.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFSelfTest.java
index d3942284b..8a456610d 100644
--- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFSelfTest.java
+++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFSelfTest.java
@@ -259,6 +259,7 @@ class TCFSelfTest {
private final Map get_state_cmds = new HashMap();
private final Map> regs =
new HashMap>();
+ private final Map> bp_list = new HashMap>();
private String context_id; // Test process context ID
private IRunControl.RunControlContext context;
@@ -287,6 +288,43 @@ class TCFSelfTest {
this.params = params;
}
}
+
+ private final IBreakpoints.BreakpointsListener bp_listener = new IBreakpoints.BreakpointsListener() {
+
+ public void breakpointStatusChanged(String id, Map status) {
+ }
+
+ public void contextAdded(Map[] bps) {
+ for (Map m0 : bps) {
+ String id = (String)m0.get(IBreakpoints.PROP_ID);
+ Map m1 = bp_list.get(id);
+ if (!checkBPData(m0, m1)) return;
+ }
+ }
+
+ public void contextChanged(Map[] bps) {
+ for (Map m0 : bps) {
+ String id = (String)m0.get(IBreakpoints.PROP_ID);
+ Map m1 = bp_list.get(id);
+ if (!checkBPData(m0, m1)) return;
+ }
+ }
+
+ public void contextRemoved(String[] ids) {
+ }
+
+ private boolean checkBPData(Map m0, Map m1) {
+ if (m1 == null) return true;
+ m0 = new HashMap(m0);
+ if (m0.get(IBreakpoints.PROP_ENABLED) == null) m0.put(IBreakpoints.PROP_ENABLED, Boolean.FALSE);
+ if (m1.get(IBreakpoints.PROP_ENABLED) == null) m1.put(IBreakpoints.PROP_ENABLED, Boolean.FALSE);
+ if (!m1.equals(m0)) {
+ exit(new Exception("Invalid data in Breakpoints event"));
+ return false;
+ }
+ return true;
+ }
+ };
TestRCBP1(IChannel channel, int channel_id) {
this.channel_id = channel_id;
@@ -307,6 +345,7 @@ class TCFSelfTest {
else {
diag.getTestList(this);
}
+ if (bp != null) bp.addListener(bp_listener);
}
public void doneGetTestList(IToken token, Throwable error, String[] list) {
@@ -397,6 +436,7 @@ class TCFSelfTest {
m[i].put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2");
break;
}
+ bp_list.put((String)m[i].get(IBreakpoints.PROP_ID), m[i]);
}
bp.set(m, new IBreakpoints.DoneCommand() {
public void doneCommand(IToken token, Exception error) {
@@ -511,7 +551,7 @@ class TCFSelfTest {
if (threads.size() == 0) return;
done_starting_test_process = true;
final String bp_id = "TcfTestBP3" + channel_id;
- Map m = new HashMap();
+ final Map m = new HashMap();
m.put(IBreakpoints.PROP_ID, bp_id);
m.put(IBreakpoints.PROP_ENABLED, Boolean.FALSE);
m.put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2");
@@ -523,6 +563,7 @@ class TCFSelfTest {
bf.append('"');
}
m.put(IBreakpoints.PROP_CONDITION, bf.toString());
+ bp_list.put(bp_id, m);
bp.change(m, new IBreakpoints.DoneCommand() {
public void doneCommand(IToken token, Exception error) {
if (error != null) exit(error);
@@ -530,6 +571,7 @@ class TCFSelfTest {
});
Protocol.sync(new Runnable() {
public void run() {
+ m.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
bp.enable(new String[]{ bp_id }, new IBreakpoints.DoneCommand() {
public void doneCommand(IToken token, Exception error) {
if (error != null) exit(error);
@@ -1032,6 +1074,7 @@ class TCFSelfTest {
if (x != null) errors.add(x);
if (rc != null) rc.removeListener(this);
}
+ if (bp != null) bp.removeListener(bp_listener);
done(this);
}
}
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsModel.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsModel.java
index ee091ca4e..7993267f4 100644
--- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsModel.java
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsModel.java
@@ -195,7 +195,6 @@ public class TCFBreakpointsModel implements IBreakpointListener, IBreakpointMana
done = new IBreakpoints.DoneCommand() {
public void doneCommand(IToken token, Exception error) {
if (error != null) channel.terminate(error);
- else done(launch);
}
};
update();
@@ -210,9 +209,6 @@ public class TCFBreakpointsModel implements IBreakpointListener, IBreakpointMana
});
};
- void done(TCFLaunch launch) {
- }
-
abstract void update();
}
@@ -297,10 +293,6 @@ public class TCFBreakpointsModel implements IBreakpointListener, IBreakpointMana
void update() {
service.remove(new String[]{ (String)tcf_attrs.get(PROP_ID) }, done);
}
- @Override
- void done(TCFLaunch launch) {
- launch.getBreakpointsStatus().removeStatus((String)tcf_attrs.get(PROP_ID));
- }
}.exec();
}
catch (Throwable x) {
diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsStatus.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsStatus.java
index aeed30228..0785e2050 100644
--- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsStatus.java
+++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFBreakpointsStatus.java
@@ -27,7 +27,6 @@ public class TCFBreakpointsStatus {
private final IBreakpoints service;
private final Map> status = new HashMap>();
private final Set listeners = new HashSet();
- private final Set removed = new HashSet();
private static final Map status_not_supported = new HashMap();
@@ -41,26 +40,49 @@ public class TCFBreakpointsStatus {
if (service != null) {
service.addListener(new IBreakpoints.BreakpointsListener() {
- public void breakpointStatusChanged(String id, Map status) {
+ public void breakpointStatusChanged(String id, Map m) {
assert Protocol.isDispatchThread();
- if (removed.contains(id)) return;
- TCFBreakpointsStatus.this.status.put(id, status);
+ if (status.get(id) == null) return;
+ status.put(id, m);
for (Iterator i = listeners.iterator(); i.hasNext();) {
i.next().breakpointStatusChanged(id);
}
}
+
+ public void contextAdded(Map[] bps) {
+ for (Map bp : bps) {
+ String id = (String)bp.get(IBreakpoints.PROP_ID);
+ if (status.get(id) != null) continue;
+ status.put(id, new HashMap());
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ i.next().breakpointStatusChanged(id);
+ }
+ }
+ }
+
+ public void contextChanged(Map[] bps) {
+ }
+
+ public void contextRemoved(String[] ids) {
+ for (String id : ids) {
+ if (status.remove(id) == null) continue;
+ for (Iterator i = listeners.iterator(); i.hasNext();) {
+ i.next().breakpointRemoved(id);
+ }
+ }
+ }
});
}
}
- public Map getStatus(String id) {
+ public Map getStatus(String id) {
assert id != null;
assert Protocol.isDispatchThread();
if (service == null) return status_not_supported;
return status.get(id);
}
- public Map getStatus(IBreakpoint bp) {
+ public Map getStatus(IBreakpoint bp) {
if (!bp.getModelIdentifier().equals(ITCFConstants.ID_TCF_DEBUG_MODEL)) return status_not_supported;
IMarker marker = bp.getMarker();
if (marker == null) return null;
@@ -68,14 +90,6 @@ public class TCFBreakpointsStatus {
ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, null));
}
- public void removeStatus(String id) {
- status.remove(id);
- removed.add(id);
- for (Iterator i = listeners.iterator(); i.hasNext();) {
- i.next().breakpointRemoved(id);
- }
- }
-
public void addListener(ITCFBreakpointListener listener) {
assert Protocol.isDispatchThread();
listeners.add(listener);
diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/BreakpointsProxy.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/BreakpointsProxy.java
index 3a7ac8ef7..577681ca8 100644
--- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/BreakpointsProxy.java
+++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/BreakpointsProxy.java
@@ -32,7 +32,7 @@ public class BreakpointsProxy implements IBreakpoints {
this.channel = channel;
}
- public IToken set(Map[] properties, final DoneCommand done) {
+ public IToken set(Map[] properties, final DoneCommand done) {
return new Command(channel, this, "set", new Object[]{ properties }) {
@Override
public void done(Exception error, Object[] args) {
@@ -45,7 +45,7 @@ public class BreakpointsProxy implements IBreakpoints {
}.token;
}
- public IToken add(Map properties, final DoneCommand done) {
+ public IToken add(Map properties, final DoneCommand done) {
return new Command(channel, this, "add", new Object[]{ properties }) {
@Override
public void done(Exception error, Object[] args) {
@@ -58,7 +58,7 @@ public class BreakpointsProxy implements IBreakpoints {
}.token;
}
- public IToken change(Map properties, final DoneCommand done) {
+ public IToken change(Map properties, final DoneCommand done) {
return new Command(channel, this, "change", new Object[]{ properties }) {
@Override
public void done(Exception error, Object[] args) {
@@ -157,6 +157,22 @@ public class BreakpointsProxy implements IBreakpoints {
}.token;
}
+ public IToken getCapabilities(String id, final DoneGetCapabilities done) {
+ return new Command(channel, this, "getCapabilities", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ Map map = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ map = (Map)args[2];
+ }
+ done.doneGetCapabilities(token, error, map);
+ }
+ }.token;
+ }
+
public String getName() {
return NAME;
}
@@ -168,6 +184,13 @@ public class BreakpointsProxy implements IBreakpoints {
return (String[])c.toArray(new String[c.size()]);
}
+ @SuppressWarnings("unchecked")
+ private Map[] toBreakpointArray(Object o) {
+ Collection