blob: 22a97fd0b7c118fddda3fc8f8d0565fdb2937500 [file] [log] [blame]
package org.eclipse.core.internal.plugins;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.model.*;
import org.eclipse.core.runtime.PluginVersionIdentifier;
import org.eclipse.core.internal.runtime.InternalPlatform;
import org.eclipse.core.internal.runtime.Policy;
public class RegistryResolver {
private Map idmap;
private PluginRegistryModel reg;
private MultiStatus status;
private boolean trimPlugins = true;
private boolean crossLink = true;
public static final int MATCH_EXACT = 0;
public static final int MATCH_COMPATIBLE = 1;
public static final int MATCH_LATEST = 2;
private boolean DEBUG_RESOLVE = false;
private static final String OPTION_DEBUG_RESOLVE = "org.eclipse.core.runtime/registry/debug/resolve";
// constraint entry
private class Constraint {
private PluginDescriptorModel parent;
private PluginPrerequisiteModel prq;
private PluginVersionIdentifier ver;
private int type = MATCH_LATEST;
private ConstraintsEntry cEntry = null;
private Constraint(PluginDescriptorModel parent, PluginPrerequisiteModel prq) {
this.parent = parent;
this.prq = prq;
if (prq != null) {
ver = RegistryResolver.this.getVersionIdentifier(prq);
if (ver == null)
type = MATCH_LATEST;
else
if (prq.getMatch())
type = MATCH_EXACT;
else
type = MATCH_COMPATIBLE;
}
}
private int getMatchType() {
return type;
}
private ConstraintsEntry getConstraintsEntry() {
return cEntry;
}
private void setConstraintsEntry(ConstraintsEntry entry) {
cEntry = entry;
}
private PluginDescriptorModel getParent() {
return parent;
}
private PluginPrerequisiteModel getPrerequisite() {
return prq;
}
private PluginVersionIdentifier getVersionIdentifier() {
return ver;
}
public String toString() {
if (prq == null)
return "(null)";
String s = parent.toString() + "->" + prq.getPlugin();
String v = prq.getVersion();
s += v == null ? "(any)" : (prq.getMatch() ? "(" + v + ",exact)" : "(" + v + ",compatible)");
return s;
}
}
// constraint index structure
private class ConstraintsEntry {
private IndexEntry parent;
private List constraintList = new LinkedList();
private PluginDescriptorModel lastResolved = null;
private boolean isResolved = false;
private PluginDescriptorModel bestMatch = null;
private boolean bestMatchEnabled = false;
private ConstraintsEntry(IndexEntry parent) {
this.parent = parent;
}
private int constraintCount() {
return constraintList.size();
}
private PluginDescriptorModel addConstraint(Constraint c) {
constraintList.add(c);
c.setConstraintsEntry(this);
List constrained = getMatchingDescriptors();
if (constrained.size() <= 0) {
constraintList.remove(c);
c.setConstraintsEntry(null);
return null;
} else {
PluginDescriptorModel match = (PluginDescriptorModel) constrained.get(0);
if (!match.equals(lastResolved)) {
lastResolved = match;
isResolved = false;
}
return match;
}
}
private void removeConstraint(Constraint c) {
if (DEBUG_RESOLVE)
debug("removing constraint " + c.toString());
constraintList.remove(c);
c.setConstraintsEntry(null);
lastResolved = null;
isResolved = false;
}
private void removeConstraintFor(PluginPrerequisiteModel prereq) {
List remove = new ArrayList();
for (Iterator list = constraintList.iterator(); list.hasNext();) {
Constraint c = (Constraint) list.next();
if (c.getPrerequisite() == prereq)
remove.add(c);
}
for (Iterator list = remove.iterator(); list.hasNext();)
removeConstraint((Constraint) list.next());
}
private PluginDescriptorModel getMatchingDescriptor() {
List constrained = getMatchingDescriptors();
if (constrained.size() <= 0)
return null;
else
return (PluginDescriptorModel) constrained.get(0);
}
private List getMatchingDescriptors() {
List constrained = new LinkedList();
for (Iterator list = parent.versions().iterator(); list.hasNext();) {
PluginDescriptorModel pd = (PluginDescriptorModel) list.next();
if (pd.getEnabled())
constrained.add(pd);
}
for (Iterator list = constraintList.iterator(); list.hasNext();) {
Constraint c = (Constraint) list.next();
if (c.getMatchType() == MATCH_LATEST)
continue;
for (Iterator list2 = parent.versions().iterator(); list2.hasNext();) {
PluginDescriptorModel pd = (PluginDescriptorModel) list2.next();
if (!pd.getEnabled())
continue;
if (c.getMatchType() == MATCH_EXACT) {
if (!getVersionIdentifier(pd).isEquivalentTo(c.getVersionIdentifier()))
constrained.remove(pd);
} else {
if (!getVersionIdentifier(pd).isCompatibleWith(c.getVersionIdentifier()))
constrained.remove(pd);
}
}
}
return constrained;
}
private void preresolve(List roots) {
if (constraintList.size() <= 0) {
if (roots.contains(parent.getId())) {
bestMatch = (PluginDescriptorModel) parent.versions().get(0);
if (bestMatch == null) {
if (DEBUG_RESOLVE)
debug("*ERROR* no resolved descriptor for " + parent.getId());
} else
bestMatchEnabled = bestMatch.getEnabled();
}
} else {
bestMatch = getMatchingDescriptor();
if (bestMatch == null) {
if (DEBUG_RESOLVE)
debug("*ERROR* no resolved descriptor for " + parent.getId());
} else
bestMatchEnabled = true;
}
}
private void resolve() {
if (bestMatch != null) {
bestMatch.setEnabled(bestMatchEnabled);
if (bestMatchEnabled) {
if (DEBUG_RESOLVE)
debug("configured " + bestMatch.toString());
if (constraintList.size() > 0) {
for (int i = 0; i < constraintList.size(); i++) {
PluginPrerequisiteModel prq = (PluginPrerequisiteModel) ((Constraint) constraintList.get(i)).getPrerequisite();
prq.setResolvedVersion(getVersionIdentifier(bestMatch).toString());
}
}
}
}
}
private boolean isResolved() {
return this.isResolved;
}
private void isResolved(boolean isResolved) {
this.isResolved = isResolved;
}
}
// plugin descriptor index structure
private class IndexEntry {
private String id;
private List verList = new LinkedList();
private List concurrentList = new ArrayList();
private IndexEntry(String id) {
this.id = id;
concurrentList.add(new ConstraintsEntry(this));
}
private String getId() {
return id;
}
private ConstraintsEntry getConstraintsEntryFor(Constraint c) {
ConstraintsEntry ce = c.getConstraintsEntry();
if (ce != null)
return ce;
ce = (ConstraintsEntry) concurrentList.get(0);
if (c.getPrerequisite() == null)
c.setConstraintsEntry(ce);
return ce;
}
private PluginDescriptorModel addConstraint(Constraint c) {
int concurrentCount = concurrentList.size();
// try to find constraits entry that can accommodate new constraint
for (Iterator list = concurrentList.iterator(); list.hasNext();) {
ConstraintsEntry cie = (ConstraintsEntry) list.next();
PluginDescriptorModel pd = cie.addConstraint(c);
if (pd != null) {
// constraint added OK and no concurrency
if (concurrentCount <= 1)
return pd;
// constraint added OK but have concurrency
if (allowConcurrencyFor(pd))
return pd;
else {
cie.removeConstraint(c); // cannot be concurrent
return null;
}
}
}
// attempt to create new constraints entry
ConstraintsEntry cie;
PluginDescriptorModel pd;
if (concurrentList.size() == 1) {
// ensure base entry allows concurrency
cie = (ConstraintsEntry) concurrentList.get(0);
pd = cie.getMatchingDescriptor();
if (!allowConcurrencyFor(pd))
return null;
}
cie = new ConstraintsEntry(this);
pd = cie.addConstraint(c);
if (pd == null) {
cie.removeConstraint(c); // no matching target
return null;
}
if (!allowConcurrencyFor(pd)) {
cie.removeConstraint(c); // cannot be concurrent
return null;
}
if (DEBUG_RESOLVE)
debug("creating new constraints list in " + id + " for " + c.toString());
concurrentList.add(cie);
return pd;
}
private boolean allowConcurrencyFor(PluginDescriptorModel pd) {
if (pd == null)
return false;
if (pd.getDeclaredExtensions() != null && pd.getDeclaredExtensions().length > 0)
return false;
if (pd.getDeclaredExtensionPoints() != null && pd.getDeclaredExtensionPoints().length > 0)
return false;
return true;
}
private void removeConstraint(Constraint c) {
ConstraintsEntry cie = getConstraintsEntryFor(c);
cie.removeConstraint(c);
if (concurrentList.get(0) != cie && cie.constraintCount() == 0)
concurrentList.remove(cie);
}
private void removeConstraintFor(PluginPrerequisiteModel prereq) {
for (Iterator list = concurrentList.iterator(); list.hasNext();)
((ConstraintsEntry) list.next()).removeConstraintFor(prereq);
}
private PluginDescriptorModel getMatchingDescriptorFor(Constraint c) {
ConstraintsEntry cie = getConstraintsEntryFor(c);
return cie.getMatchingDescriptor();
}
private void disableAllDescriptors() {
for (Iterator list = verList.iterator(); list.hasNext();) {
PluginDescriptorModel pd = (PluginDescriptorModel) list.next();
pd.setEnabled(false);
}
}
private void resolveDependencies(List roots) {
for (Iterator list = concurrentList.iterator(); list.hasNext();)
((ConstraintsEntry) list.next()).preresolve(roots);
disableAllDescriptors();
for (Iterator list = concurrentList.iterator(); list.hasNext();)
((ConstraintsEntry) list.next()).resolve();
}
private List versions() {
return verList;
}
private boolean isResolvedFor(Constraint c) {
ConstraintsEntry cie = getConstraintsEntryFor(c);
return cie.isResolved();
}
private void isResolvedFor(Constraint c, boolean value) {
ConstraintsEntry cie = getConstraintsEntryFor(c);
cie.isResolved(value);
}
}
// subtree resolution "cookie" (composite change list)
private class Cookie {
private boolean ok = true;
private List changes = new ArrayList();
private Cookie() {
}
private boolean addChange(Constraint c) {
PluginPrerequisiteModel prereq = c.getPrerequisite();
for (Iterator list = changes.iterator(); list.hasNext();)
if (prereq == ((Constraint)list.next()).getPrerequisite())
return false; // prereq loop
changes.add(c);
return true;
}
private List getChanges() {
return changes;
}
private void clearChanges() {
if (changes.size() >= 0)
changes = new ArrayList();
}
private boolean isOk() {
return ok;
}
private void isOk(boolean value) {
ok = value;
}
}
public RegistryResolver() {
String debug = Platform.getDebugOption(OPTION_DEBUG_RESOLVE);
DEBUG_RESOLVE = debug==null ? false : ( debug.equalsIgnoreCase("true") ? true : false );
}
private void add(PluginDescriptorModel pd) {
String key = pd.getId();
List verList;
IndexEntry ix = (IndexEntry) idmap.get(key);
// create new index entry if one does not exist for plugin
if (ix == null) {
ix = new IndexEntry(key);
idmap.put(key, ix);
}
// insert plugin into list maintaining version order
verList = ix.versions();
int i = 0;
for (i = 0; i < verList.size(); i++) {
PluginDescriptorModel element = (PluginDescriptorModel) verList.get(i);
if (getVersionIdentifier(pd).equals(getVersionIdentifier(element)))
return; // ignore duplicates
if (getVersionIdentifier(pd).isGreaterThan(getVersionIdentifier(element)))
break;
}
verList.add(i, pd);
}
private void addAll(Collection c) {
for (Iterator list = c.iterator(); list.hasNext();)
add((PluginDescriptorModel) list.next());
}
private void addExtensions(ExtensionModel[] extensions, PluginDescriptorModel plugin) {
int extLength = extensions.length;
for (int i = 0; i < extLength; i++) {
extensions[i].setParentPluginDescriptor (plugin);
}
ExtensionModel[] list = plugin.getDeclaredExtensions();
int listLength = (list == null ? 0 : list.length);
ExtensionModel[] result = null;
if (list == null)
result = new ExtensionModel[extLength];
else {
result = new ExtensionModel[list.length + extLength];
System.arraycopy(list, 0, result, 0, list.length);
}
System.arraycopy(extensions, 0, result, listLength, extLength);
plugin.setDeclaredExtensions(result);
}
private void addExtensionPoints(ExtensionPointModel[] extensionPoints, PluginDescriptorModel plugin) {
int extPtLength = extensionPoints.length;
for (int i = 0; i < extPtLength; i++) {
extensionPoints[i].setParentPluginDescriptor (plugin);
}
ExtensionPointModel[] list = plugin.getDeclaredExtensionPoints();
int listLength = (list == null ? 0 : list.length);
ExtensionPointModel[] result = null;
if (list == null)
result = new ExtensionPointModel[extPtLength];
else {
result = new ExtensionPointModel[list.length + extPtLength];
System.arraycopy(list, 0, result, 0, list.length);
}
System.arraycopy(extensionPoints, 0, result, listLength, extPtLength);
plugin.setDeclaredExtensionPoints(result);
}
private void addLibraries(LibraryModel[] libraries, PluginDescriptorModel plugin) {
int libLength = libraries.length;
LibraryModel[] list = plugin.getRuntime();
LibraryModel[] result = null;
int listLength = (list == null ? 0 : list.length);
if (list == null)
result = new LibraryModel[libLength];
else {
result = new LibraryModel[list.length + libLength];
System.arraycopy(list, 0, result, 0, list.length);
}
System.arraycopy(libraries, 0, result, listLength, libLength);
plugin.setRuntime(result);
}
private void addPrerequisites(PluginPrerequisiteModel[] prerequisites, PluginDescriptorModel plugin) {
int reqLength = prerequisites.length;
PluginPrerequisiteModel[] list = plugin.getRequires();
PluginPrerequisiteModel[] result = null;
int listLength = (list == null ? 0 : list.length);
if (list == null)
result = new PluginPrerequisiteModel[reqLength];
else {
result = new PluginPrerequisiteModel[list.length + reqLength];
System.arraycopy(list, 0, result, 0, list.length);
}
System.arraycopy(prerequisites, 0, result, listLength, reqLength);
plugin.setRequires(result);
}
private void debug(String s) {
System.out.println("Registry Resolve: "+s);
}
private void error(String message) {
Status error = new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, message, null);
status.add(error);
if (InternalPlatform.DEBUG && DEBUG_RESOLVE)
System.out.println(error.toString());
}
public IExtensionPoint getExtensionPoint(PluginDescriptorModel plugin, String extensionPointId) {
if (extensionPointId == null)
return null;
ExtensionPointModel[] list = plugin.getDeclaredExtensionPoints();
if (list == null)
return null;
for (int i = 0; i < list.length; i++) {
if (extensionPointId.equals(list[i].getId()))
return (IExtensionPoint) list[i];
}
return null;
}
private PluginVersionIdentifier getVersionIdentifier(PluginDescriptorModel descriptor) {
String version = descriptor.getVersion();
if (version == null)
return new PluginVersionIdentifier("1.0.0");
try {
return new PluginVersionIdentifier(version);
} catch (Throwable e) {
return new PluginVersionIdentifier("1.0.0");
}
}
private PluginVersionIdentifier getVersionIdentifier(PluginPrerequisiteModel prereq) {
String version = prereq.getVersion();
return version == null ? null : new PluginVersionIdentifier(version);
}
private void linkFragments() {
/* For each fragment, find out which plugin descriptor it belongs
* to and add it to the list of fragments in this plugin.
*/
PluginFragmentModel[] fragments = reg.getFragments();
HashSet seen = new HashSet(5);
for (int i = 0; i < fragments.length; i++) {
PluginFragmentModel fragment = fragments[i];
if (!requiredFragment(fragment)) {
// There is a required field missing on this fragment, so
// ignore it.
String id, name;
if ((id = fragment.getId()) != null)
error (Policy.bind("parse.fragmentMissingAttr", id));
else if ((name = fragment.getName()) != null)
error (Policy.bind("parse.fragmentMissingAttr", name));
else
error (Policy.bind("parse.fragmentMissingIdName"));
continue;
}
if (seen.contains(fragment.getId()))
continue;
seen.add(fragment.getId());
PluginDescriptorModel plugin = reg.getPlugin(fragment.getPluginId(), fragment.getPluginVersion());
if (plugin == null) {
// We couldn't find this fragment's plugin
error (Policy.bind("parse.missingFragmentPd", fragment.getPluginId(), fragment.getId()));
continue;
}
// Soft prereq's ???
// PluginFragmentModel[] list = reg.getFragments(fragment.getId());
// resolvePluginFragments(list, plugin);
// Add this fragment to the list of fragments for this plugin descriptor
PluginFragmentModel[] list = plugin.getFragments();
PluginFragmentModel[] newList;
if (list == null) {
newList = new PluginFragmentModel[1];
newList[0] = fragment;
} else {
newList = new PluginFragmentModel[list.length + 1];
System.arraycopy(list, 0, newList, 0, list.length);
newList[list.length] = fragment;
}
plugin.setFragments(newList);
}
}
private void removeConstraintFor(PluginPrerequisiteModel prereq) {
String id = prereq.getPlugin();
IndexEntry ix = (IndexEntry) idmap.get(id);
if (ix == null) {
if (DEBUG_RESOLVE)
debug("unable to locate index entry for " + id);
return;
}
ix.removeConstraintFor(prereq);
}
private void resolve() {
// Add all the fragments to their associated plugin
linkFragments();
PluginDescriptorModel[] pluginList = reg.getPlugins();
for (int i = 0; i < pluginList.length; i++) {
if (pluginList[i].getFragments() != null) {
// Take all the information in each fragment and
// embed it in the plugin descriptor
resolvePluginFragments(pluginList[i]);
}
}
// Walk through the registry and ensure that all structures
// have all their 'required' fields. Do this now as
// the resolve assumes required field exist.
resolveRequiredComponents();
// resolve root descriptors
List rd = resolveRootDescriptors();
if (rd.size() == 0) {
// no roots ... quit
idmap = null;
reg = null;
error(Policy.bind("plugin.unableToResolve"));
return;
}
// sort roots
Object[] a = rd.toArray();
Arrays.sort(a);
ArrayList roots = new ArrayList(Arrays.asList(a));
// walk the dependencies and setup constraints
ArrayList orphans = new ArrayList();
for (int i = 0; i < roots.size(); i++)
resolveNode((String) roots.get(i), null, null, null, orphans);
for (int i = 0; i < orphans.size(); i++) {
if (!roots.contains(orphans.get(i))) {
roots.add(orphans.get(i));
if (DEBUG_RESOLVE)
debug("orphan " + orphans.get(i));
}
}
// resolve dependencies
Iterator plugins = idmap.entrySet().iterator();
while (plugins.hasNext()) {
IndexEntry ix = (IndexEntry) ((Map.Entry) plugins.next()).getValue();
ix.resolveDependencies(roots);
}
// walk down the registry structure and resolve links
resolvePluginRegistry();
// unhook registry and index
idmap = null;
reg = null;
}
public IStatus resolve(PluginRegistryModel registry) {
status = new MultiStatus(Platform.PI_RUNTIME, IStatus.OK, "", null);
if (registry.isResolved())
return status;
reg = registry;
idmap = new HashMap();
// Need to pick up the fragments before calling
// addAll. Currently we do this in resolve().
addAll(Arrays.asList(reg.getPlugins()));
resolve();
registry.markResolved();
return status;
}
private void resolveExtension(ExtensionModel ext) {
String target = ext.getExtensionPoint();
int ix = target.lastIndexOf(".");
String pluginId = target.substring(0, ix);
String extPtId = target.substring(ix + 1);
String message;
PluginDescriptorModel plugin = (PluginDescriptorModel) reg.getPlugin(pluginId);
if (plugin == null) {
message = Policy.bind("parse.extPointUnknown", target, ext.getParentPluginDescriptor().getId());
error(message);
return;
}
if (!plugin.getEnabled()) {
message = Policy.bind("parse.extPointDisabled", target, ext.getParentPluginDescriptor().getId());
error(message);
return;
}
ExtensionPointModel extPt = (ExtensionPointModel) getExtensionPoint(plugin, extPtId);
if (extPt == null) {
message = Policy.bind("parse.extPointUnknown", target, ext.getParentPluginDescriptor().getId());
error(message);
return;
}
ExtensionModel[] oldValues = extPt.getDeclaredExtensions();
ExtensionModel[] newValues = null;
if (oldValues == null)
newValues = new ExtensionModel[1];
else {
newValues = new ExtensionModel[oldValues.length + 1];
System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
}
newValues[newValues.length - 1] = ext;
extPt.setDeclaredExtensions(newValues);
}
private void resolveFragments() {
PluginFragmentModel[] fragments = reg.getFragments();
HashSet seen = new HashSet(5);
for (int i = 0; i < fragments.length; i++) {
PluginFragmentModel fragment = fragments[i];
if (!requiredFragment(fragment))
continue;
if (seen.contains(fragment.getId()))
continue;
seen.add(fragment.getId());
PluginDescriptorModel plugin = reg.getPlugin(fragment.getPluginId(), fragment.getPluginVersion());
if (plugin == null)
// XXX log something here?
continue;
PluginFragmentModel[] list = reg.getFragments(fragment.getId());
resolvePluginFragments(plugin);
}
}
private Cookie resolveNode(String child, PluginDescriptorModel parent, PluginPrerequisiteModel prq, Cookie cookie, List orphans) {
// This method is called recursively to setup dependency constraints.
// Top invocation is passed null parent and null prerequisite.
if (DEBUG_RESOLVE)
debug("PUSH> " + child);
if (cookie == null)
cookie = new Cookie();
// lookup child entry
IndexEntry ix = (IndexEntry) idmap.get(child);
if (ix == null) {
if (parent != null)
error(Policy.bind("parse.prereqDisabled", new String[] { parent.getId(), child }));
if (DEBUG_RESOLVE)
debug("<POP " + child + " not found");
cookie.isOk(false);
return cookie;
}
// try to add new dependency constraint
Constraint currentConstraint = new Constraint(parent, prq);
PluginDescriptorModel childPd = null;
if (parent != null) {
childPd = ix.addConstraint(currentConstraint);
if (childPd == null) {
String message = Policy.bind("parse.unsatisfiedPrereq", parent.getId(), child);
error(message);
if (DEBUG_RESOLVE)
debug("<POP " + child + " unable to satisfy constraint");
cookie.isOk(false);
return cookie;
} else
if (!cookie.addChange(currentConstraint)) {
String message = Policy.bind("parse.prereqLoop", parent.getId(), child);
error(message);
if (DEBUG_RESOLVE)
debug("<POP " + child + " prerequisite loop");
cookie.isOk(false);
return cookie;
}
} else {
childPd = ix.getMatchingDescriptorFor(currentConstraint);
if (childPd == null) {
if (DEBUG_RESOLVE)
debug("<POP " + child + " not found (missing descriptor entry)");
cookie.isOk(false);
return cookie;
}
}
// check to see if subtree is already resolved
if (ix.isResolvedFor(currentConstraint)) {
if (DEBUG_RESOLVE)
debug("<POP " + child + " already resolved");
return cookie;
}
// select the subtree to resolve
PluginPrerequisiteModel[] prereqs = childPd.getRequires();
PluginPrerequisiteModel prereq;
prereqs = prereqs == null ? new PluginPrerequisiteModel[0] : prereqs;
for (int i = 0; cookie.isOk() && i < prereqs.length; i++) {
prereq = (PluginPrerequisiteModel) prereqs[i];
cookie = resolveNode(prereq.getPlugin(), childPd, prereq, cookie, orphans);
}
// if we failed, remove any constraints we added
if (!cookie.isOk()) {
Constraint cookieConstraint;
for (Iterator change = cookie.getChanges().iterator(); change.hasNext();) {
cookieConstraint = (Constraint) change.next();
if (childPd == cookieConstraint.getParent()) {
prereq = cookieConstraint.getPrerequisite();
removeConstraintFor(prereq);
if (!orphans.contains(prereq.getPlugin())) // keep track of orphaned subtrees
orphans.add(prereq.getPlugin());
}
}
if (parent != null)
error(Policy.bind("parse.prereqDisabled", parent.getId(), child));
childPd.setEnabled(false);
if (DEBUG_RESOLVE)
debug("<POP " + child + " failed to resolve subtree");
return cookie;
} else {
// we're done
ix.isResolvedFor(currentConstraint, true);
if (DEBUG_RESOLVE)
debug("<POP " + child + " " + getVersionIdentifier(childPd));
return cookie;
}
}
private void resolvePluginDescriptor(PluginDescriptorModel pd) {
ExtensionModel[] list = pd.getDeclaredExtensions();
if (list == null || list.length == 0 || !pd.getEnabled())
// Can be disabled if all required attributes not present
return;
for (int i = 0; i < list.length; i++)
resolveExtension((ExtensionModel) list[i]);
}
private void resolvePluginFragment(PluginFragmentModel fragment, PluginDescriptorModel plugin) {
ExtensionModel[] extensions = fragment.getDeclaredExtensions();
if (extensions != null)
// Add all the fragment extensions to the plugin
addExtensions(extensions, plugin);
ExtensionPointModel[] points = fragment.getDeclaredExtensionPoints();
if (points != null)
// Add all the fragment extension points to the plugin
addExtensionPoints(points, plugin);
LibraryModel[] libraries = fragment.getRuntime();
if (libraries != null)
// Add all the fragment library entries to the plugin
addLibraries(libraries, plugin);
PluginPrerequisiteModel[] prerequisites = fragment.getRequires();
if (prerequisites != null)
// Add all the fragment prerequisites to the plugin
addPrerequisites(prerequisites, plugin);
}
private void resolvePluginFragments(PluginDescriptorModel plugin) {
/* For each fragment contained in the fragment list of this plugin,
* apply all the fragment bits to the plugin (e.g. all of the fragment's
* extensions are added to the list of extensions in the plugin). Be
* sure to use only the latest version of any given fragment (in case
* there are multiple versions of a given fragment id). So note that,
* if there are multiple versions of a given fragment id, all but the
* latest version will be discarded.
*/
PluginFragmentModel[] fragmentList = plugin.getFragments();
while (fragmentList != null) {
ArrayList fragmentsWithId = new ArrayList();
ArrayList fragmentsToProcessLater = new ArrayList();
String currentFragmentId = fragmentList[0].getId();
for (int i = 0; i < fragmentList.length; i++) {
// Find all the fragments with a given id.
if (currentFragmentId.equals(fragmentList[i].getId())) {
fragmentsWithId.add(fragmentList[i]);
} else {
fragmentsToProcessLater.add(fragmentList[i]);
}
}
PluginFragmentModel[] fragments;
if (fragmentsWithId.isEmpty())
fragments = null;
else
fragments = (PluginFragmentModel[]) fragmentsWithId.toArray(new PluginFragmentModel[fragmentsWithId.size()]);
if (fragmentsToProcessLater.isEmpty())
fragmentList = null;
else
fragmentList = (PluginFragmentModel[]) fragmentsToProcessLater.toArray(new PluginFragmentModel[fragmentsToProcessLater.size()]);
if (fragments != null) {
// Now find the latest version of the fragment with the chosen id
PluginFragmentModel latestFragment = null;
PluginVersionIdentifier latestVersion = null;
PluginVersionIdentifier targetVersion = new PluginVersionIdentifier(plugin.getVersion());
for (int i = 0; i < fragments.length; i++) {
PluginFragmentModel fragment = fragments[i];
PluginVersionIdentifier fragmentVersion = new PluginVersionIdentifier(fragment.getVersion());
PluginVersionIdentifier pluginVersion = new PluginVersionIdentifier(fragment.getPluginVersion());
if (pluginVersion.getMajorComponent() == targetVersion.getMajorComponent() && pluginVersion.getMinorComponent() == targetVersion.getMinorComponent())
if (latestFragment == null || fragmentVersion.isGreaterThan(latestVersion)) {
latestFragment = fragment;
latestVersion = fragmentVersion;
}
}
if (latestFragment != null) {
// For the latest version of this fragment id only, apply
// all the fragment bits to the plugin.
resolvePluginFragment(latestFragment, plugin);
}
}
}
}
private void resolvePluginRegistry() {
// filter out disabled plugins from "live" registry
if (trimPlugins)
trimRegistry();
// resolve relationships
if (crossLink) {
// cross link all of the extensions and extension points.
PluginDescriptorModel[] plugins = reg.getPlugins();
for (int i = 0; i < plugins.length; i++)
resolvePluginDescriptor(plugins[i]);
}
}
private void resolveRequiredComponents() {
PluginDescriptorModel[] pluginList = reg.getPlugins();
// Only worry about the enabled plugins as we are going
// to disable any plugins that don't have all the
// required bits.
for (int i = 0; i < pluginList.length; i++) {
if (pluginList[i].getEnabled()) {
if (!requiredPluginDescriptor(pluginList[i])) {
pluginList[i].setEnabled(false);
String id, name;
if ((id = pluginList[i].getId()) != null)
error (Policy.bind("parse.pluginMissingAttr", id));
else if ((name = pluginList[i].getName()) != null)
error (Policy.bind("parse.pluginMissingAttr", name));
else
error (Policy.bind("parse.pluginMissingIdName"));
}
}
}
// Don't worry about the fragments. They were done already.
}
private boolean requiredPluginDescriptor(PluginDescriptorModel plugin) {
boolean retValue = true;
retValue = plugin.getName() != null &&
plugin.getId() != null &&
plugin.getVersion() != null;
if (!retValue)
return retValue;
PluginPrerequisiteModel[] requiresList = plugin.getRequires();
ExtensionModel[] extensions = plugin.getDeclaredExtensions();
ExtensionPointModel[] extensionPoints = plugin.getDeclaredExtensionPoints();
LibraryModel[] libraryList = plugin.getRuntime();
PluginFragmentModel[] fragments = plugin.getFragments();
if (requiresList != null) {
for (int i = 0; i < requiresList.length && retValue; i++) {
retValue = retValue && requiredPrerequisite(requiresList[i]);
}
}
if (extensions != null) {
for (int i = 0; i < extensions.length && retValue; i++) {
retValue = retValue && requiredExtension(extensions[i]);
}
}
if (extensionPoints != null) {
for (int i = 0; i < extensionPoints.length && retValue; i++) {
retValue = retValue && requiredExtensionPoint(extensionPoints[i]);
}
}
if (libraryList != null) {
for (int i = 0; i < libraryList.length && retValue; i++) {
retValue = retValue && requiredLibrary(libraryList[i]);
}
}
if (fragments != null) {
for (int i = 0; i < fragments.length && retValue; i++) {
retValue = retValue && requiredFragment(fragments[i]);
}
}
return retValue;
}
private boolean requiredPrerequisite (PluginPrerequisiteModel prerequisite) {
return ((prerequisite.getPlugin() != null));
}
private boolean requiredExtension (ExtensionModel extension) {
return (extension.getExtensionPoint() != null);
}
private boolean requiredExtensionPoint (ExtensionPointModel extensionPoint) {
return ((extensionPoint.getName() != null) &&
(extensionPoint.getId() != null));
}
private boolean requiredLibrary (LibraryModel library) {
return (library.getName() != null);
}
private boolean requiredFragment (PluginFragmentModel fragment) {
return ((fragment.getName() != null) &&
(fragment.getId() != null) &&
(fragment.getPlugin() != null) &&
(fragment.getPluginVersion() != null) &&
(fragment.getVersion() != null));
}
private List resolveRootDescriptors() {
// Determine the roots of the dependency tree. Disable all
// but one versions of the root descriptors.
// get list of all plugin identifiers in the registry
List ids = new ArrayList();
ids.addAll(idmap.keySet());
// iterate over the list eliminating targets of <requires> entries
Iterator p = idmap.entrySet().iterator();
while (p.hasNext()) {
IndexEntry ix = (IndexEntry) ((Map.Entry) p.next()).getValue();
if (ix != null) {
List list = ix.versions();
if (list.size() > 0) {
PluginDescriptorModel pd = (PluginDescriptorModel) list.get(0);
PluginPrerequisiteModel[] prereqs = pd.getRequires();
for (int i = 0; prereqs != null && i < prereqs.length; i++) {
ids.remove(prereqs[i].getPlugin());
}
}
}
}
if (ids.size() > 0) {
// disable all but the most recent version of root descriptors
String id;
p = ids.iterator();
while (p.hasNext()) {
id = (String) p.next();
IndexEntry ix = (IndexEntry) idmap.get(id);
if (ix != null) {
List list = ix.versions();
for (int i = 0; i < list.size(); i++) {
PluginDescriptorModel pd = (PluginDescriptorModel) list.get(i);
if (i == 0) {
if (DEBUG_RESOLVE)
debug("root " + pd);
} else {
if (DEBUG_RESOLVE)
debug(" " + pd + " disabled");
pd.setEnabled(false);
}
}
}
}
} else {
if (DEBUG_RESOLVE)
debug("NO ROOTS");
}
return ids;
}
/**
* Specifies whether extensions and extension points should be cross
* linked during the resolve process.
*/
public void setCrossLink(boolean value) {
crossLink = value;
}
/**
* Specified whether disabled plugins should to be removed when the resolve
* is completed.
*/
public void setTrimPlugins(boolean value) {
trimPlugins = value;
}
private void trimRegistry() {
PluginDescriptorModel[] list = reg.getPlugins();
for (int i = 0; i < list.length; i++) {
PluginDescriptorModel pd = (PluginDescriptorModel) list[i];
if (!pd.getEnabled()) {
if (DEBUG_RESOLVE)
debug("removing " + pd.toString());
reg.removePlugin(pd.getId(), pd.getVersion());
}
}
}
}