blob: bc386e56680c8c0ba5c6a3f63e199edd334972aa [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<h1>Registry Resolver &#8211; Pseudo Code and Notes</h1>
<p><em>Last updated April 15, 2003</em></p>
<pre>if (registry is already resolved)
stop now &#8211; nothing to do
foreach (plugin in the registry) do {
if (the plugin is missing any of the required fields)
generate an error and disable this plugin
make an IndexEntry for this plugin id (if one doesn&#8217;t exist)
put this plugin in the version list of this IndexEntry in order from largest down
} end foreach
foreach (fragment in the registry) do {
if (the fragment is missing any of the required fields)
generate an error and ignore this fragment
make sure all prerequisites for this fragment exist (bug 10799)
find the plugin for fragment.getPluginId() + fragment.getPluginVersion() using
the matching rules described in class PluginVersionIdentifier (bug 5668)
if (the plugin is not found)
generate an error and ignore this fragment
add this fragment to the plugin&#8217;s list of fragments (plugin.fragments)
} end foreach
foreach (plugin in the registry) do {
foreach (fragment in this plugin&#8217;s fragment list) do {
if (this is the most recent version of this fragment in this list)
add the components of this fragment to this plugin
if (this fragment adds a library to the plugin)
make sure we don&#8217;t have duplicate library entries in the plugin (bug 23522)
} end foreach
remove any fragments not contributing to the plugin (i.e. older versions of a fragment) (bug 10719 and 10720)
} end foreach
identify all the root plugin ids
foreach (root plugin id) do {
identify the latest version of the root and use it only
build the ConstraintsEntry -&gt; Constraints structure under this IndexEntry
recursively build these structures for each prerequisite
} end foreach</pre>
<p>NOTE: When the above foreach is done, each plugin id will have an associated
IndexEntry -&gt; ConstraintsEntry -&gt; Constraints structure. For a given plugin
id, the associated IndexEntry, etc. will identify all plugins which require
this one as a prerequisite and all conditions which much be satisfied.
The building of these structures must also remove any prerequisite loops and
remove any conflicts. This may require disabling some plugins and removing portions
of the ConstraintsEntry -&gt; Constraints structure under a particular IndexEntry.</p>
<pre>foreach (IndexEntry) do {
foreach (ConstraintsEntry) do {
find the plugin descriptor that is a best match for this group of Constraints
} end foreach (ConstraintsEntry)
} end foreach (IndexEntry)
disable all plugin descriptors
foreach (IndexEntry) do {
foreach (ConstraintsEntry) do {
enable the plugin found to be the best match in the previous loop
find the PluginPrerequisite that this plugin descriptor satisfies
tell the PluginPrerequisite which version we resolved to
} end foreach (ConstraintsEntry)
} end foreach (IndexEntry)
optional &#8211; remove all disabled plugins from the registry
optional
foreach (enabled plugin in the registry) do {
foreach (extension in this plugin) do {
find the associated extension point
if (extension point not found){
generate an error
NOTE: Should the plugin be disabled?
} endif
add this extension to the list of extensions for the found extension point
} end foreach (extension)
} end foreach (enabled plugin)
end optional
</pre>
<h3>Some Notes:</h3>
<p>A plugin with no extensions or extension points is termed a &#8216;library&#8217;
plugin.</p>
<p>Version Numbers are matched as follows:
<li>if no version number is specified, pick the latest version that satisfies any other related constraints</li>
<li>if only a version number is specified, ensure a &#8216;compatible&#8217; match</li>
<li>for exact matching rules, check out class PluginVersionIdentifier</li>
<li>multiple versions of a particular plugin id are allowed only if there are
no extensions or extension points in any of the versions</li>
<li>we always try to use at most 1 version of a plugin even if all plugins are
&#8216;library&#8217; plugins.</li>
<p>Example (all plugins are library plugins):</p>
<li>pluginA version 1.2.0 requires pluginB and pluginC version 1.0.0</li>
<li>pluginB version 1.0.0 has no requirements</li>
<li>pluginB version 2.1.0 requires pluginC</li>
<li>pluginC version 1.0.0 has no requirements</li>
<li>pluginC version 1.1.0 has no requirements</li>
<li>pluginC version 2.0.5 has no requirements</li>
<p>Resolving will give us the following plugins:</p>
<li>pluginA version 1.2.0 requires pluginB and pluginC version 1.0.0</li>
<li>pluginB version 2.1.0 requires pluginC</li>
<li>pluginC version 1.1.0 has no requirements</li>
<p>Ideally, pluginB could have used pluginC version 2.0.5.</p>
<h3>Internal RegistryResolver structures:</h3>
<h4>IndexEntry:</h4>
<li>one index entry for each plugin id</li>
<li>each index entry has a pointer to each of the plugin descriptors that have this id</li>
<li>the pointers of plugin descriptors are in version order from the largest version to the smallest</li>
<li>each index entry also has a list of ConstraintsEntry&#8217;s (each ConstraintsEntry
represents a group of constraints that can all be satisfied without conflict)</li>
<li>there is no ordering of ConstraintsEntry&#8217;s (just the order in which they are built)</li>
<h4>ConstraintsEntry:</h4>
<li>represents a group of constraints on a particular plugin id that can all be
satisfied without conflict</li>
<li>these constraints are kept in a list</li>
<li>a new ConstraintsEntry is not created if multiple versions of this plugin
are required and extensions or extension points exist</li>
<li>when an IndexEntry is created, the first (empty) ConstraintsEntry is also
created (therefore, the first invocation must use this first ConstrainsEntry
while other invocations may need to create a new one, if concurrent versions
of this plugin are allowed)</li>
<li>the ConstraintsEntry points back to it&#8217;s parent IndexEntry</li>
<h4>Constraint:</h4>
<li>represents a particular prerequisite in a plugin</li>
<li>a Constraint hangs off a ConstraintsEntry and a ConstraintsEntry hangs off
an IndexEntry. The &#8216;parent&#8217; plugin descriptor in the Constraint
is one of the same plugin descriptors that can be found in the version list
for this IndexEntry</li>
<li>each Constraint exists in only one ConstraintsEntry but a ConstraintsEntry
can have multiple Constraints</li>
<li>the Constraint points back to its parent ConstraintsEntry</li>
<h4>Cookie:</h4>
<li>used primarily as a tool to communicate any errors back to the calling methods
(and thus terminate processing of a particular area of the tree)</li>
<li>keeps a list of all Constraints that have been successfully evaluated to the
current point of execution. This list of constraints is also our was of ensure
we don&#8217;t have any circular dependencies. If we have already have a constraint
in this list with the same PluginPrerequisite as the one we are currently trying
to resolve, we know we have a circular dependency.</li>
<h4>Orphaned Subtrees:</h4>
<p>If a conflict arises such that a particular subtree becomes orphaned, the root
of this subtree will be considered a root node and the remainder of the subtree
(if it resolves correctly) will remain intact. Consider the following example
(pluginResolveTest_15):</p>
<p>PluginA 1.2.0 requires PluginB 2.1.0 and PluginC 1.0.0<br>
PluginB 1.0.0 has no requirements but does have an extension and extension point<br>
PluginB 2.1.0 requires PluginC 2.0.5 (exact match)<br>
PluginC 1.0.0 has no requirements<br>
PluginC 1.1.0 has no requirements but have an extension and extension point<br>
PluginC 2.0.5 has no requirements</p>
<p>In this case, a conflict (non-resolvable because of extensions and extension
points) exists in PluginA and it is disabled. This causes PluginB to be orphaned
and it is then considered a root. Resolution of the above example will return
a registry containing PluginB 2.1.0 and PluginC 2.0.5. While this may seem counter-intuitive,
consider the case where PluginA was a PDE plugin and PluginB was the JDT plugin.
JDT can live without PDE and the subtree really should survive the conflict
in PDE&#8217;s plugin.</p>
<h4>Soft Prerequisites (Optional clause):</h4>
<p>We now have the notion of prerequisites which are optional, called soft prerequisites.
These prerequisites must have the clause &#8216;optional=&#8221;true&#8221;&#8217;.
Consider the following xml statement:</p>
<pre>&lt;requires&gt;
&lt;import plugin=&quot;tests.c&quot; version=&quot;2.1.0&quot; optional=&#8221;true&#8221;/&gt;
&lt;/requires&gt;</pre>
<p>This prerequisite will be ignored if any of the following conditions apply:</p>
<li>the plugin &#8216;tests.c&#8217; does not exist at all</li>
<li>the plugin &#8216;tests.c&#8217; does exist but there are no versions compatible
with version number 2.1.0</li>
<li>the plugin &#8216;tests.c&#8217; exists and there is a version compatible
with 2.1.0 but the addition of this plugin will cause a conflict. A conflict
arises if a particular root plugin requires more than one version of &#8216;tests.c&#8217;,
the versions are not compatible with each other, and at least one of the versions
contains a minimum of one extension or extension point</li>
<p>If an optional prerequisite is ignored for any of the reasons listed above
no error message is generated (but an informational message may be output to
indicate that this prerequisite is being ignored). Ignoring an optional prerequisite
does not cause any plugins to be disabled. This causes potential error conditions
to be more complex. Each time we have a situation where we have a conflict,
we must first check to see if this is an optional prerequisite. The same is
true of situations where we expect to find an associated IndexEntry (or other
structure).</p>
<p>If a prerequisite is ignored, the Constraint structure associated with this
particular parent/prerequisite pair is not added into the IndexEntry, ConstraintsEntry,
Constraint structure. None of the existing structures or pointers to them are
altered or removed. We cannot tell, without re-examining every relationship
associated with this particular root plugin, which portions were used for other
relationships (and not just the relationship leading to this ignored prerequisite).</p>
<h4>Question on &#8216;lastResolved&#8217; field:</h4>
<p>The ConstraintsEntry structure contains a field called &#8216;lastResolved&#8217;
which is set but does not seem to be used. At the same time, there are numerous
places where we examine all of the Constraints off a ConstraintsEntry structure
to determine which plugin (if any) is the best one to resolve these Constraints
compatibly. Can we use &#8216;lastResolved&#8217; to try and minimize these?
Each time we look for a best match plugin, we cycle through all versions of
this plugin and all Constraints off this ConstraintsEntry.</p>
<p></p>
</body>
</html>