| Some notes about the CNF in attempt to understand things. | 
 |  | 
 | 30 Nov 08 FRU | 
 |  | 
 | Documentation notes: | 
 |  | 
 | There is some good text potentially for the docs in: | 
 |  | 
 | https://bugs.eclipse.org/bugs/show_bug.cgi?id=195595 | 
 |  | 
 |  | 
 |  | 
 | Navigator Content | 
 |  | 
 | The purpose of the navigatorContent extension (NCE) is to bind a content provider | 
 | and label provider to the navigator under the right circumstances depending | 
 | on what is selected. | 
 |  | 
 | A navigator content descriptor has a one-to-one correspondence with the | 
 | navigator content extension, which is the higher level object representing | 
 | the navigator content. | 
 |  | 
 | Overriding | 
 |  | 
 | An NCE may specify that it overrides another through the user of the override | 
 | mechanism where it specifies the NCE extension ID of the extension to override. | 
 |  | 
 | When doing the processing associated with the label and content provider, it is possible | 
 | that multiple NCEs meet the criteria for processing based on their triggerPoints and/or  | 
 | possibleChildren.  When this happens, the NCEs are ordered in a tree based | 
 | on the overrides specification, and then with that based on priority. | 
 | The first NCE in the tree that provides the answer (label or content) being | 
 | sought is used. | 
 |  | 
 | When the NCE is bound to the viewer (using the contentExtension element) it may | 
 | specify that that NCE serves as "root content" for that viewer, which allows | 
 | the viewer to start with an initial set of NCEs to process the root(s) [why exactly -- | 
 | I understand intuitively but can't put it into words]. | 
 |  | 
 |  | 
 | Pipelining | 
 |  | 
 | In some cases, it is desirable to have multiple NCEs be invoked during | 
 | content provider processing to modify the objects to be returned by the | 
 | content provider.  This is done using the pipelining mechanism where each NCE | 
 | in the tree has the opportunity to modify the objects to be returned by the | 
 | content provider.  There are also hooks for these pipelined NCEs to  | 
 | be invoked at the Add/Remove/Update/Refresh methods on the viewer. | 
 |  | 
 |  | 
 | Selecting a Content Extension (NCE) | 
 |  | 
 | This is done either through the possibleChildren or triggerPoints expression | 
 | on the NCE.  The enablement expression expression specifies the same expression | 
 | for both triggerPoints and possibleChildren. | 
 |  | 
 | The triggerPoints expression is used: | 
 |  | 
 | - by the NavigatorContentServiceContentProvider | 
 | to find extensions for getElements() (through the root content extensions)  | 
 | or getChildren().  Given a parent node, that content extension is used | 
 | to determine what children to provide. | 
 | - by the NavigatorPipelineService for ??? | 
 |  | 
 | The possibleChildren expression is used for all other cases, which include: | 
 |  | 
 | - Label/icon/description provider | 
 | - Selecting the NCE for a drop | 
 |  | 
 | The current documentation on these uses is incorrect, in particular for  | 
 | the label provides, it says that the triggerPoints expression is used, but | 
 | it's not. | 
 |  | 
 |  | 
 |  | 
 |  | 
 |  | 
 |  | 
 | Dependency | 
 |  | 
 | Questions/Issues: | 
 |  | 
 | 1) In NavigatorContentServicedLabelProvider, seems that we look for | 
 | label providers by looking for matching NCEs by possibleChild. | 
 | However the documentation is clear that content and label providers | 
 | are found by triggerPoint, possibleChild is used only in the content | 
 | provider getParent() case. | 
 |  | 
 | <mde>The API documentation for label providers is wrong. It has always been  | 
 | the case that label providers rely on the possibleChildren; we should | 
 |  correct the doc since actual implementations are relying on the  | 
 |  behavior of label providers using possible children (but only in  | 
 |  cases where the framework can't determine which extension contributed  | 
 |  the content with its short term memory mechanism).  | 
 |  Other parts of the framework (like the DND Drop Handlers) also rely on  | 
 |  possible children to determine which content extension's handlers  | 
 |  should be invoked when processing a drop operation. </mde> | 
 |  | 
 |  | 
 | 2) In NavigatorContentServiceLabel provider, there seems to be special | 
 | processing to handle overriding instead of using the normal processing | 
 | to get only the relevant NCEs.  Also, the way to get the NCEs is | 
 | different depending on whether doing a getImage() or getForeground() | 
 | for example and I don't understand why.  Also | 
 | NavigatorContentServiceDescriptionProvider does not seem to consider | 
 | overrides at all.  This all seems wrong. | 
 |  | 
 | <mde> | 
 | The content extension has alot of complexity because it has to  | 
 | determine the overrides for each individual child along the path.  | 
 | Labels are a bit simpler because only one value can be returned.  | 
 | The override logic recursively walks the override path by the highest  | 
 | priority label provider. Overriding label providers can opt not to  | 
 | return a label (e.g. null), and the framework will fall back on the  | 
 | base label provider to provide a value. | 
 |  | 
 | The getForeground()/getFont() cases weren't retrofitted for  | 
 | overriding values. This was just a legacy/point in time and  | 
 | is arguably a bug. The Font and Color providers were added to  | 
 | support the Team providers (they weren't part of the original product  | 
 | framework). If anything, the getFont()/Foreground/Background()  | 
 | methods should be retrofitted to follow the patter in getText/Image(). | 
 | </mde> | 
 |  | 
 |  | 
 | 3) The triggerPoints and possibleChildren descriptions in the exsd are | 
 | confusing: | 
 |  | 
 | "The triggerPoints expression defines the nodes in a tree that should | 
 | cause this extension to be invoked for children." | 
 |  | 
 | "The possibleChildren expression defines the nodes in a tree that | 
 | could be contributed by this extension.  Clients should describes when | 
 | this content extension could provide a parent for elements that match | 
 | the expression." | 
 |  | 
 | I think a clearer description is: | 
 |  | 
 | The triggerPoints expression defines the tree nodes for which this | 
 | extension (and associated content/label providers) is to be invoked. | 
 |  | 
 | <mde>Remove "label providers" and we're good. </mde> | 
 |  | 
 | The possibleChildren expression defines the content provider to be | 
 | selected when processing the ITreeContentProvider.getParent() call. | 
 |  | 
 | <mde>As well as the DND Drop Handler and Action Providers.</mde> | 
 |  | 
 | 4) Why is the overridden tree computed only on | 
 | findDescriptorsForPossibleChild and not for | 
 | findDescriptorsForTriggerPoint?  The extension point documentation for | 
 | the overrides element says that the overrides only applied to | 
 | triggerpoints, it does not mention possibleChildren (except in | 
 | reference to the OnlySuppressedifExtVisibleAndActive option is set, | 
 | but it still seems to say that only triggerPoints is actually used). | 
 |  | 
 | <mde>It might be worth setting up an hour to go through a deep dive  | 
 | for this material. If I recall correctly, there was a challenge in  | 
 | computing all of the triggerpoint overrides a priori, but the  | 
 | overrides are used. The NavigatorContentServiceContentProvider  | 
 | processes a given element for children (e.g. getChildren()),  | 
 | and then invokes the overridden providers directly (from within  | 
 | the Service content provider) to compute the overridden tree.  | 
 | The possible children through doesn't have a use case like this,  | 
 | and so these can be computed and returned as needed.</mde> | 
 |  | 
 | 5) More confusion (from the overrides exsd): | 
 |  | 
 | "InvokeAlwaysRegardlessOfSuppressedExt (default): Indicates that this | 
 | extension is a first class extension; it should be given opportunities | 
 | to contribute content regardless if its suppressedExtensionId is | 
 | visible or active to the viewer. Thus, the extension is a first-class | 
 | extension and an overriding extension. It will be invoked whenever its | 
 | triggerPoints expression is matched. When the suppressed extension and | 
 | its triggerPoints extension is matched, it will be invoked with the | 
 | contributed items from its suppressed extension; the suppressed | 
 | extension will not be given an opportunity to directly contribute." | 
 |  | 
 | The last sentence of this is unclear.  I think it would be better (and | 
 | consistent with the rest of the explanations) if the suppressed | 
 | extension was just suppressed, it is never invoked at all. | 
 |  | 
 | <mde>The use cases here are as follows: | 
 |  | 
 | 1. I want to contribute my stuff, and I want to specialize an existing provider  | 
 | like Java, and | 
 |  | 
 | 2. I want to just specialize another provider, and if it's not turned on, I don't  | 
 | even need to be considered. | 
 |  | 
 | So in neither case is it completely suppressed, but rather in case 2 it acts  | 
 | like a domino of its source provider. I just want to make sure we don't  | 
 | lose this meaning in the update of the documentation </mde> | 
 |  | 
 |  | 
 | 6) Should the NCE class and NavigatorContentDescriptor classes be | 
 | combined? They seem to be one-to-one and there is a lot of code that | 
 | seems to convert from one to another for no good reason. | 
 |  | 
 | <mde>The Descriptor/Extension pattern is used for every part of the framework, here's why: | 
 |  | 
 | A Manager handles Descriptors; Managers are singletons, and each known extension | 
 | has exactly one Descriptor. The state associated with a Descriptor is just an API  | 
 | convenience layer on top of the IConfigurationElement API. These are relatively  | 
 | lightweight, and their lifecycle is the lifecycle of the Manager, which is  | 
 | effectively the lifecycle of the workbench. | 
 |  | 
 | A Service handles Extensions; Services are 1 instance per Common Navigator viewer  | 
 | (or whatever client is using the Service). Each Service creates an Extension  | 
 | and manages a map from Descriptor (1 instance for each extension for all  | 
 | viewers) to its Extension (1 instance for each instance viewer). The Extension  | 
 | instance creates instances of classes defined by the plugin extension metadata;  | 
 | each of these instances has an associated lifecycle (init .. do work .. dispose)  | 
 | and can hold on to system resources (label providers can hold Fonts or Colors,  | 
 | content providers might talk to a data source across a network). Most of these  | 
 | classes aren't necessarily designed to be re-entrant (they make assumptions  | 
 | about the current state of a given viewer, like whether to show  | 
 | Packages as hierarchical or flattened). So if I create a Project Explorer,  | 
 | and then separately create a MyCustomView and bind Java to each of them,  | 
 | I'll have 1 Java Descriptor, and 2 Java Extensions in memory. | 
 |  | 
 | Collapsing Descriptors into Extensions would be a fundamental change to the  | 
 | framework, eliminate the assumption that there's 1 content  | 
 | provider/label provider/etc for each view instance, and make it hard or  | 
 | impossible to know when each of the instantiated classes from each  | 
 | plugin extension can be disposed. I would not recommend this. | 
 | </mde> | 
 |  | 
 |  | 
 | 7) There are substantial chunks of duplicate code where only one | 
 | line is different between the similar methods. | 
 |  | 
 | <mde>If you can provide a few examples, I might be able to provide some  | 
 | insights here; in many cases, I tried to use the same simple patterns  | 
 | throughout the frameworks to keep the overall complexity down, which  | 
 | can lead to this kind of pattern.</mde> | 
 |  | 
 |  |