1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00
cdt/plugins/org.eclipse.dd.doc.dsf/docs/dsf_data_model.html

286 lines
16 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title>DSF Data Model</title>
</head>
<body>
<h2>DSF Data Model</h2>
<b><span style="font-size: 12pt; font-family: &quot;Times New Roman&quot;;">Version
1.0<br>
Pawel Piech<br>
&copy; 2006, Wind River Systems.<span style="">&nbsp; </span>Release
under EPL version 1.0.</span></b>
<h3>Overview</h3>
<p>The data model aspect of DSF is only partially complete as compared
to the Concurrency and Services Models.&nbsp; The goals for its design
are:<br>
</p>
<ol>
<li><span style="font-style: italic;">Separate the structure of the
data in the services from the model used for presentation in views.</span>&nbsp;
This seems like a basic model-viewer separation, which is something
that we theoretically have already.&nbsp; But in reality the current
platform debug model APIs closely correspond to how the data is
laid out in debug views, and even with the flexible hierarchy views it
is
difficult to provide alternative layouts.</li>
<li><span style="font-style: italic;">Allow for a modular
implementation of services that contribute to the data model.</span>&nbsp;&nbsp;
<br>
</li>
<li><span style="font-style: italic;">Perform well with large
data sets.</span></li>
<li><span style="font-style: italic;">Make the data model interfaces
convenient to use by other services as well as by views.</span>&nbsp;
Some interim designs of DSF data model APIs were very well suited for
populating views (though asynchronous) content and label provider, but
were very difficult to use for other purposes, such as by another
service, or a client that creates a dialog.&nbsp; This led to services
implementing two sets of interfaces for the same data, which was more
expensive to develop and maintain.<br>
</li>
<li><span style="font-style: italic;">Allow for easy changes to the
layout of data in views.</span>&nbsp; This is from the point of view of
a debugger implementer that would like to modify the standard layout of
debugger data. <br>
</li>
<li><span style="font-style: italic;">Allow the users to modify the
layout of data in views.</span>&nbsp; And this is a logical extension
of the previous goal.</li>
</ol>
<p> </p>
That's a pretty ambitious set of goals to keep in mind, which partly
explains why the design is not fully complete yet.&nbsp; In particular,
the last goal doesn't have any implementation at this point.&nbsp; But
other than that the, we believe that our current design mostly
meets the other goals.&nbsp; It remains to be seen how well it will
hold up
beyond a prototype implementation.<br>
<p>The DSF data model is divided into two parts: a non-UI part that
helps services expose data in a consistent form, and a UI part that
helps viewers present the data.&nbsp; They are described separately in
the two sections below.<br>
</p>
<h3>Timers Example</h3>
<p>A <a
href="http://dsdp.eclipse.org/help/latest/topic/org.eclipse.dd.dsf.doc/reference/api/org/eclipse/dd/dsf/examples/timers/package-summary.html">"timers
example"</a> is included with the DSF plugins which
demonstrates the use of data model and view model
APIs.&nbsp;&nbsp; It is probably much easier to digest this document
when referring to this example for usage.<br>
</p>
<h3>Data Model API (<a
href="http://dsdp.eclipse.org/help/latest/topic/org.eclipse.dd.dsf.doc/reference/api/org/eclipse/dd/dsf/model/package-summary.html"><span
style="font-family: monospace;">org.eclipse.dd.dsf.model</span></a>)<br>
</h3>
As stated before, the aim of this API is to allow services to provide
data with just enough common information, so that it can be easily
presented in the view, but with a simple enough design, so that the
data can be accessed by non-viewer clients.&nbsp; The type of data in
services can vary greatly from service to service, some data for
example:<br>
<ul>
<li>service data might be extremely large and thus may only be
retrieved from a back end process in small chunks, while some service
data might be always stored locally in the service<br>
</li>
<li>data might take a very long time to retrieve, or it could be
instantaneous<br>
</li>
<li>some services might support canceling of the request while it is
being processed, while other services might not<br>
</li>
<li>some data may change very frequently, other data may not change
at all<br>
</li>
</ul>
The data model API tries to find a common denominator for these
divergent properties and imposes the following restrictions:<br>
<ol>
<li>Each "chunk" of data that comes from a service has a
corresponding <span style="font-family: monospace;">IDataModelContext </span>(Data Model Context)
object.<br>
</li>
<li>The DM-Context objects are to be generated by the data model services (<span
style="font-family: monospace;">IDataModelService</span>) with either
synchronous or asynchronous methods, and taking whatever arguments are
needed.&nbsp; Put differently, how DM-Contexts are created is up to the
service.</li>
<li>The service will provide a method for retrieving each "chunk" of
model data (<span style="font-family: monospace;">IDataModelData</span>)
using a method that requires no other arguments besides the DM-Contexts.</li>
</ol>
<h4>DM-Context (<span style="font-family: monospace;">IMContext</span>)<br>
</h4>
The DM-Contexts are the most
important part of this design, so they warrant a closer look.&nbsp; The
interface is listed below:<br>
<pre> public interface IDataModelContext&lt;V extends IDataModelData&gt; extends IAdaptable {<br> public String getSessionId();<br> public String getServiceFilter();<br> public IDataModelContext[] getParents();<br> }<br></pre>
First of all the object extends <span style="font-family: monospace;">IAdaptable</span>,
which allows clients to use these objects as handles that are stored
with UI components.&nbsp; However the implementation of <span
style="font-family: monospace;">IDataModelData.getAdapter()</span>&nbsp;
presents a particular challenge.&nbsp; If the standard platform method
of retrieving an adapter is used (<span style="font-family: monospace;">PlatformObject.getAdapter()</span>),
then there can only be one adapter registered for a given DM-Context class,
which has to be shared by all the DSF sessions that are running
concurrently.&nbsp; Thus one debugger that implements a <span
style="font-family: monospace;">IStack.IFrameDMContext</span>, would have to
have the same instance of<span style="font-family: monospace;">
IAsynchronousLabelAdapter</span> as another debugger implementation
that is running at the same time.&nbsp; To overcome this problem, DSF
provides a method for registering adapters with a session using <span
style="font-family: monospace;">DsfSession.registerModelAdapter()</span>,
instead of with the platform (<span style="font-family: monospace;">Platform.getAdapterManager().registerAdapters()</span>).&nbsp;
<br>
<p>The <span style="font-family: monospace; font-weight: bold;">getSessionId()</span>
method serves two purposes.&nbsp; First, it allows the
<span style="font-family: monospace;">IAdapter.getAdapter()</span>
implementation to work as described above. Second, it allows clients to
access the correct dispatch thread (<span
style="font-family: monospace;">DsfSession.getSession(id).getExecutor()</span>)
for calling the service that the DM-Context originated from.&nbsp; <br>
</p>
<p>The <span style="font-family: monospace; font-weight: bold;">getServiceFilter()</span>
method is actually included to allow future development.&nbsp; It is
intended to allow the client to precisely identify the service that
the DM-Context originated from, without having to examine the exact class type
of the DM-Context.&nbsp; But this functionality will not really be needed
until we start writing generic/data-driven clients.<br>
</p>
<p>The <span style="font-family: monospace; font-weight: bold;">getParents()</span>
method allows the DM-Context to be connected together into something that can
be considered a "model".&nbsp; Of course, most debugger data objects,
require the context of other objects in order to make sense: stack
frame is meaningless without the thread, debug symbols belong to a
module, which belongs to a process, etc.&nbsp; In other words, there is
some natural hierarchy to the data in debug services which needs to be
accessible through the data model APIs.&nbsp; This hierarchy may be the
same hierarchy that is to be shown in some debug views, but it doesn't
have to be.&nbsp; More importantly, this hierarchy should allow for a
clean separation of debug services, and for a clear dependency graph
between these services. </p>
<h3>View Model API (<a
href="http://dsdp.eclipse.org/help/latest/topic/org.eclipse.dd.dsf.doc/reference/api/org/eclipse/dd/dsf/ui/model/package-summary.html"><span
style="font-family: monospace;">org.eclipse.dd.dsf.ui.model</span></a>)<br>
</h3>
This is the component which allows the DSF data model to be presented
in
the views with different/configurable layouts.&nbsp; It is tightly
integrated with the recently added (and still provisional)
flexible-hierarchy viewers in the <span style="font-family: monospace;">org.eclipse.debug.ui</span>
plugin (see EclipseCon 2006 <a
href="http://www.eclipsecon.org/2006/Sub.do?id=31">presentation</a>
for more details).&nbsp; Actually, the platform flexible hierarchy
framework already provides all the adapter interfaces needed to present
the DSF data model in the viewers, and it is possible to do
that.&nbsp; However the flexible hierarchy views were not specifically
designed for DSF, and there are a few ugly patterns that emerge when
using them with DSF data model interfaces directly:<br>
<ul>
<li>Because of the nature of IAdaptable pattern, the flexible
hierarchy label and content adapters have to have a single instance
that works for all views that the objects appear in.&nbsp; This leads
to a lot of if-else statements, which make the implementation difficult
to follow.<br>
</li>
<li>There is a single adapter for all DSF data model elements in the
tree (from the same session), so the adapters have even more if-else
statements to handle the different elements in the viewer.</li>
<li>Most of DSF adapter work needs to be performed in the dispatch
thread, so each handler starts with a re-dispatch call.</li>
<li>In all of this, the logic which determines the hierarchy of
elements in the viewer is very hard to follow.</li>
</ul>
The view model API tries to address these issues in the following way:<br>
<ol>
<li>It divides the adapter work for different views in separate <span
style="font-family: monospace;">ViewModelProvider</span> objects.</li>
<li>It defines the view layout in an object-oriented manner using the
<span style="font-family: monospace;">IViewModelLayoutNode</span>
objects.</li>
<li>It consolidates the logic of switching to dispatch thread in one
place, and allows the <span style="font-family: monospace;">ViewModelProvider</span>
objects to work only in dispatch thread.<br>
</li>
</ol>
<h4><span style="font-family: monospace;">IViewModelLayoutNode</span></h4>
The core of the logic in this design lies in the implementation of the <span
style="font-family: monospace;">IViewModelLayoutNode</span> objects.
This interface is listed below:<br>
<pre>public interface IViewModelLayoutNode {<br> public IViewModelLayoutNode[] getChildNodes();<br> public void hasElements(IViewModelContext parentVmc, GetDataDone&lt;Boolean&gt; done);<br> public void getElements(final IViewModelContext parentVmc, GetDataDone&lt;IViewModelContext[]&gt; done);<br> public void retrieveLabel(IViewModelContext vmc, final ILabelRequestMonitor result);<br> public boolean hasDeltaFlags(IDataModelEvent e);<br> public void buildDelta(IDataModelEvent e, ViewModelDelta parent, Done done);<br> public void sessionDispose();<br>}<br></pre>
The <span style="font-family: monospace; font-weight: bold;">getChildNodes()</span>
method allows these layout nodes to be combined into a tree structure,
which mimics the layout of elements in the view.&nbsp; What the
children are depends on the implementation, some may be configurable
and
some may be fixed.<br>
<br>
The <span style="font-family: monospace; font-weight: bold;">hasElements()</span>
and <span style="font-family: monospace; font-weight: bold;">getElements()</span>
methods generate the actual elements that will appear in the
view.&nbsp; The methods are analogous to the flexible hierarchy API
methods: <span style="font-family: monospace;">IAsynchronousContentAdapter.isContainer()</span>
and <span style="font-family: monospace;">IAsynchronousContentAdapter.retrieveChildren()</span>
and are pretty straightforward to implement. Also <span
style="font-weight: bold; font-family: monospace;">retrieveLabel()</span>
is directly analogous to
IAsynchronousLabelAdapter.retrieveLabel().&nbsp; <br>
<br>
The <span style="font-family: monospace; font-weight: bold;">hasDeltaFlags()</span>
and <span style="font-weight: bold; font-family: monospace;">buildDelta()</span>
are used to generate model deltas in response to service events. These
are discussed in the next section.<br>
<br>
Finally, in most cases the elements in the views correspond
directly to an <span style="font-family: monospace;">IDataModelContext</span>
(DM-Context) objects of a specific type.&nbsp; In those cases, the <span
style="font-family: monospace;">DMContextVMLayoutNode</span>
abstract class implements the common functionality in that pattern.<br>
<h4>Model deltas</h4>
The <span style="font-family: monospace;">hasDeltaFlags()</span> and <span
style="font-family: monospace;">buildDelta()</span> methods are used
to implement the <span style="font-family: monospace;">IModelProxy </span>adapter,
and are the most tricky aspect of this design.&nbsp; The difficulty is
that the flexible hierarchy views require that the <span
style="font-family: monospace;">IModelProxy </span>translate data
model-specific events, into generic model deltas that can be
interpreted by the viewer.&nbsp; The deltas (<span
style="font-family: monospace;">IModelDelta</span>) are tree
structures which are supposed to mirror the structure of nodes in the
tree, and which contain flags that tell the viewer what has changed in
the view and how.<a href="#Asterix">*</a>&nbsp; This means that if the
model proxy receives an event for some <span
style="font-family: monospace;">IDataModelContext</span> (DM-Context) object,
it needs to know if this object is in the viewer's tree, and what is
the full path (or paths) that leads to this object.&nbsp; <br>
<p>The model delta is generated by first calling the top layout node's <span
style="font-family: monospace;">hasDeltaFlags()</span> with the
received event, which then can either return <span
style="font-family: monospace;">true </span>or ask any of its
children if they have deltas (which in turn returns true or calls its
children, etc).&nbsp; If a node returns <span
style="font-family: monospace;">true </span>for <span
style="font-family: monospace;">hasDeltaFlags()</span>, then the
asynchronous <span style="font-family: monospace;">buildDelta()</span>
is called with the event and a parent delta node, to generate the delta
elements and flags for its node.&nbsp; Once the layout node generates
its delta objects, it still needs to call its children, which in turn
add their delta information, and so on.<br>
</p>
<p><a name="Asterix"></a>* It's not strictly true that a full path to
an element always has to be present for model delta's to work.&nbsp; If
the full path is not present, the viewer will try to find the element
using an internal map that it keeps of all of the elements it
knows.&nbsp;
But since the viewer is lazy loading, it is possible (and likely) that
the element affected by an event is not even known to the viewer at
time of the event, and for some delta actions, <span
style="font-family: monospace;">IModelDelta.SELECT</span> and <span
style="font-family: monospace;">IModelDelta.EXPAND</span>, this is not
acceptable.<br>
</p>
</body>
</html>