Skip to content

Commit

Permalink
Small Resolver refactoring for PDE API tooling stability
Browse files Browse the repository at this point in the history
- changed Maps/Sets to "Linked" versions where iteration was done
- changed resolveBundles() to resolve fragments only if asked to - this
avoids the problem that fragments are resolved before host bundles
- added some debug logging for unresolved fragment hosts

See eclipse-pde/eclipse.pde#1073
  • Loading branch information
iloveeclipse committed Jan 31, 2024
1 parent cb29271 commit a7941db
Showing 1 changed file with 41 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -100,9 +102,9 @@ public class ResolverImpl implements Resolver {
// Repository for generics
private Map<String, VersionHashMap<GenericCapability>> resolverGenerics = null;
// List of unresolved bundles
private HashSet<ResolverBundle> unresolvedBundles = null;
private Set<ResolverBundle> unresolvedBundles;
// Keys are BundleDescriptions, values are ResolverBundles
private HashMap<BundleDescription, ResolverBundle> bundleMapping = null;
private Map<BundleDescription, ResolverBundle> bundleMapping;
private GroupingChecker groupingChecker;
private Comparator<BaseDescription> selectionPolicy;
private boolean developmentMode = false;
Expand All @@ -123,9 +125,9 @@ PermissionChecker getPermissionChecker() {
private void initialize() {
resolverExports = new VersionHashMap<>(this);
resolverBundles = new VersionHashMap<>(this);
resolverGenerics = new HashMap<>();
unresolvedBundles = new HashSet<>();
bundleMapping = new HashMap<>();
resolverGenerics = new LinkedHashMap<>();
unresolvedBundles = new LinkedHashSet<>();
bundleMapping = new LinkedHashMap<>();
BundleDescription[] bundles = state.getBundles();
groupingChecker = new GroupingChecker();

Expand Down Expand Up @@ -512,11 +514,12 @@ public synchronized void resolve(BundleDescription[] reRefresh, Dictionary<Objec
iToResolve.remove();
}
}
if (!unresolvedSystemBundles.isEmpty())
resolveBundles(unresolvedSystemBundles.toArray(new ResolverBundle[unresolvedSystemBundles.size()]), platformProperties, hookDisabled);
if (!unresolvedSystemBundles.isEmpty()) {
resolveBundles(unresolvedSystemBundles.toArray(new ResolverBundle[unresolvedSystemBundles.size()]), platformProperties, hookDisabled, false);
}

// Now resolve the rest
resolveBundles(toResolve.toArray(new ResolverBundle[toResolve.size()]), platformProperties, hookDisabled);
resolveBundles(toResolve.toArray(new ResolverBundle[toResolve.size()]), platformProperties, hookDisabled, true);

Collection<ResolverBundle> optionalResolved = resolveOptional ? resolveOptionalConstraints(currentlyResolved) : Collections.EMPTY_LIST;
ResolverHook current = hook;
Expand Down Expand Up @@ -591,7 +594,7 @@ private BundleDescription[] addDevConstraints(BundleDescription[] reRefresh) {
return reRefresh; // we don't care about this unless we are in development mode
// when in develoment mode we need to reRefresh hosts of unresolved fragments that add new constraints
// and reRefresh and unresolved bundles that have dependents
Set<BundleDescription> additionalRefresh = new HashSet<>();
Set<BundleDescription> additionalRefresh = new LinkedHashSet<>();
ResolverBundle[] allUnresolved = unresolvedBundles.toArray(new ResolverBundle[unresolvedBundles.size()]);
for (ResolverBundle unresolved : allUnresolved) {
addUnresolvedWithDependents(unresolved, additionalRefresh);
Expand Down Expand Up @@ -673,18 +676,19 @@ private void getCurrentEEs(Dictionary<Object, Object>[] platformProperties) {
}
}

private void resolveBundles(ResolverBundle[] bundles, Dictionary<Object, Object>[] platformProperties, Collection<ResolverBundle> hookDisabled) {
private void resolveBundles(ResolverBundle[] bundles, Dictionary<Object, Object>[] platformProperties, Collection<ResolverBundle> hookDisabled, boolean resolveFragments) {

// First check that all the meta-data is valid for each unresolved bundle
// This will reset the resolvable flag for each bundle
for (ResolverBundle bundle : bundles) {
state.removeResolverErrors(bundle.getBundleDescription());
// if in development mode then make all bundles resolvable
// we still want to call isResolvable here to populate any possible ResolverErrors for the bundle
bundle.setResolvable(isResolvable(bundle, platformProperties, hookDisabled) || developmentMode);
boolean resolvable = isResolvable(bundle, platformProperties, hookDisabled);
bundle.setResolvable(resolvable || developmentMode);
}
selectSingletons(bundles);
resolveBundles0(bundles, platformProperties);
resolveBundles0(bundles, platformProperties, resolveFragments);
if (DEBUG_WIRING)
printWirings();
}
Expand Down Expand Up @@ -774,7 +778,7 @@ private ResolverBundle pickOneToResolve(Collection<ResolverBundle> pickOneToReso
}

private Map<ResolverBundle, Collection<ResolverBundle>> getCollisionMap(List<ResolverBundle> sameBSN) {
Map<ResolverBundle, Collection<ResolverBundle>> result = new HashMap<>();
Map<ResolverBundle, Collection<ResolverBundle>> result = new LinkedHashMap<>();
for (ResolverBundle singleton : sameBSN) {
if (!singleton.getBundleDescription().isSingleton() || !singleton.isResolvable())
continue; // ignore non-singleton and non-resolvable
Expand All @@ -798,7 +802,7 @@ private BundleCapability getIdentity(ResolverBundle bundle) {
return identities.size() == 1 ? identities.get(0) : bundle.getCapability();
}

private void resolveBundles0(ResolverBundle[] bundles, Dictionary<Object, Object>[] platformProperties) {
private void resolveBundles0(ResolverBundle[] bundles, Dictionary<Object, Object>[] platformProperties, boolean resolveFragments) {
if (developmentMode)
// need to sort bundles to keep consistent order for fragment attachment (bug 174930)
Arrays.sort(bundles);
Expand All @@ -822,7 +826,7 @@ private void resolveBundles0(ResolverBundle[] bundles, Dictionary<Object, Object
checkCycle(cycle);
}
// Resolve all fragments that are still attached to at least one host.
if (unresolvedBundles.size() > 0) {
if (resolveFragments && unresolvedBundles.size() > 0) {
ResolverBundle[] unresolved = unresolvedBundles.toArray(new ResolverBundle[unresolvedBundles.size()]);
for (ResolverBundle toResolve : unresolved) {
resolveFragment(toResolve);
Expand Down Expand Up @@ -899,7 +903,7 @@ private void reResolveBundles(Set<ResolverBundle> exclude, ResolverBundle[] bund
remainingUnresolved.add(bundle);
}
}
resolveBundles0(remainingUnresolved.toArray(new ResolverBundle[remainingUnresolved.size()]), platformProperties);
resolveBundles0(remainingUnresolved.toArray(new ResolverBundle[remainingUnresolved.size()]), platformProperties, true);
}

private List<ResolverConstraint> findBestCombination(ResolverBundle[] bundles, Dictionary<Object, Object>[] platformProperties) {
Expand Down Expand Up @@ -1230,13 +1234,13 @@ private ResolverConstraint[][] getMultipleSuppliers(ResolverBundle[] bundles, Se
if (multipleImportSupplierList.size() + multipleRequireSupplierList.size() + multipleGenericSupplierList.size() > usesMultipleSuppliersLimit) {
// we have hit a max on the multiple suppliers in the lists without merging.
// first merge the identical constraints that have identical suppliers
Map<String, List<List<ResolverConstraint>>> multipleImportSupplierMaps = new HashMap<>();
Map<String, List<List<ResolverConstraint>>> multipleImportSupplierMaps = new LinkedHashMap<>();
for (ResolverImport importPkg : multipleImportSupplierList)
addMutipleSupplierConstraint(multipleImportSupplierMaps, importPkg, importPkg.getName());
Map<String, List<List<ResolverConstraint>>> multipleRequireSupplierMaps = new HashMap<>();
Map<String, List<List<ResolverConstraint>>> multipleRequireSupplierMaps = new LinkedHashMap<>();
for (BundleConstraint requireBundle : multipleRequireSupplierList)
addMutipleSupplierConstraint(multipleRequireSupplierMaps, requireBundle, requireBundle.getName());
Map<String, List<List<ResolverConstraint>>> multipleGenericSupplierMaps = new HashMap<>();
Map<String, List<List<ResolverConstraint>>> multipleGenericSupplierMaps = new LinkedHashMap<>();
for (GenericConstraint genericRequire : multipleGenericSupplierList)
addMutipleSupplierConstraint(multipleGenericSupplierMaps, genericRequire, genericRequire.getNameSpace());
addMergedSuppliers(results, multipleImportSupplierMaps);
Expand Down Expand Up @@ -1380,11 +1384,26 @@ static Collection<BundleCapability> asCapabilities(Collection<? extends BundleCa
}

private void resolveFragment(ResolverBundle fragment) {
if (!fragment.isFragment())
if (!fragment.isFragment()) {
return;
if (fragment.getHost().getNumPossibleSuppliers() > 0)
if (!developmentMode || state.getResolverErrors(fragment.getBundleDescription()).length == 0)
}
BundleConstraint hostConstraint = fragment.getHost();
if (DEBUG){
ResolverBundle host = null;
if (hostConstraint != null) {
String hostName = hostConstraint.getName();
host = unresolvedBundles.stream().filter(b -> hostName.equals(b.getName())).findFirst().orElse(null);
if (host != null && host.getState() != ResolverBundle.RESOLVED) {
ResolverImpl.log("Host " + host + " is not resolved, but fragment " + fragment + " is!"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
}

if (hostConstraint.getNumPossibleSuppliers() > 0) {
if (!developmentMode || state.getResolverErrors(fragment.getBundleDescription()).length == 0) {
setBundleResolved(fragment);
}
}
}

// This method will attempt to resolve the supplied bundle and any bundles that it is dependent on
Expand Down

0 comments on commit a7941db

Please sign in to comment.