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. 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. 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. 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(). 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. Remove "label providers" and we're good. The possibleChildren expression defines the content provider to be selected when processing the ITreeContentProvider.getParent() call. As well as the DND Drop Handler and Action Providers. 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). 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. 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. 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 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. 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. 7) There are substantial chunks of duplicate code where only one line is different between the similar methods. 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.