KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > model > RegistryResolver


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.core.internal.model;
13
14 import java.util.*;
15 import org.eclipse.core.internal.runtime.InternalPlatform;
16 import org.eclipse.core.internal.runtime.Messages;
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.core.runtime.model.*;
19 import org.eclipse.osgi.util.NLS;
20
21 public class RegistryResolver {
22
23     private Map idmap;
24     private PluginRegistryModel reg;
25     private MultiStatus status;
26     private boolean trimPlugins = true;
27     private boolean crossLink = true;
28
29     private boolean DEBUG_RESOLVE = false;
30     private static final String JavaDoc OPTION_DEBUG_RESOLVE = "org.eclipse.core.runtime/registry/debug/resolve"; //$NON-NLS-1$
31

32     // constraint entry
33
// A constraint is made for each relationship where 'parent' requires 'prq'.
34
// ver is the version number we must try to match. It can be null if we just
35
// want to match the latest.
36
// cEntry points to the parent ConstraintsEntry element.
37
private class Constraint {
38         private PluginDescriptorModel parent;
39         private PluginPrerequisiteModel prq;
40         private PluginVersionIdentifier ver;
41         private byte type = PluginPrerequisiteModel.PREREQ_MATCH_UNSPECIFIED;
42         private ConstraintsEntry cEntry = null;
43
44         private Constraint(PluginDescriptorModel parent, PluginPrerequisiteModel prq) {
45             this.parent = parent;
46             this.prq = prq;
47             if (prq != null) {
48                 ver = RegistryResolver.this.getVersionIdentifier(prq);
49                 type = prq.getMatchByte();
50                 if ((ver != null) && (type == PluginPrerequisiteModel.PREREQ_MATCH_UNSPECIFIED))
51                     type = PluginPrerequisiteModel.PREREQ_MATCH_COMPATIBLE;
52             }
53         }
54
55         private int getMatchType() {
56             return type;
57         }
58
59         private ConstraintsEntry getConstraintsEntry() {
60             return cEntry;
61         }
62
63         private void setConstraintsEntry(ConstraintsEntry entry) {
64             cEntry = entry;
65         }
66
67         private PluginDescriptorModel getParent() {
68             return parent;
69         }
70
71         private PluginPrerequisiteModel getPrerequisite() {
72             return prq;
73         }
74
75         private PluginVersionIdentifier getVersionIdentifier() {
76             return ver;
77         }
78
79         public String JavaDoc toString() {
80             if (prq == null)
81                 return "(null)"; //$NON-NLS-1$
82
String JavaDoc s = parent.toString() + "->" + prq.getPlugin(); //$NON-NLS-1$
83
switch (prq.getMatchByte()) {
84                 case PluginPrerequisiteModel.PREREQ_MATCH_UNSPECIFIED :
85                     s += "(any)"; //$NON-NLS-1$
86
break;
87                 case PluginPrerequisiteModel.PREREQ_MATCH_PERFECT :
88                     s += IModel.PLUGIN_REQUIRES_MATCH_PERFECT;
89                     break;
90                 case PluginPrerequisiteModel.PREREQ_MATCH_EQUIVALENT :
91                     s += IModel.PLUGIN_REQUIRES_MATCH_EQUIVALENT;
92                     break;
93                 case PluginPrerequisiteModel.PREREQ_MATCH_COMPATIBLE :
94                     s += IModel.PLUGIN_REQUIRES_MATCH_COMPATIBLE;
95                     break;
96                 case PluginPrerequisiteModel.PREREQ_MATCH_GREATER_OR_EQUAL :
97                     s += IModel.PLUGIN_REQUIRES_MATCH_GREATER_OR_EQUAL;
98                     break;
99             }
100             return s;
101         }
102     }
103
104     // constraint index structure
105
// Each time an IndexEntry is created, a single ContraintsEntry
106
// is created and put into the IndexEntry's concurrentList.
107
// Note that the new ConstraintsEntry will always point
108
// back to the IndexEntry it is associated with (parent).
109
// A ConstraintsEntry holds a group of constraints that can be
110
// resolved, without conflict for a particular plugin id. The
111
// constraints are all of the form where another plugin id
112
// requires some version of this plugin id as a prerequisite.
113
private class ConstraintsEntry {
114         private IndexEntry parent;
115         private List constraintList = new LinkedList();
116         // lastResolved doesn't seem to be used. Is it designed to
117
// eliminate the numerous calls to find a matching plugin
118
// descriptor? Calls to find a matching plugin descriptor
119
// iterate through each version of this plugin and each
120
// constraint in each ConstraintsEntry.
121
private PluginDescriptorModel lastResolved = null;
122         private boolean isResolved = false;
123         private PluginDescriptorModel bestMatch = null;
124         private boolean bestMatchEnabled = false;
125
126         private ConstraintsEntry(IndexEntry parent) {
127             // Create a new ConstraintsEntry and point 'parent'
128
// back to the associated IndexEntry
129
this.parent = parent;
130         }
131
132         private int constraintCount() {
133             // Returns the number of Constraint entries in
134
// constraintList. Initially this will be 0.
135
return constraintList.size();
136         }
137
138         private PluginDescriptorModel addConstraint(Constraint c) {
139             // Add this Constraint to the list of constraints
140
// for this ConstraintsEntry. Note that while a
141
// given ConstraintsEntry can have many Constraints,
142
// any Constraint can have only one ConstraintsEntry.
143
// This method will return a single plugin descriptor which
144
// is the most recent descriptor which satisfies this
145
// constraint.
146
constraintList.add(c);
147             c.setConstraintsEntry(this);
148             // get all of the plugin descriptors which satisfy this
149
// constraint and all other constraints in this ConstraintsEntry
150
List constrained = getMatchingDescriptors();
151             if (constrained.size() <= 0) {
152                 // looks like we have a conflict
153
constraintList.remove(c);
154                 c.setConstraintsEntry(null);
155                 return null;
156             } else {
157                 // match will be only the latest version plugin which
158
// satisfies these constraints
159
PluginDescriptorModel match = (PluginDescriptorModel) constrained.get(0);
160                 if (!match.equals(lastResolved)) {
161                     lastResolved = match;
162                     isResolved = false;
163                 }
164                 return match;
165             }
166         }
167
168         private void removeConstraint(Constraint c) {
169             if (DEBUG_RESOLVE)
170                 debug("removing constraint " + c.toString()); //$NON-NLS-1$
171
constraintList.remove(c);
172             c.setConstraintsEntry(null);
173             lastResolved = null;
174             isResolved = false;
175         }
176
177         private void removeConstraintFor(PluginPrerequisiteModel prereq) {
178             List remove = new ArrayList();
179             for (Iterator list = constraintList.iterator(); list.hasNext();) {
180                 Constraint c = (Constraint) list.next();
181                 if (c.getPrerequisite() == prereq)
182                     remove.add(c);
183             }
184             for (Iterator list = remove.iterator(); list.hasNext();)
185                 removeConstraint((Constraint) list.next());
186         }
187
188         private PluginDescriptorModel getMatchingDescriptor() {
189             // We do this a lot. Can we use some mechanism to
190
// hold the last matching descriptor and discard
191
// it if the constraints change?
192
List constrained = getMatchingDescriptors();
193             if (constrained.size() <= 0)
194                 return null;
195             else
196                 return (PluginDescriptorModel) constrained.get(0);
197         }
198
199         private List getMatchingDescriptors() {
200             // The object of the game here is to return a list of plugin
201
// descriptors that match the list of Constraint elements
202
// hanging off this ConstraintsEntry.
203

204             // constrained will be a list of matching plugin descriptors
205
List constrained = new LinkedList();
206
207             for (Iterator list = parent.versions().iterator(); list.hasNext();) {
208                 // parent is an IndexEntry and versions is a list of all the
209
// plugin descriptors, in version order (biggest to smallest),
210
// that have this plugin id.
211
PluginDescriptorModel pd = (PluginDescriptorModel) list.next();
212                 if (pd.getEnabled())
213                     constrained.add(pd);
214             }
215             // constrained now contains all of the enabled plugin descriptors for
216
// this IndexEntry. The next step is to remove any that don't fit.
217

218             for (Iterator list = constraintList.iterator(); list.hasNext();) {
219                 // For each Constraint, go through all of the versions of this plugin
220
// and remove any from 'constrained' which don't match the criteria
221
// for this Constraint.
222

223                 // constraintList is all the Constraint entries for this ConstraintsEntry.
224
Constraint c = (Constraint) list.next();
225                 if (c.getMatchType() == PluginPrerequisiteModel.PREREQ_MATCH_UNSPECIFIED)
226                     continue;
227                 for (Iterator list2 = parent.versions().iterator(); list2.hasNext();) {
228                     PluginDescriptorModel pd = (PluginDescriptorModel) list2.next();
229                     if (!pd.getEnabled())
230                         // ignore disabled plugins
231
continue;
232                     switch (c.getMatchType()) {
233                         case PluginPrerequisiteModel.PREREQ_MATCH_PERFECT :
234                             if (!getVersionIdentifier(pd).isPerfect(c.getVersionIdentifier()))
235                                 constrained.remove(pd);
236                             break;
237                         case PluginPrerequisiteModel.PREREQ_MATCH_EQUIVALENT :
238                             if (!getVersionIdentifier(pd).isEquivalentTo(c.getVersionIdentifier()))
239                                 constrained.remove(pd);
240                             break;
241                         case PluginPrerequisiteModel.PREREQ_MATCH_COMPATIBLE :
242                             if (!getVersionIdentifier(pd).isCompatibleWith(c.getVersionIdentifier()))
243                                 constrained.remove(pd);
244                             break;
245                         case PluginPrerequisiteModel.PREREQ_MATCH_GREATER_OR_EQUAL :
246                             if (!getVersionIdentifier(pd).isGreaterOrEqualTo(c.getVersionIdentifier()))
247                                 constrained.remove(pd);
248                             break;
249                     }
250                 }
251             }
252
253             // At this point, constrained will contain only those plugin descriptors which
254
// satisfy ALL of the Constraint entries.
255

256             return constrained;
257         }
258
259         private void preresolve(List roots) {
260             // All of the constraints that need to be added, have been. Now just
261
// pick the plugin descriptor that is a best fit for all of these
262
// constraints. Root nodes will not have any constraints (since nothing
263
// requires this plugin as a prerequisite, by definition). For root
264
// node, just pick up the latest version.
265

266             if (constraintList.size() <= 0) {
267                 // This should be a root descriptor. So, just pick up the latest
268
// version of the root.
269
if (roots.contains(parent.getId())) {
270                     bestMatch = (PluginDescriptorModel) parent.versions().get(0);
271                     if (bestMatch == null) {
272                         if (DEBUG_RESOLVE)
273                             debug("*ERROR* no resolved descriptor for " + parent.getId()); //$NON-NLS-1$
274
} else
275                         bestMatchEnabled = bestMatch.getEnabled();
276                 }
277             } else {
278                 // If this isn't a root descriptor, get the latest version of the
279
// plugin descriptor which matches all the constraints we have.
280
// Pick the plugin that best matches all the constraints. Any
281
// allowable conflicts will be in another ConstraintsEntry.
282
bestMatch = getMatchingDescriptor();
283                 if (bestMatch == null) {
284                     if (DEBUG_RESOLVE)
285                         debug("*ERROR* no resolved descriptor for " + parent.getId()); //$NON-NLS-1$
286
} else
287                     bestMatchEnabled = true;
288             }
289         }
290
291         private void resolve() {
292             // Assumptions: All constraints that need to be added, have been.
293
// - preresolve (above) has been called and a bestMatch (if it
294
// exists) has been identified
295
// - all versions of this plugin have been disabled (so it is
296
// up to this method to enable the plugin that is a bestMatch
297
// for all of the constraints in this ConstraintsEntry).
298
if (bestMatch != null) {
299                 // All of the versions of this plugin will have been disabled.
300
// Enable only the one which is the best match.
301
// bestMatchEnabled will be set to false if this particular plugin
302
// caused an unresolvable conflict. Therefore, setEnabled(bestMatchEnabled)
303
// will leave this delinquent plugin disabled.
304
bestMatch.setEnabled(bestMatchEnabled);
305                 if (bestMatchEnabled) {
306                     if (DEBUG_RESOLVE)
307                         debug("configured " + bestMatch.toString()); //$NON-NLS-1$
308
if (constraintList.size() > 0) {
309                         for (int i = 0; i < constraintList.size(); i++) {
310                             // Put which actual version this prerequisite resolved to in the
311
// relevant prerequisite in the registry.
312
PluginPrerequisiteModel prq = (PluginPrerequisiteModel) ((Constraint) constraintList.get(i)).getPrerequisite();
313                             prq.setResolvedVersion(getVersionIdentifier(bestMatch).toString());
314                         }
315                     }
316                 }
317             }
318         }
319
320         private boolean isResolved() {
321             return this.isResolved;
322         }
323
324         private void isResolved(boolean isResolved) {
325             this.isResolved = isResolved;
326         }
327     }
328
329     // plugin descriptor index structure
330
// There is exactly one IndexEntry for each plugin id.
331
// The actual plugin descriptor is an element of verList.
332
// Multiple versions of this plugin id are found in verList
333
// and are ordered from the highest version number (assumed
334
// to be the most recent) to the lowest version number.
335
// concurrentList contains a list of ConstraintsEntry's which
336
// group constraints together into non-conflicting groups.
337
private class IndexEntry {
338         private String JavaDoc id;
339         private List verList = new LinkedList();
340         private List concurrentList = new ArrayList();
341
342         private IndexEntry(String JavaDoc id) {
343             this.id = id;
344             // Create the first ConstraintsEntry with no constraints
345
concurrentList.add(new ConstraintsEntry(this));
346         }
347
348         private String JavaDoc getId() {
349             return id;
350         }
351
352         private ConstraintsEntry getConstraintsEntryFor(Constraint c) {
353             // Each Constraint must have exactly one ConstraintsEntry but
354
// a ConstraintsEntry may have many (non-conflicting) Constraints.
355
ConstraintsEntry ce = c.getConstraintsEntry();
356             if (ce != null)
357                 return ce;
358             ce = (ConstraintsEntry) concurrentList.get(0);
359             if (c.getPrerequisite() == null)
360                 c.setConstraintsEntry(ce);
361             return ce;
362         }
363
364         private PluginDescriptorModel addConstraint(Constraint c) {
365             int concurrentCount = concurrentList.size();
366
367             // try to find constraits entry that can accommodate new constraint
368
for (Iterator list = concurrentList.iterator(); list.hasNext();) {
369                 ConstraintsEntry cie = (ConstraintsEntry) list.next();
370                 PluginDescriptorModel pd = cie.addConstraint(c);
371                 // If pd comes back null, adding this constraint to the
372
// ConstraintsEntry cie will cause a conflict (no plugin
373
// descriptor can satisfy all the constraints).
374
if (pd != null) {
375
376                     // constraint added OK and no concurrency
377
if (concurrentCount <= 1)
378                         return pd;
379
380                     // constraint added OK but have concurrency
381
if (allowConcurrencyFor(pd))
382                         return pd;
383                     else {
384                         cie.removeConstraint(c); // cannot be concurrent
385
return null;
386                     }
387                 }
388             }
389
390             // If we get to this point, the constraint we are trying to add
391
// gave us no matching plugins when used in conjunction with the
392
// other constraints in a particular ConstraintsEntry. Add a
393
// new ConstraintsEntry and put this constraint in it (only if
394
// concurrency is allowed). Concurrency is allowed only if the
395
// plugin we find which matches this constraint has no extensions
396
// or extension points.
397

398             // attempt to create new constraints entry
399
ConstraintsEntry cie;
400             PluginDescriptorModel pd;
401
402             if (concurrentList.size() == 1) {
403                 // ensure base entry allows concurrency
404
cie = (ConstraintsEntry) concurrentList.get(0);
405                 pd = cie.getMatchingDescriptor();
406                 if (!allowConcurrencyFor(pd))
407                     return null;
408             }
409
410             cie = new ConstraintsEntry(this);
411             pd = cie.addConstraint(c);
412             if (pd == null) {
413                 cie.removeConstraint(c); // no matching target
414
return null;
415             }
416             if (!allowConcurrencyFor(pd)) {
417                 cie.removeConstraint(c); // cannot be concurrent
418
return null;
419             }
420             if (DEBUG_RESOLVE)
421                 debug("creating new constraints list in " + id + " for " + c.toString()); //$NON-NLS-1$ //$NON-NLS-2$
422
concurrentList.add(cie);
423             return pd;
424         }
425
426         private boolean allowConcurrencyFor(PluginDescriptorModel pd) {
427             if (pd == null)
428                 return false;
429             if (pd.getDeclaredExtensions() != null && pd.getDeclaredExtensions().length > 0)
430                 return false;
431             if (pd.getDeclaredExtensionPoints() != null && pd.getDeclaredExtensionPoints().length > 0)
432                 return false;
433             return true;
434         }
435
436         private void removeConstraintFor(PluginPrerequisiteModel prereq) {
437             for (Iterator list = concurrentList.iterator(); list.hasNext();)
438                 ((ConstraintsEntry) list.next()).removeConstraintFor(prereq);
439         }
440
441         private PluginDescriptorModel getMatchingDescriptorFor(Constraint c) {
442             ConstraintsEntry cie = getConstraintsEntryFor(c);
443             return cie.getMatchingDescriptor();
444         }
445
446         private void disableAllDescriptors() {
447             for (Iterator list = verList.iterator(); list.hasNext();) {
448                 PluginDescriptorModel pd = (PluginDescriptorModel) list.next();
449                 pd.setEnabled(false);
450             }
451         }
452
453         private void resolveDependencies(List roots) {
454             // preresolved will pick out the plugin which has the highest version
455
// number and satisfies all the constraints. This is then put in
456
// bestMatch field of the ConstraintsEntry.
457
for (Iterator list = concurrentList.iterator(); list.hasNext();)
458                 ((ConstraintsEntry) list.next()).preresolve(roots);
459             // Now all versions of this plugin are disabled.
460
disableAllDescriptors();
461             // Now, find the best match (from preresolve above) and enable it.
462
// Be sure to update any prerequisite entries with the version number
463
// of the plugin we are actually using.
464
for (Iterator list = concurrentList.iterator(); list.hasNext();)
465                 ((ConstraintsEntry) list.next()).resolve();
466         }
467
468         /**
469          * A root plug-in does not have any constraints attached to it.
470          */

471         private boolean isRoot() {
472             if (concurrentList.size() != 1)
473                 return false;
474             ConstraintsEntry constraintsEntry = (ConstraintsEntry) concurrentList.get(0);
475             return constraintsEntry.constraintCount() == 0;
476         }
477
478         private List versions() {
479             return verList;
480         }
481
482         private boolean isResolvedFor(Constraint c) {
483             ConstraintsEntry cie = getConstraintsEntryFor(c);
484             return cie.isResolved();
485         }
486
487         private void isResolvedFor(Constraint c, boolean value) {
488             ConstraintsEntry cie = getConstraintsEntryFor(c);
489             cie.isResolved(value);
490         }
491
492     }
493
494     // subtree resolution "cookie" (composite change list)
495
private class Cookie {
496         private boolean ok = true;
497         private List changes = new ArrayList(); // a list of Constraints
498

499         private Cookie() {
500         }
501
502         private boolean addChange(Constraint c) {
503             // Keep a list of all constraints so that
504
// - we can spot circular dependencies
505
// - we can clean up if there is an unresolvable conflict
506
PluginPrerequisiteModel prereq = c.getPrerequisite();
507             for (Iterator list = changes.iterator(); list.hasNext();)
508                 if (prereq == ((Constraint) list.next()).getPrerequisite())
509                     // We have a circular dependency
510
return false;
511             changes.add(c);
512             return true;
513         }
514
515         private List getChanges() {
516             return changes;
517         }
518
519         private boolean isOk() {
520             return ok;
521         }
522
523         private void isOk(boolean value) {
524             ok = value;
525         }
526     }
527
528     public RegistryResolver() {
529         String JavaDoc debug = Platform.getDebugOption(OPTION_DEBUG_RESOLVE);
530         DEBUG_RESOLVE = debug == null ? false : (debug.equalsIgnoreCase("true") ? true : false); //$NON-NLS-1$
531
}
532
533     private void add(PluginDescriptorModel pd) {
534
535         String JavaDoc key = pd.getId();
536         List verList;
537         IndexEntry ix = (IndexEntry) idmap.get(key);
538
539         // create new index entry if one does not exist for plugin
540
if (ix == null) {
541             ix = new IndexEntry(key);
542             idmap.put(key, ix);
543         }
544
545         // insert plugin into list maintaining version order
546
verList = ix.versions();
547         int i = 0;
548         for (i = 0; i < verList.size(); i++) {
549             PluginDescriptorModel element = (PluginDescriptorModel) verList.get(i);
550             if (getVersionIdentifier(pd).equals(getVersionIdentifier(element)))
551                 return; // ignore duplicates
552
if (getVersionIdentifier(pd).isGreaterThan(getVersionIdentifier(element)))
553                 break;
554         }
555         verList.add(i, pd);
556     }
557
558     private void addExtensions(ExtensionModel[] extensions, PluginDescriptorModel plugin) {
559         // Add all the extensions (presumably from a fragment) to plugin
560
int extLength = extensions.length;
561         for (int i = 0; i < extLength; i++) {
562             extensions[i].setParentPluginDescriptor(plugin);
563         }
564         ExtensionModel[] list = plugin.getDeclaredExtensions();
565         int listLength = (list == null ? 0 : list.length);
566         ExtensionModel[] result = null;
567         if (list == null)
568             result = new ExtensionModel[extLength];
569         else {
570             result = new ExtensionModel[list.length + extLength];
571             System.arraycopy(list, 0, result, 0, list.length);
572         }
573         System.arraycopy(extensions, 0, result, listLength, extLength);
574         plugin.setDeclaredExtensions(result);
575     }
576
577     private void addExtensionPoints(ExtensionPointModel[] extensionPoints, PluginDescriptorModel plugin) {
578         // Add all the extension points (presumably from a fragment) to plugin
579
int extPtLength = extensionPoints.length;
580         for (int i = 0; i < extPtLength; i++) {
581             extensionPoints[i].setParentPluginDescriptor(plugin);
582         }
583         ExtensionPointModel[] list = plugin.getDeclaredExtensionPoints();
584         int listLength = (list == null ? 0 : list.length);
585         ExtensionPointModel[] result = null;
586         if (list == null)
587             result = new ExtensionPointModel[extPtLength];
588         else {
589             result = new ExtensionPointModel[list.length + extPtLength];
590             System.arraycopy(list, 0, result, 0, list.length);
591         }
592         System.arraycopy(extensionPoints, 0, result, listLength, extPtLength);
593         plugin.setDeclaredExtensionPoints(result);
594     }
595
596     private void addLibraries(LibraryModel[] libraries, PluginDescriptorModel plugin) {
597         // Add all the libraries (presumably from a fragment) to plugin
598
int libLength = libraries.length;
599         LibraryModel[] list = plugin.getRuntime();
600         LibraryModel[] result = null;
601         int listLength = (list == null ? 0 : list.length);
602         if (list == null)
603             result = new LibraryModel[libLength];
604         else {
605             result = new LibraryModel[list.length + libLength];
606             System.arraycopy(list, 0, result, 0, list.length);
607         }
608         System.arraycopy(libraries, 0, result, listLength, libLength);
609         plugin.setRuntime(result);
610     }
611
612     private void addPrerequisites(PluginPrerequisiteModel[] prerequisites, PluginDescriptorModel plugin) {
613         // Add all the prerequisites (presumably from a fragment) to plugin
614
int reqLength = prerequisites.length;
615         PluginPrerequisiteModel[] list = plugin.getRequires();
616         PluginPrerequisiteModel[] result = null;
617         int listLength = (list == null ? 0 : list.length);
618         if (list == null)
619             result = new PluginPrerequisiteModel[reqLength];
620         else {
621             result = new PluginPrerequisiteModel[list.length + reqLength];
622             System.arraycopy(list, 0, result, 0, list.length);
623         }
624         System.arraycopy(prerequisites, 0, result, listLength, reqLength);
625         plugin.setRequires(result);
626     }
627
628     private void debug(String JavaDoc s) {
629         System.out.println("Registry Resolve: " + s); //$NON-NLS-1$
630
}
631
632     private void error(String JavaDoc message) {
633         Status error = new Status(IStatus.WARNING, Platform.PI_RUNTIME, Platform.PARSE_PROBLEM, message, null);
634         status.add(error);
635         if (InternalPlatform.DEBUG && DEBUG_RESOLVE)
636             System.out.println(error.toString());
637     }
638
639     private void information(String JavaDoc message) {
640         if (InternalPlatform.DEBUG && DEBUG_RESOLVE)
641             System.out.println(message);
642     }
643
644     public IExtensionPoint getExtensionPoint(PluginDescriptorModel plugin, String JavaDoc extensionPointId) {
645         if (extensionPointId == null)
646             return null;
647         ExtensionPointModel[] list = plugin.getDeclaredExtensionPoints();
648         if (list == null)
649             return null;
650         for (int i = 0; i < list.length; i++) {
651             if (extensionPointId.equals(list[i].getId()))
652                 return (IExtensionPoint) list[i];
653         }
654         return null;
655     }
656
657     private PluginVersionIdentifier getVersionIdentifier(PluginModel model) {
658         try {
659             return new PluginVersionIdentifier(model.getVersion());
660         } catch (RuntimeException JavaDoc e) {
661             // if the version is invalid, an AssertionFailedException (not visible here) will be thrown
662
if (this.DEBUG_RESOLVE)
663                 // only show if we are debugging
664
e.printStackTrace(System.out);
665             // Hopefully, we will never get here. The version number
666
// has already been successfully converted from a string to
667
// a PluginVersionIdentifier and back to a string. But keep
668
// this catch around in case something does go wrong.
669
return new PluginVersionIdentifier(0, 0, 0);
670         }
671     }
672
673     private PluginVersionIdentifier getVersionIdentifier(PluginPrerequisiteModel prereq) {
674         String JavaDoc version = prereq.getVersion();
675         return version == null ? null : new PluginVersionIdentifier(version);
676     }
677
678     private boolean fragmentHasPrerequisites(PluginFragmentModel fragment) {
679         PluginPrerequisiteModel[] requires = fragment.getRequires();
680         if (requires == null || requires.length == 0)
681             return true;
682         for (int i = 0; i < requires.length; i++) {
683             // Use the idmap to determine if a plugin exists. We know
684
// that all plugins in this registry already have an entry
685
// in the idmap. If the right idmap entry doesn't exist,
686
// this plugin is not in the registry.
687
if (idmap.get(requires[i].getPlugin()) == null) {
688                 // We know this plugin doesn't exist
689
error(NLS.bind(Messages.parse_badPrereqOnFrag, fragment.getName(), requires[i].getPlugin()));
690                 return false;
691             }
692         }
693         return true;
694     }
695
696     private void linkFragments() {
697         /* For each fragment, find out which plugin descriptor it belongs
698          * to and add it to the list of fragments in this plugin.
699          */

700         PluginFragmentModel[] fragments = reg.getFragments();
701         for (int i = 0; i < fragments.length; i++) {
702             PluginFragmentModel fragment = fragments[i];
703             if (!requiredFragment(fragment)) {
704                 // There is a required field missing on this fragment, so
705
// ignore it.
706
String JavaDoc id, name;
707                 if ((id = fragment.getId()) != null)
708                     error(NLS.bind(Messages.parse_fragmentMissingAttr, id));
709                 else if ((name = fragment.getName()) != null)
710                     error(NLS.bind(Messages.parse_fragmentMissingAttr, name));
711                 else
712                     error(Messages.parse_fragmentMissingIdName);
713                 continue;
714             }
715             if (!fragmentHasPrerequisites(fragment)) {
716                 // This fragment requires a plugin that does not
717
// exist. Ignore the fragment.
718
continue;
719             }
720
721             // Now find a plugin that fits the matching criteria specified for this fragment and
722
// its related plugin
723
PluginDescriptorModel plugin = null;
724             IndexEntry ix = (IndexEntry) idmap.get(fragment.getPluginId());
725             byte matchType = fragment.getMatch();
726             if (ix != null) {
727                 for (Iterator list = ix.versions().iterator(); list.hasNext() && plugin == null;) {
728                     PluginDescriptorModel pd = (PluginDescriptorModel) list.next();
729                     if (pd.getEnabled()) {
730                         // return the highest version that fits the matching criteria
731
switch (matchType) {
732                             case PluginFragmentModel.FRAGMENT_MATCH_PERFECT :
733                                 if (getVersionIdentifier(pd).isPerfect(new PluginVersionIdentifier(fragment.getPluginVersion())))
734                                     plugin = pd;
735                                 break;
736                             case PluginFragmentModel.FRAGMENT_MATCH_EQUIVALENT :
737                                 if (getVersionIdentifier(pd).isEquivalentTo(new PluginVersionIdentifier(fragment.getPluginVersion())))
738                                     plugin = pd;
739                                 break;
740                             case PluginFragmentModel.FRAGMENT_MATCH_COMPATIBLE :
741                             case PluginFragmentModel.FRAGMENT_MATCH_UNSPECIFIED :
742                                 if (getVersionIdentifier(pd).isCompatibleWith(new PluginVersionIdentifier(fragment.getPluginVersion())))
743                                     plugin = pd;
744                                 break;
745                             case PluginFragmentModel.FRAGMENT_MATCH_GREATER_OR_EQUAL :
746                                 if (getVersionIdentifier(pd).isGreaterOrEqualTo(new PluginVersionIdentifier(fragment.getPluginVersion())))
747                                     plugin = pd;
748                                 break;
749                         }
750                     }
751                 }
752             }
753
754             if (plugin == null) {
755                 // We couldn't find this fragment's plugin
756
error(NLS.bind(Messages.parse_missingFragmentPd, fragment.getPluginId(), fragment.getId()));
757                 continue;
758             }
759
760             // Add this fragment to the list of fragments for this plugin descriptor
761
PluginFragmentModel[] list = plugin.getFragments();
762             PluginFragmentModel[] newList;
763             if (list == null) {
764                 newList = new PluginFragmentModel[1];
765                 newList[0] = fragment;
766             } else {
767                 newList = new PluginFragmentModel[list.length + 1];
768                 System.arraycopy(list, 0, newList, 0, list.length);
769                 newList[list.length] = fragment;
770             }
771             plugin.setFragments(newList);
772         }
773     }
774
775     private void removeConstraintFor(PluginPrerequisiteModel prereq) {
776
777         String JavaDoc id = prereq.getPlugin();
778         IndexEntry ix = (IndexEntry) idmap.get(id);
779         if (ix == null) {
780             if (DEBUG_RESOLVE)
781                 debug("unable to locate index entry for " + id); //$NON-NLS-1$
782
return;
783         }
784         ix.removeConstraintFor(prereq);
785     }
786
787     private void resolve() {
788
789         // Start by putting each plugin in the idmap. We are
790
// going to need this for the call to linkFragments.
791
PluginDescriptorModel[] pluginList = reg.getPlugins();
792         idmap = new HashMap();
793         for (int i = 0; i < pluginList.length; i++) {
794             // Check to see if all the required fields exist now.
795
// For example, if we have a null plugin version identifier,
796
// the add(pluginList[i]) will give a null pointer
797
// exception.
798
if (!requiredPluginDescriptor(pluginList[i])) {
799                 pluginList[i].setEnabled(false);
800                 String JavaDoc id, name;
801                 if ((id = pluginList[i].getId()) != null)
802                     error(NLS.bind(Messages.parse_pluginMissingAttr, id));
803                 else if ((name = pluginList[i].getName()) != null)
804                     error(NLS.bind(Messages.parse_pluginMissingAttr, name));
805                 else
806                     error(Messages.parse_pluginMissingIdName);
807                 continue;
808             }
809             add(pluginList[i]);
810         }
811         // Add all the fragments to their associated plugin.
812
// Note that this will check for all the required fields in
813
// the fragment.
814
linkFragments();
815         // Now we have to cycle through the plugin list again
816
// to assimilate all the fragment information and
817
// check for 'required' fields.
818
for (int i = 0; i < pluginList.length; i++) {
819             if (pluginList[i].getFragments() != null) {
820                 // Take all the information in each fragment and
821
// embed it in the plugin descriptor
822
resolvePluginFragments(pluginList[i]);
823             }
824         }
825
826         // resolve root descriptors
827
List roots = resolveRootDescriptors();
828
829         if (roots.size() == 0) {
830             // No roots, likely due to a circular dependency
831
// (or multiple circular dependencies). Disable
832
// all plugins before returning. Remember to trim
833
// the registry if needed.
834
PluginDescriptorModel[] plugins = reg.getPlugins();
835             for (int i = 0; i < plugins.length; i++) {
836                 plugins[i].setEnabled(false);
837             }
838             resolvePluginRegistry();
839             idmap = null;
840             reg = null;
841             error(Messages.plugin_unableToResolve);
842             return;
843         }
844
845         // roots is a list of those plugin ids that are not a
846
// prerequisite for any other plugin. Note that roots
847
// contains ids only.
848

849         // process all root nodes (first those previously on roots list, then those on the orphans set)
850
// The orphans of an iteration will become the roots of the next one.
851
for (Set orphans, rootsSet = new HashSet(roots); !rootsSet.isEmpty(); rootsSet = orphans) {
852             orphans = new HashSet();
853             // walk the dependencies and setup constraints
854
for (Iterator rootsIter = rootsSet.iterator(); rootsIter.hasNext();) {
855                 String JavaDoc rootID = (String JavaDoc) rootsIter.next();
856                 resolveNode(rootID, null, null, null, orphans);
857                 // At this point we have set up all the Constraint and
858
// ConstraintsEntry components. But we may not have found which
859
// plugin is the best match for a given set of constraints.
860
}
861             // build the roots set for the next iteration
862
for (Iterator orphansIter = orphans.iterator(); orphansIter.hasNext();) {
863                 IndexEntry orphan = (IndexEntry) idmap.get(orphansIter.next());
864                 // only after a complete iteration over the roots set we can decide if
865
// a potential orphan is a real orphan
866
// Now we need to resolve for these new roots (they may
867
// not have been resolved before, especially if the parent
868
// was looking for an older version and not the latest
869
// version which is what we pick up for the roots).
870
if (orphan.isRoot()) {
871                     if (DEBUG_RESOLVE)
872                         debug("orphan " + orphan.getId()); //$NON-NLS-1$
873
roots.add(orphan.getId());
874                 } else
875                     orphansIter.remove();
876             }
877         }
878
879         // resolve dependencies
880
Iterator plugins = idmap.entrySet().iterator();
881         while (plugins.hasNext()) {
882             IndexEntry ix = (IndexEntry) ((Map.Entry) plugins.next()).getValue();
883             // Now go off and find the plugin that matches the
884
// constraints. Note that root plugins will always use the
885
// latest version.
886
ix.resolveDependencies(roots);
887         }
888
889         // walk down the registry structure and resolve links
890
// between extensions and extension points
891
resolvePluginRegistry();
892
893         // unhook registry and index
894
idmap = null;
895         reg = null;
896     }
897
898     public IStatus resolve(PluginRegistryModel registry) {
899         // This is the entry point to the registry resolver.
900
// Calling this method, with a valid registry will
901
// cause this registry to be 'resolved'.
902

903         status = new MultiStatus(Platform.PI_RUNTIME, IStatus.OK, "", null); //$NON-NLS-1$
904

905         if (registry.isResolved())
906             // don't bother doing anything if it's already resolved
907
return status;
908
909         reg = registry;
910         resolve();
911         registry.markResolved();
912         return status;
913     }
914
915     private void resolveExtension(ExtensionModel ext) {
916
917         String JavaDoc target = ext.getExtensionPoint();
918         int ix = target.lastIndexOf("."); //$NON-NLS-1$
919
String JavaDoc pluginId = target.substring(0, ix);
920         String JavaDoc extPtId = target.substring(ix + 1);
921         String JavaDoc message;
922
923         PluginDescriptorModel plugin = (PluginDescriptorModel) reg.getPlugin(pluginId);
924         if (plugin == null) {
925             message = NLS.bind(Messages.parse_extPointUnknown, target, ext.getParentPluginDescriptor().getId());
926             error(message);
927             return;
928         }
929         if (!plugin.getEnabled()) {
930             message = NLS.bind(Messages.parse_extPointDisabled, target, ext.getParentPluginDescriptor().getId());
931             error(message);
932             return;
933         }
934
935         ExtensionPointModel extPt = (ExtensionPointModel) getExtensionPoint(plugin, extPtId);
936         if (extPt == null) {
937             message = NLS.bind(Messages.parse_extPointUnknown, target, ext.getParentPluginDescriptor().getId());
938             error(message);
939             return;
940         }
941
942         ExtensionModel[] oldValues = extPt.getDeclaredExtensions();
943         ExtensionModel[] newValues = null;
944         if (oldValues == null)
945             newValues = new ExtensionModel[1];
946         else {
947             newValues = new ExtensionModel[oldValues.length + 1];
948             System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
949         }
950         newValues[newValues.length - 1] = ext;
951         extPt.setDeclaredExtensions(newValues);
952     }
953
954     private Cookie resolveNode(String JavaDoc child, PluginDescriptorModel parent, PluginPrerequisiteModel prq, Cookie cookie, Set orphans) {
955         // This method is called recursively to setup dependency constraints.
956
// Top invocation is passed null parent and null prerequisite.
957
// We are trying to resolve for the plugin descriptor with id 'child'.
958

959         if (DEBUG_RESOLVE)
960             debug("PUSH> " + child); //$NON-NLS-1$
961

962         if (cookie == null)
963             cookie = new Cookie();
964
965         // lookup child entry
966
IndexEntry ix = (IndexEntry) idmap.get(child);
967         // We should now have the IndexEntry for the plugin we
968
// wish to resolve
969
if (ix == null) {
970             // If this is an optional prerequisite and not a root
971
// node, we can just ignore this prerequisite if there
972
// is no IndexEntry (as there is no corresponding plugin)
973
// and continue processing.
974
if (prq.getOptional() && parent != null && child != null)
975                 return cookie;
976             if (parent != null)
977                 error(NLS.bind(Messages.parse_prereqDisabled, parent.getId(), child));
978             if (DEBUG_RESOLVE)
979                 debug("<POP " + child + " not found"); //$NON-NLS-1$ //$NON-NLS-2$
980
cookie.isOk(false);
981             return cookie;
982         }
983
984         // try to add new dependency constraint
985
Constraint currentConstraint = new Constraint(parent, prq);
986         // A constraint will be added for each parent which requires us.
987
PluginDescriptorModel childPd = null;
988         if (parent != null) {
989             childPd = ix.addConstraint(currentConstraint);
990             if (childPd == null) {
991                 if (prq.getOptional()) {
992                     // This is an optional prerequisite. Ignore the conflict and this
993
// prerequisite.
994
orphans.add(ix.getId());
995                     information(NLS.bind(Messages.parse_unsatisfiedOptPrereq, parent.getId(), child));
996                     return cookie;
997                 } else {
998                     // This prerequisite is mandatory.
999
String JavaDoc message = NLS.bind(Messages.parse_unsatisfiedPrereq, parent.getId(), child);
1000                    error(message);
1001                    if (DEBUG_RESOLVE)
1002                        debug("<POP " + child + " unable to satisfy constraint"); //$NON-NLS-1$ //$NON-NLS-2$
1003
cookie.isOk(false);
1004                    return cookie;
1005                }
1006            } else if (!cookie.addChange(currentConstraint)) {
1007                if (prq.getOptional()) {
1008                    // This is an optional prerequisite. Ignore the loop, and the
1009
// prerequisite
1010
information(NLS.bind(Messages.parse_prereqOptLoop, parent.getId(), child));
1011                    return cookie;
1012                } else {
1013                    String JavaDoc message = NLS.bind(Messages.parse_prereqLoop, parent.getId(), child);
1014                    error(message);
1015                    if (DEBUG_RESOLVE)
1016                        debug("<POP " + child + " prerequisite loop"); //$NON-NLS-1$ //$NON-NLS-2$
1017
cookie.isOk(false);
1018                    return cookie;
1019                }
1020            }
1021        } else {
1022            // This is a root node. There is no prerequisite so this IndexEntry must
1023
// exist
1024
childPd = ix.getMatchingDescriptorFor(currentConstraint);
1025            if (childPd == null) {
1026                if (DEBUG_RESOLVE)
1027                    debug("<POP " + child + " not found (missing descriptor entry)"); //$NON-NLS-1$ //$NON-NLS-2$
1028
cookie.isOk(false);
1029                return cookie;
1030            }
1031        }
1032
1033        // check to see if subtree is already resolved
1034
if (ix.isResolvedFor(currentConstraint)) {
1035            if (DEBUG_RESOLVE)
1036                debug("<POP " + child + " already resolved"); //$NON-NLS-1$ //$NON-NLS-2$
1037
return cookie;
1038        }
1039
1040        // select the subtree to resolve
1041
PluginPrerequisiteModel[] prereqs = childPd.getRequires();
1042        PluginPrerequisiteModel prereq;
1043        prereqs = prereqs == null ? new PluginPrerequisiteModel[0] : prereqs;
1044        for (int i = 0; cookie.isOk() && i < prereqs.length; i++) {
1045            prereq = (PluginPrerequisiteModel) prereqs[i];
1046            cookie = resolveNode(prereq.getPlugin(), childPd, prereq, cookie, orphans);
1047        }
1048
1049        // if we failed, remove any constraints we added
1050
if (!cookie.isOk()) {
1051            Constraint cookieConstraint;
1052            for (Iterator change = cookie.getChanges().iterator(); change.hasNext();) {
1053                cookieConstraint = (Constraint) change.next();
1054                prereq = cookieConstraint.getPrerequisite();
1055                if (childPd == cookieConstraint.getParent()) {
1056                    // keep track of orphaned subtrees
1057
if (!orphans.contains(prereq.getPlugin()) && (idmap.get(prereq.getPlugin()) != null))
1058                        orphans.add(prereq.getPlugin());
1059                }
1060                removeConstraintFor(prereq);
1061            }
1062            // Make sure you picked up all the orphaned subtrees
1063
// for this childPd
1064
for (int i = 0; i < prereqs.length; i++) {
1065                if (!orphans.contains(prereqs[i].getPlugin()) && (idmap.get(prereqs[i].getPlugin()) != null))
1066                    orphans.add(prereqs[i].getPlugin());
1067            }
1068            if (parent != null)
1069                error(NLS.bind(Messages.parse_prereqDisabled, parent.getId(), child));
1070            childPd.setEnabled(false);
1071            if (DEBUG_RESOLVE)
1072                debug("<POP " + child + " failed to resolve subtree"); //$NON-NLS-1$ //$NON-NLS-2$
1073
return cookie;
1074        } else {
1075            // we're done
1076
ix.isResolvedFor(currentConstraint, true);
1077            if (DEBUG_RESOLVE)
1078                debug("<POP " + child + " " + getVersionIdentifier(childPd)); //$NON-NLS-1$ //$NON-NLS-2$
1079
return cookie;
1080        }
1081    }
1082
1083    private void resolvePluginDescriptor(PluginDescriptorModel pd) {
1084        ExtensionModel[] list = pd.getDeclaredExtensions();
1085        if (list == null || list.length == 0 || !pd.getEnabled())
1086            // Can be disabled if all required attributes not present
1087
return;
1088        for (int i = 0; i < list.length; i++)
1089            resolveExtension((ExtensionModel) list[i]);
1090    }
1091
1092    private void resolvePluginFragment(PluginFragmentModel fragment, PluginDescriptorModel plugin) {
1093        ExtensionModel[] extensions = fragment.getDeclaredExtensions();
1094        if (extensions != null)
1095            // Add all the fragment extensions to the plugin
1096
addExtensions(extensions, plugin);
1097
1098        ExtensionPointModel[] points = fragment.getDeclaredExtensionPoints();
1099        if (points != null)
1100            // Add all the fragment extension points to the plugin
1101
addExtensionPoints(points, plugin);
1102
1103        LibraryModel[] libraries = fragment.getRuntime();
1104        if (libraries != null)
1105            // Add all the fragment library entries to the plugin
1106
addLibraries(libraries, plugin);
1107
1108        PluginPrerequisiteModel[] prerequisites = fragment.getRequires();
1109        if (prerequisites != null)
1110            // Add all the fragment prerequisites to the plugin
1111
addPrerequisites(prerequisites, plugin);
1112    }
1113
1114    private void resolvePluginFragments(PluginDescriptorModel plugin) {
1115        /* For each fragment contained in the fragment list of this plugin,
1116         * apply all the fragment bits to the plugin (e.g. all of the fragment's
1117         * extensions are added to the list of extensions in the plugin). Be
1118         * sure to use only the latest version of any given fragment (in case
1119         * there are multiple versions of a given fragment id). So note that,
1120         * if there are multiple versions of a given fragment id, all but the
1121         * latest version will be discarded.
1122         */

1123
1124        // The boolean 'dirty' will remain false if there is only one
1125
// version of every fragment id associated with this plugin
1126
boolean dirty = false;
1127
1128        PluginFragmentModel[] fragmentList = plugin.getFragments();
1129        HashMap latestFragments = new HashMap(30);
1130        for (int i = 0; i < fragmentList.length; i++) {
1131            String JavaDoc fragmentId = fragmentList[i].getId();
1132            PluginFragmentModel latestVersion = (PluginFragmentModel) latestFragments.get(fragmentId);
1133            if (latestVersion == null) {
1134                // We don't have any fragments with this id yet
1135
latestFragments.put(fragmentId, fragmentList[i]);
1136            } else {
1137                dirty = true;
1138                if (getVersionIdentifier(fragmentList[i]).equals(getVersionIdentifier(latestVersion)))
1139                    // ignore duplicates
1140
error(NLS.bind(Messages.parse_duplicateFragment, fragmentId, fragmentList[i].getVersion()));
1141                if (getVersionIdentifier(fragmentList[i]).isGreaterThan(getVersionIdentifier(latestVersion))) {
1142                    latestFragments.put(fragmentId, fragmentList[i]);
1143                }
1144            }
1145        }
1146
1147        // latestFragments now contains the latest version of each fragment
1148
// id for this plugin
1149

1150        // Now add the latest version of each fragment to the plugin
1151
Set latestOnly = new HashSet();
1152        for (Iterator list = latestFragments.values().iterator(); list.hasNext();) {
1153            PluginFragmentModel latestFragment = (PluginFragmentModel) list.next();
1154            if (dirty)
1155                latestOnly.add(latestFragment);
1156            int numLibraries = latestFragment.getRuntime() == null ? 0 : latestFragment.getRuntime().length;
1157            resolvePluginFragment(latestFragment, plugin);
1158            // If this fragment added library entries, check to see if it
1159
// added a duplicate library entry.
1160
if (numLibraries != 0) {
1161                // Something got added
1162
LibraryModel[] libraries = plugin.getRuntime();
1163                // Put all the library names into a set as we know the set will not
1164
// have any duplicates.
1165
Set libNames = new HashSet();
1166                int setSize = libNames.size();
1167                for (int i = 0; i < libraries.length; i++) {
1168                    libNames.add(libraries[i].getName());
1169                    if (libNames.size() == setSize) {
1170                        // We know this library name didn't get added to the set.
1171
// Ignore the duplicate but indicate an error
1172
String JavaDoc[] bindings = {latestFragment.getId(), plugin.getId(), libraries[i].getName()};
1173                        error(NLS.bind(Messages.parse_duplicateLib, bindings));
1174                    } else {
1175                        setSize = libNames.size();
1176                    }
1177                }
1178            }
1179        }
1180        // Currently the fragments on the plugin include all fragment
1181
// versions. Now strip off all but the latest version of each
1182
// fragment id (only if necessary).
1183
if (dirty)
1184            plugin.setFragments((PluginFragmentModel[]) latestOnly.toArray(new PluginFragmentModel[latestOnly.size()]));
1185
1186    }
1187
1188    private void resolvePluginRegistry() {
1189        // filter out disabled plugins from "live" registry
1190
if (trimPlugins)
1191            trimRegistry();
1192
1193        // resolve relationships
1194
if (crossLink) {
1195            // cross link all of the extensions and extension points.
1196
PluginDescriptorModel[] plugins = reg.getPlugins();
1197            for (int i = 0; i < plugins.length; i++)
1198                resolvePluginDescriptor(plugins[i]);
1199        }
1200    }
1201
1202    private boolean requiredPluginDescriptor(PluginDescriptorModel plugin) {
1203        boolean retValue = true;
1204        retValue = plugin.getName() != null && plugin.getId() != null && plugin.getVersion() != null;
1205        if (!retValue)
1206            return retValue;
1207
1208        PluginPrerequisiteModel[] requiresList = plugin.getRequires();
1209        ExtensionModel[] extensions = plugin.getDeclaredExtensions();
1210        ExtensionPointModel[] extensionPoints = plugin.getDeclaredExtensionPoints();
1211        LibraryModel[] libraryList = plugin.getRuntime();
1212        PluginFragmentModel[] fragments = plugin.getFragments();
1213
1214        if (requiresList != null) {
1215            for (int i = 0; i < requiresList.length && retValue; i++) {
1216                retValue = retValue && requiredPrerequisite(requiresList[i]);
1217            }
1218        }
1219        if (extensions != null) {
1220            for (int i = 0; i < extensions.length && retValue; i++) {
1221                retValue = retValue && requiredExtension(extensions[i]);
1222            }
1223        }
1224        if (extensionPoints != null) {
1225            for (int i = 0; i < extensionPoints.length && retValue; i++) {
1226                retValue = retValue && requiredExtensionPoint(extensionPoints[i]);
1227            }
1228        }
1229        if (libraryList != null) {
1230            for (int i = 0; i < libraryList.length && retValue; i++) {
1231                retValue = retValue && requiredLibrary(libraryList[i]);
1232            }
1233        }
1234        if (fragments != null) {
1235            for (int i = 0; i < fragments.length && retValue; i++) {
1236                retValue = retValue && requiredFragment(fragments[i]);
1237            }
1238        }
1239
1240        return retValue;
1241    }
1242
1243    private boolean requiredPrerequisite(PluginPrerequisiteModel prerequisite) {
1244        return ((prerequisite.getPlugin() != null));
1245    }
1246
1247    private boolean requiredExtension(ExtensionModel extension) {
1248        return (extension.getExtensionPoint() != null);
1249    }
1250
1251    private boolean requiredExtensionPoint(ExtensionPointModel extensionPoint) {
1252        return ((extensionPoint.getName() != null) && (extensionPoint.getId() != null));
1253    }
1254
1255    private boolean requiredLibrary(LibraryModel library) {
1256        return (library.getName() != null);
1257    }
1258
1259    private boolean requiredFragment(PluginFragmentModel fragment) {
1260        return ((fragment.getName() != null) && (fragment.getId() != null) && (fragment.getPlugin() != null) && (fragment.getPluginVersion() != null) && (fragment.getVersion() != null));
1261    }
1262
1263    private List resolveRootDescriptors() {
1264
1265        // Determine the roots of the dependency tree. Disable all
1266
// but one versions of the root descriptors.
1267

1268        // get list of all plugin identifiers in the registry
1269
List ids = new ArrayList();
1270        ids.addAll(idmap.keySet());
1271
1272        // ids is just a list of all the plugin id's
1273
// The following while loop will remove all id's that
1274
// appear in any prerequisite list.
1275

1276        // iterate over the list eliminating targets of <requires> entries
1277
Iterator p = idmap.entrySet().iterator();
1278        while (p.hasNext()) {
1279            IndexEntry ix = (IndexEntry) ((Map.Entry) p.next()).getValue();
1280            if (ix != null) {
1281                List list = ix.versions();
1282                int ixSize = list.size();
1283                if (ixSize > 0) {
1284                    // Remove any prerequisite mentioned in any version of this plugin
1285
for (int i = 0; i < ixSize; i++) {
1286                        PluginDescriptorModel pd = (PluginDescriptorModel) list.get(i);
1287                        PluginPrerequisiteModel[] prereqs = pd.getRequires();
1288                        for (int j = 0; prereqs != null && j < prereqs.length; j++) {
1289                            ids.remove(prereqs[j].getPlugin());
1290                        }
1291                    }
1292                }
1293            }
1294        }
1295
1296        if (ids.size() > 0) {
1297            // disable all but the most recent version of root descriptors
1298
String JavaDoc id;
1299            p = ids.iterator();
1300            while (p.hasNext()) {
1301                id = (String JavaDoc) p.next();
1302                IndexEntry ix = (IndexEntry) idmap.get(id);
1303                if (ix != null) {
1304                    List list = ix.versions();
1305                    for (int i = 0; i < list.size(); i++) {
1306                        PluginDescriptorModel pd = (PluginDescriptorModel) list.get(i);
1307                        if (i == 0) {
1308                            // Don't disable this one. It is the
1309
// one with the highest version number.
1310
if (DEBUG_RESOLVE)
1311                                debug("root " + pd); //$NON-NLS-1$
1312
} else {
1313                            // Disable all versions except the one with the
1314
// highest version number.
1315
if (DEBUG_RESOLVE)
1316                                debug(" " + pd + " disabled"); //$NON-NLS-1$ //$NON-NLS-2$
1317
pd.setEnabled(false);
1318                        }
1319                    }
1320                }
1321            }
1322        } else {
1323            if (DEBUG_RESOLVE)
1324                debug("NO ROOTS"); //$NON-NLS-1$
1325
}
1326
1327        return ids;
1328    }
1329
1330    /**
1331     * Specifies whether extensions and extension points should be cross
1332     * linked during the resolve process.
1333     */

1334    public void setCrossLink(boolean value) {
1335        crossLink = value;
1336    }
1337
1338    /**
1339     * Specified whether disabled plugins should to be removed when the resolve
1340     * is completed.
1341     */

1342    public void setTrimPlugins(boolean value) {
1343        trimPlugins = value;
1344    }
1345
1346    private void trimRegistry() {
1347        PluginDescriptorModel[] list = reg.getPlugins();
1348        for (int i = 0; i < list.length; i++) {
1349            PluginDescriptorModel pd = (PluginDescriptorModel) list[i];
1350            if (!pd.getEnabled()) {
1351                if (DEBUG_RESOLVE)
1352                    debug("removing " + pd.toString()); //$NON-NLS-1$
1353
reg.removePlugin(pd.getId(), pd.getVersion());
1354            }
1355        }
1356    }
1357}
1358
Popular Tags