1
|
Some notes about the CNF in attempt to understand things.
|
2
|
|
3
|
30 Nov 08 FRU
|
4
|
|
5
|
Documentation notes:
|
6
|
|
7
|
There is some good text potentially for the docs in:
|
8
|
|
9
|
https://bugs.eclipse.org/bugs/show_bug.cgi?id=195595
|
10
|
|
11
|
|
12
|
|
13
|
Navigator Content
|
14
|
|
15
|
The purpose of the navigatorContent extension (NCE) is to bind a content provider
|
16
|
and label provider to the navigator under the right circumstances depending
|
17
|
on what is selected.
|
18
|
|
19
|
A navigator content descriptor has a one-to-one correspondence with the
|
20
|
navigator content extension, which is the higher level object representing
|
21
|
the navigator content.
|
22
|
|
23
|
Overriding
|
24
|
|
25
|
An NCE may specify that it overrides another through the user of the override
|
26
|
mechanism where it specifies the NCE extension ID of the extension to override.
|
27
|
|
28
|
When doing the processing associated with the label and content provider, it is possible
|
29
|
that multiple NCEs meet the criteria for processing based on their triggerPoints and/or
|
30
|
possibleChildren. When this happens, the NCEs are ordered in a tree based
|
31
|
on the overrides specification, and then with that based on priority.
|
32
|
The first NCE in the tree that provides the answer (label or content) being
|
33
|
sought is used.
|
34
|
|
35
|
When the NCE is bound to the viewer (using the contentExtension element) it may
|
36
|
specify that that NCE serves as "root content" for that viewer, which allows
|
37
|
the viewer to start with an initial set of NCEs to process the root(s) [why exactly --
|
38
|
I understand intuitively but can't put it into words].
|
39
|
|
40
|
|
41
|
Pipelining
|
42
|
|
43
|
In some cases, it is desirable to have multiple NCEs be invoked during
|
44
|
content provider processing to modify the objects to be returned by the
|
45
|
content provider. This is done using the pipelining mechanism where each NCE
|
46
|
in the tree has the opportunity to modify the objects to be returned by the
|
47
|
content provider. There are also hooks for these pipelined NCEs to
|
48
|
be invoked at the Add/Remove/Update/Refresh methods on the viewer.
|
49
|
|
50
|
|
51
|
Selecting a Content Extension (NCE)
|
52
|
|
53
|
This is done either through the possibleChildren or triggerPoints expression
|
54
|
on the NCE. The enablement expression expression specifies the same expression
|
55
|
for both triggerPoints and possibleChildren.
|
56
|
|
57
|
The triggerPoints expression is used:
|
58
|
|
59
|
- by the NavigatorContentServiceContentProvider
|
60
|
to find extensions for getElements() (through the root content extensions)
|
61
|
or getChildren(). Given a parent node, that content extension is used
|
62
|
to determine what children to provide.
|
63
|
- by the NavigatorPipelineService for ???
|
64
|
|
65
|
The possibleChildren expression is used for all other cases, which include:
|
66
|
|
67
|
- Label/icon/description provider
|
68
|
- Selecting the NCE for a drop
|
69
|
|
70
|
The current documentation on these uses is incorrect, in particular for
|
71
|
the label provides, it says that the triggerPoints expression is used, but
|
72
|
it's not.
|
73
|
|
74
|
|
75
|
|
76
|
|
77
|
|
78
|
|
79
|
Dependency
|
80
|
|
81
|
Questions/Issues:
|
82
|
|
83
|
1) In NavigatorContentServicedLabelProvider, seems that we look for
|
84
|
label providers by looking for matching NCEs by possibleChild.
|
85
|
However the documentation is clear that content and label providers
|
86
|
are found by triggerPoint, possibleChild is used only in the content
|
87
|
provider getParent() case.
|
88
|
|
89
|
<mde>The API documentation for label providers is wrong. It has always been
|
90
|
the case that label providers rely on the possibleChildren; we should
|
91
|
correct the doc since actual implementations are relying on the
|
92
|
behavior of label providers using possible children (but only in
|
93
|
cases where the framework can't determine which extension contributed
|
94
|
the content with its short term memory mechanism).
|
95
|
Other parts of the framework (like the DND Drop Handlers) also rely on
|
96
|
possible children to determine which content extension's handlers
|
97
|
should be invoked when processing a drop operation. </mde>
|
98
|
|
99
|
|
100
|
2) In NavigatorContentServiceLabel provider, there seems to be special
|
101
|
processing to handle overriding instead of using the normal processing
|
102
|
to get only the relevant NCEs. Also, the way to get the NCEs is
|
103
|
different depending on whether doing a getImage() or getForeground()
|
104
|
for example and I don't understand why. Also
|
105
|
NavigatorContentServiceDescriptionProvider does not seem to consider
|
106
|
overrides at all. This all seems wrong.
|
107
|
|
108
|
<mde>
|
109
|
The content extension has alot of complexity because it has to
|
110
|
determine the overrides for each individual child along the path.
|
111
|
Labels are a bit simpler because only one value can be returned.
|
112
|
The override logic recursively walks the override path by the highest
|
113
|
priority label provider. Overriding label providers can opt not to
|
114
|
return a label (e.g. null), and the framework will fall back on the
|
115
|
base label provider to provide a value.
|
116
|
|
117
|
The getForeground()/getFont() cases weren't retrofitted for
|
118
|
overriding values. This was just a legacy/point in time and
|
119
|
is arguably a bug. The Font and Color providers were added to
|
120
|
support the Team providers (they weren't part of the original product
|
121
|
framework). If anything, the getFont()/Foreground/Background()
|
122
|
methods should be retrofitted to follow the patter in getText/Image().
|
123
|
</mde>
|
124
|
|
125
|
|
126
|
3) The triggerPoints and possibleChildren descriptions in the exsd are
|
127
|
confusing:
|
128
|
|
129
|
"The triggerPoints expression defines the nodes in a tree that should
|
130
|
cause this extension to be invoked for children."
|
131
|
|
132
|
"The possibleChildren expression defines the nodes in a tree that
|
133
|
could be contributed by this extension. Clients should describes when
|
134
|
this content extension could provide a parent for elements that match
|
135
|
the expression."
|
136
|
|
137
|
I think a clearer description is:
|
138
|
|
139
|
The triggerPoints expression defines the tree nodes for which this
|
140
|
extension (and associated content/label providers) is to be invoked.
|
141
|
|
142
|
<mde>Remove "label providers" and we're good. </mde>
|
143
|
|
144
|
The possibleChildren expression defines the content provider to be
|
145
|
selected when processing the ITreeContentProvider.getParent() call.
|
146
|
|
147
|
<mde>As well as the DND Drop Handler and Action Providers.</mde>
|
148
|
|
149
|
4) Why is the overridden tree computed only on
|
150
|
findDescriptorsForPossibleChild and not for
|
151
|
findDescriptorsForTriggerPoint? The extension point documentation for
|
152
|
the overrides element says that the overrides only applied to
|
153
|
triggerpoints, it does not mention possibleChildren (except in
|
154
|
reference to the OnlySuppressedifExtVisibleAndActive option is set,
|
155
|
but it still seems to say that only triggerPoints is actually used).
|
156
|
|
157
|
<mde>It might be worth setting up an hour to go through a deep dive
|
158
|
for this material. If I recall correctly, there was a challenge in
|
159
|
computing all of the triggerpoint overrides a priori, but the
|
160
|
overrides are used. The NavigatorContentServiceContentProvider
|
161
|
processes a given element for children (e.g. getChildren()),
|
162
|
and then invokes the overridden providers directly (from within
|
163
|
the Service content provider) to compute the overridden tree.
|
164
|
The possible children through doesn't have a use case like this,
|
165
|
and so these can be computed and returned as needed.</mde>
|
166
|
|
167
|
5) More confusion (from the overrides exsd):
|
168
|
|
169
|
"InvokeAlwaysRegardlessOfSuppressedExt (default): Indicates that this
|
170
|
extension is a first class extension; it should be given opportunities
|
171
|
to contribute content regardless if its suppressedExtensionId is
|
172
|
visible or active to the viewer. Thus, the extension is a first-class
|
173
|
extension and an overriding extension. It will be invoked whenever its
|
174
|
triggerPoints expression is matched. When the suppressed extension and
|
175
|
its triggerPoints extension is matched, it will be invoked with the
|
176
|
contributed items from its suppressed extension; the suppressed
|
177
|
extension will not be given an opportunity to directly contribute."
|
178
|
|
179
|
The last sentence of this is unclear. I think it would be better (and
|
180
|
consistent with the rest of the explanations) if the suppressed
|
181
|
extension was just suppressed, it is never invoked at all.
|
182
|
|
183
|
<mde>The use cases here are as follows:
|
184
|
|
185
|
1. I want to contribute my stuff, and I want to specialize an existing provider
|
186
|
like Java, and
|
187
|
|
188
|
2. I want to just specialize another provider, and if it's not turned on, I don't
|
189
|
even need to be considered.
|
190
|
|
191
|
So in neither case is it completely suppressed, but rather in case 2 it acts
|
192
|
like a domino of its source provider. I just want to make sure we don't
|
193
|
lose this meaning in the update of the documentation </mde>
|
194
|
|
195
|
|
196
|
6) Should the NCE class and NavigatorContentDescriptor classes be
|
197
|
combined? They seem to be one-to-one and there is a lot of code that
|
198
|
seems to convert from one to another for no good reason.
|
199
|
|
200
|
<mde>The Descriptor/Extension pattern is used for every part of the framework, here's why:
|
201
|
|
202
|
A Manager handles Descriptors; Managers are singletons, and each known extension
|
203
|
has exactly one Descriptor. The state associated with a Descriptor is just an API
|
204
|
convenience layer on top of the IConfigurationElement API. These are relatively
|
205
|
lightweight, and their lifecycle is the lifecycle of the Manager, which is
|
206
|
effectively the lifecycle of the workbench.
|
207
|
|
208
|
A Service handles Extensions; Services are 1 instance per Common Navigator viewer
|
209
|
(or whatever client is using the Service). Each Service creates an Extension
|
210
|
and manages a map from Descriptor (1 instance for each extension for all
|
211
|
viewers) to its Extension (1 instance for each instance viewer). The Extension
|
212
|
instance creates instances of classes defined by the plugin extension metadata;
|
213
|
each of these instances has an associated lifecycle (init .. do work .. dispose)
|
214
|
and can hold on to system resources (label providers can hold Fonts or Colors,
|
215
|
content providers might talk to a data source across a network). Most of these
|
216
|
classes aren't necessarily designed to be re-entrant (they make assumptions
|
217
|
about the current state of a given viewer, like whether to show
|
218
|
Packages as hierarchical or flattened). So if I create a Project Explorer,
|
219
|
and then separately create a MyCustomView and bind Java to each of them,
|
220
|
I'll have 1 Java Descriptor, and 2 Java Extensions in memory.
|
221
|
|
222
|
Collapsing Descriptors into Extensions would be a fundamental change to the
|
223
|
framework, eliminate the assumption that there's 1 content
|
224
|
provider/label provider/etc for each view instance, and make it hard or
|
225
|
impossible to know when each of the instantiated classes from each
|
226
|
plugin extension can be disposed. I would not recommend this.
|
227
|
</mde>
|
228
|
|
229
|
|
230
|
7) There are substantial chunks of duplicate code where only one
|
231
|
line is different between the similar methods.
|
232
|
|
233
|
<mde>If you can provide a few examples, I might be able to provide some
|
234
|
insights here; in many cases, I tried to use the same simple patterns
|
235
|
throughout the frameworks to keep the overall complexity down, which
|
236
|
can lead to this kind of pattern.</mde>
|
237
|
|
238
|
|