diff options
author | Thomas Watson | 2013-11-19 21:21:33 +0000 |
---|---|---|
committer | Thomas Watson | 2013-11-21 15:52:38 +0000 |
commit | 5a122e8088f7db503d94c46fac507cee86aee578 (patch) | |
tree | 99f78ccecbf1c9b876335ef409a28317fa64687f | |
parent | 56378517e2131c04a5e5804fb27db5fd80b54dc3 (diff) | |
download | rt.equinox.framework-5a122e8088f7db503d94c46fac507cee86aee578.tar.gz rt.equinox.framework-5a122e8088f7db503d94c46fac507cee86aee578.tar.xz rt.equinox.framework-5a122e8088f7db503d94c46fac507cee86aee578.zip |
Bug 421706 - Can't start Eclipse M3 after installing "everything"I20131203-0800I20131126-0800
- Do single bundle resolves to reduce the uses constraint problem set.
5 files changed, 141 insertions, 60 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java index 02c487162..c4164886b 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleContainer.java @@ -144,7 +144,7 @@ public final class ModuleContainer { * @param attributes the requirement attributes * @return a synthetic requirement */ - public Requirement createRequirement(String namespace, Map<String, String> directives, Map<String, ?> attributes) { + public static Requirement createRequirement(String namespace, Map<String, String> directives, Map<String, ?> attributes) { return new ModuleRequirement(namespace, directives, attributes, null); } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java index 5b371ed65..5482159f5 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java @@ -180,27 +180,6 @@ public class ModuleDatabase { } /** - * Returns a snapshot collection of current revisions which are fragments - - * @return a snapshot collection of current revisions which are fragments - */ - final Collection<ModuleRevision> getFragmentRevisions() { - Collection<ModuleRevision> fragments = new ArrayList<ModuleRevision>(); - readLock(); - try { - for (Module module : modulesById.values()) { - ModuleRevision revision = module.getCurrentRevision(); - if (revision != null && ((revision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0)) { - fragments.add(revision); - } - } - return fragments; - } finally { - readUnlock(); - } - } - - /** * Installs a new revision using the specified builder, location and module. * <p> * A write operation protected by the {@link #writeLock() write} lock. diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolver.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolver.java index de9cc6929..e3e9bd11e 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolver.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleResolver.java @@ -12,9 +12,9 @@ package org.eclipse.osgi.container; import java.security.Permission; import java.util.*; -import org.apache.felix.resolver.Logger; -import org.apache.felix.resolver.ResolverImpl; +import org.apache.felix.resolver.*; import org.eclipse.osgi.container.ModuleRequirement.DynamicModuleRequirement; +import org.eclipse.osgi.container.namespaces.EquinoxFragmentNamespace; import org.eclipse.osgi.internal.container.InternalUtils; import org.eclipse.osgi.internal.messages.Msg; import org.eclipse.osgi.report.resolution.*; @@ -402,7 +402,7 @@ final class ModuleResolver { return version instanceof Version ? (Version) version : Version.emptyVersion; } - class ResolveProcess extends ResolveContext implements Comparator<Capability> { + class ResolveProcess extends ResolveContext implements Comparator<Capability>, FelixResolveContext { class ResolveLogger extends Logger { private Map<Resource, ResolutionException> errors = null; @@ -445,9 +445,14 @@ final class ModuleResolver { private final boolean triggersMandatory; private final ModuleDatabase moduleDatabase; private final Map<ModuleRevision, ModuleWiring> wirings; + private final Set<ModuleRevision> previouslyResolved; private final DynamicModuleRequirement dynamicReq; private volatile ResolverHook hook = null; private volatile Map<String, Collection<ModuleRevision>> byName = null; + private volatile ModuleRevision currentlyResolving = null; + private volatile boolean currentlyResolvingMandatory = false; + private final Set<Resource> transitivelyResolveFailures = new LinkedHashSet<Resource>(); + private final Set<Resource> failedToResolve = new HashSet<Resource>(); /* * Used to generate the UNRESOLVED_PROVIDER resolution report entries. * @@ -469,6 +474,7 @@ final class ModuleResolver { this.optionals.removeAll(triggers); } this.wirings = new HashMap<ModuleRevision, ModuleWiring>(wirings); + this.previouslyResolved = new HashSet<ModuleRevision>(wirings.keySet()); this.moduleDatabase = moduleDatabase; this.dynamicReq = null; } @@ -482,6 +488,7 @@ final class ModuleResolver { this.triggersMandatory = false; this.optionals = new ArrayList<ModuleRevision>(unresolved); this.wirings = wirings; + this.previouslyResolved = new HashSet<ModuleRevision>(wirings.keySet()); this.moduleDatabase = moduleDatabase; this.dynamicReq = dynamicReq; } @@ -489,13 +496,7 @@ final class ModuleResolver { @Override public List<Capability> findProviders(Requirement requirement) { List<ModuleCapability> candidates = moduleDatabase.findCapabilities(requirement); - // TODO Record missing capability here if empty? Then record other - // entry types later if an existing capability was filtered? List<Capability> result = filterProviders(requirement, candidates); - if (result.isEmpty()) - reportBuilder.addEntry(requirement.getResource(), Entry.Type.MISSING_CAPABILITY, requirement); - else - computeUnresolvedProviders(requirement, result); return result; } @@ -510,16 +511,43 @@ final class ModuleResolver { removeSubstituted(iCandidates); filterPermissions((BundleRequirement) requirement, iCandidates); hook.filterMatches((BundleRequirement) requirement, InternalUtils.asListBundleCapability(candidates)); + // filter resolved hosts after calling hooks to allow hooks to see the host capability filterResolvedHosts(requirement, candidates, filterResolvedHosts); + + if (requirement instanceof DynamicModuleRequirement) { + requirement = ((DynamicModuleRequirement) requirement).getOriginal(); + } + if (candidates.isEmpty()) { + if (!wirings.containsKey(requirement.getResource())) { + reportBuilder.addEntry(requirement.getResource(), Entry.Type.MISSING_CAPABILITY, requirement); + String resolution = requirement.getDirectives().get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE); + if ((resolution == null || Namespace.RESOLUTION_MANDATORY.equals(resolution))) { + transitivelyResolveFailures.add(requirement.getResource()); + } + } + } else { + computeUnresolvedProviders(requirement, candidates); + } + + filterFailedToResolve(candidates); + Collections.sort(candidates, this); return InternalUtils.asListCapability(candidates); } + private void filterFailedToResolve(List<ModuleCapability> candidates) { + for (Iterator<ModuleCapability> iCandidates = candidates.iterator(); iCandidates.hasNext();) { + if (failedToResolve.contains(iCandidates.next().getRevision())) { + iCandidates.remove(); + } + } + } + private void filterResolvedHosts(Requirement requirement, List<ModuleCapability> candidates, boolean filterResolvedHosts) { if (filterResolvedHosts && HostNamespace.HOST_NAMESPACE.equals(requirement.getNamespace())) { for (Iterator<ModuleCapability> iCandidates = candidates.iterator(); iCandidates.hasNext();) { - if (wirings.containsKey(iCandidates.next().getRevision())) { + if (previouslyResolved.contains(iCandidates.next().getRevision())) { iCandidates.remove(); } } @@ -596,15 +624,45 @@ final class ModuleResolver { @Override public Collection<Resource> getMandatoryResources() { - if (triggersMandatory) { - return InternalUtils.asCollectionResource(triggers); + if (currentlyResolvingMandatory) { + return Collections.<Resource> singleton(currentlyResolving); } - return super.getMandatoryResources(); + return Collections.emptyList(); } @Override public Collection<Resource> getOptionalResources() { - return InternalUtils.asCollectionResource(optionals); + if (!currentlyResolvingMandatory) { + return Collections.<Resource> singleton(currentlyResolving); + } + return Collections.emptyList(); + } + + @Override + public Collection<Resource> getOndemandResources(Resource host) { + String hostBSN = ((ModuleRevision) host).getSymbolicName(); + if (hostBSN == null) { + return Collections.emptyList(); + } + List<ModuleCapability> hostCaps = ((ModuleRevision) host).getModuleCapabilities(HostNamespace.HOST_NAMESPACE); + if (hostCaps.isEmpty()) { + return Collections.emptyList(); + } + ModuleCapability hostCap = hostCaps.get(0); + String matchFilter = "(" + EquinoxFragmentNamespace.FRAGMENT_NAMESPACE + "=" + hostBSN + ")"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + Requirement fragmentRequirement = ModuleContainer.createRequirement(EquinoxFragmentNamespace.FRAGMENT_NAMESPACE, Collections.<String, String> singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE, matchFilter), Collections.<String, Object> emptyMap()); + List<ModuleCapability> candidates = moduleDatabase.findCapabilities(fragmentRequirement); + // filter out disabled fragments and singletons + filterDisabled(candidates.listIterator()); + Collection<Resource> ondemandFragments = new ArrayList<Resource>(candidates.size()); + for (Iterator<ModuleCapability> iCandidates = candidates.iterator(); iCandidates.hasNext();) { + ModuleCapability candidate = iCandidates.next(); + ModuleRequirement hostReq = candidate.getRevision().getModuleRequirements(HostNamespace.HOST_NAMESPACE).get(0); + if (hostReq.matches(hostCap)) { + ondemandFragments.add(candidate.getResource()); + } + } + return ondemandFragments; } ModuleResolutionReport resolve() { @@ -641,16 +699,26 @@ final class ModuleResolver { if (dynamicReq != null) { result = resolveDynamic(); } else { + result = new HashMap<Resource, List<Wire>>(); Map<Resource, List<Wire>> dynamicAttachWirings = resolveNonPayLoadFragments(); + applyInterimResultToWiringCopy(dynamicAttachWirings); if (!dynamicAttachWirings.isEmpty()) { - // update the copy of wirings to include the new attachments - Map<ModuleRevision, ModuleWiring> updatedWirings = generateDelta(dynamicAttachWirings, wirings); - for (Map.Entry<ModuleRevision, ModuleWiring> updatedWiring : updatedWirings.entrySet()) { - wirings.put(updatedWiring.getKey(), updatedWiring.getValue()); + // be sure to remove the revisions from the optional and triggers + // so they no longer attempt to be resolved + Set<Resource> fragmentResources = dynamicAttachWirings.keySet(); + triggers.removeAll(fragmentResources); + optionals.removeAll(fragmentResources); + + result.putAll(dynamicAttachWirings); + } + if (triggersMandatory) { + for (ModuleRevision mandatory : triggers) { + resolveSingleRevision(mandatory, true, logger, result); } } - result = new ResolverImpl(logger).resolve(this); - result.putAll(dynamicAttachWirings); + for (ModuleRevision optional : optionals) { + resolveSingleRevision(optional, false, logger, result); + } } } catch (ResolutionException e) { re = e; @@ -668,6 +736,49 @@ final class ModuleResolver { } } + private void resolveSingleRevision(ModuleRevision single, boolean isMandatory, ResolveLogger logger, Map<Resource, List<Wire>> result) throws ResolutionException { + if (wirings.containsKey(single) || failedToResolve.contains(single)) { + return; + } + currentlyResolving = single; + currentlyResolvingMandatory = isMandatory; + transitivelyResolveFailures.clear(); + Map<Resource, List<Wire>> interimResults = null; + try { + transitivelyResolveFailures.add(single); + interimResults = new ResolverImpl(logger).resolve(this); + applyInterimResultToWiringCopy(interimResults); + // now apply the simple wires to the results + for (Map.Entry<Resource, List<Wire>> interimResultEntry : interimResults.entrySet()) { + List<Wire> existingWires = result.get(interimResultEntry.getKey()); + if (existingWires != null) { + existingWires.addAll(interimResultEntry.getValue()); + } else { + result.put(interimResultEntry.getKey(), interimResultEntry.getValue()); + } + } + } finally { + transitivelyResolveFailures.addAll(logger.getUsesConstraintViolations().keySet()); + if (interimResults != null) { + transitivelyResolveFailures.removeAll(interimResults.keySet()); + } + // what is left did not resolve + failedToResolve.addAll(transitivelyResolveFailures); + currentlyResolving = null; + currentlyResolvingMandatory = false; + } + } + + private void applyInterimResultToWiringCopy(Map<Resource, List<Wire>> interimResult) { + if (!interimResult.isEmpty()) { + // update the copy of wirings to include interim results + Map<ModuleRevision, ModuleWiring> updatedWirings = generateDelta(interimResult, wirings); + for (Map.Entry<ModuleRevision, ModuleWiring> updatedWiring : updatedWirings.entrySet()) { + wirings.put(updatedWiring.getKey(), updatedWiring.getValue()); + } + } + } + private void computeUsesConstraintViolations(Map<Resource, ResolutionException> usesConstraintViolations) { for (Map.Entry<Resource, ResolutionException> usesConstraintViolation : usesConstraintViolations.entrySet()) { reportBuilder.addEntry(usesConstraintViolation.getKey(), Type.USES_CONSTRAINT_VIOLATION, usesConstraintViolation.getValue()); @@ -798,10 +909,6 @@ final class ModuleResolver { } } if (resolvedReqs) { - // be sure to remove the revision from the optional and triggers - // so they no longer attempt to be resolved - triggers.remove(nonPayLoad); - optionals.remove(nonPayLoad); dynamicAttachment.put(nonPayLoad, nonPayloadWires); } } @@ -824,13 +931,7 @@ final class ModuleResolver { private Map<Resource, List<Wire>> resolveDynamic() throws ResolutionException { List<Capability> dynamicMatches = filterProviders(dynamicReq.getOriginal(), moduleDatabase.findCapabilities(dynamicReq)); - if (dynamicMatches.isEmpty()) - reportBuilder.addEntry(dynamicReq.getResource(), Entry.Type.MISSING_CAPABILITY, dynamicReq.getOriginal()); - else - computeUnresolvedProviders(dynamicReq.getOriginal(), dynamicMatches); - Collection<Resource> ondemandFragments = InternalUtils.asCollectionResource(moduleDatabase.getFragmentRevisions()); - - return new ResolverImpl(new Logger(0)).resolve(this, dynamicReq.getRevision(), dynamicReq.getOriginal(), dynamicMatches, ondemandFragments); + return new ResolverImpl(new Logger(0)).resolve(this, dynamicReq.getRevision(), dynamicReq.getOriginal(), dynamicMatches); } private void filterResolvable() { @@ -913,7 +1014,7 @@ final class ModuleResolver { // this is to avoid interacting with the module database Set<ModuleRevision> revisions = new HashSet<ModuleRevision>(); revisions.addAll(unresolved); - revisions.addAll(wirings.keySet()); + revisions.addAll(previouslyResolved); current = new HashMap<String, Collection<ModuleRevision>>(); for (ModuleRevision revision : revisions) { Collection<ModuleRevision> sameName = current.get(revision.getSymbolicName()); @@ -982,8 +1083,8 @@ final class ModuleResolver { // TODO Ideally this policy should be handled by the ModuleDatabase. // To do that the wirings would have to be provided since the wirings may // be a subset of the current wirings provided by the ModuleDatabase - boolean resolved1 = wirings.get(c1.getResource()) != null; - boolean resolved2 = wirings.get(c2.getResource()) != null; + boolean resolved1 = previouslyResolved.contains(c1.getResource()); + boolean resolved2 = previouslyResolved.contains(c2.getResource()); if (resolved1 != resolved2) return resolved1 ? -1 : 1; diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/builders/OSGiManifestBuilderFactory.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/builders/OSGiManifestBuilderFactory.java index 8c29f87d6..2f3a39c04 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/builders/OSGiManifestBuilderFactory.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/builders/OSGiManifestBuilderFactory.java @@ -439,7 +439,8 @@ public final class OSGiManifestBuilderFactory { directives.put(BundleNamespace.REQUIREMENT_FILTER_DIRECTIVE, filter.toString()); builder.addRequirement(HostNamespace.HOST_NAMESPACE, directives, new HashMap<String, Object>(0)); // Add a fragment capability to advertise what host this resource is providing a fragment for - builder.addCapability(EquinoxFragmentNamespace.FRAGMENT_NAMESPACE, Collections.<String, String> emptyMap(), Collections.<String, Object> singletonMap(EquinoxFragmentNamespace.FRAGMENT_NAMESPACE, hostName)); + directives = Collections.singletonMap(EquinoxModuleDataNamespace.CAPABILITY_EFFECTIVE_DIRECTIVE, EquinoxModuleDataNamespace.EFFECTIVE_INFORMATION); + builder.addCapability(EquinoxFragmentNamespace.FRAGMENT_NAMESPACE, directives, Collections.<String, Object> singletonMap(EquinoxFragmentNamespace.FRAGMENT_NAMESPACE, hostName)); } private static void getProvideCapabilities(ModuleRevisionBuilder builder, ManifestElement[] provideElements, boolean chechSystemCapabilities) throws BundleException { diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/legacy/PackageAdminImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/legacy/PackageAdminImpl.java index 1547c69cb..92b1857bc 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/legacy/PackageAdminImpl.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/legacy/PackageAdminImpl.java @@ -108,7 +108,7 @@ public class PackageAdminImpl implements PackageAdmin { String filter = "(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + (name == null ? "*" : name) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ Map<String, String> directives = Collections.<String, String> singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter); Map<String, Boolean> attributes = Collections.singletonMap(Capabilities.SYNTHETIC_REQUIREMENT, Boolean.TRUE); - Requirement packageReq = container.createRequirement(PackageNamespace.PACKAGE_NAMESPACE, directives, attributes); + Requirement packageReq = ModuleContainer.createRequirement(PackageNamespace.PACKAGE_NAMESPACE, directives, attributes); Collection<BundleCapability> packageCaps = container.getFrameworkWiring().findProviders(packageReq); InternalUtils.filterCapabilityPermissions(packageCaps); List<ExportedPackage> result = new ArrayList<ExportedPackage>(); @@ -135,7 +135,7 @@ public class PackageAdminImpl implements PackageAdmin { String filter = "(" + BundleNamespace.BUNDLE_NAMESPACE + "=" + (symbolicName == null ? "*" : symbolicName) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ Map<String, String> directives = Collections.<String, String> singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter); Map<String, Boolean> attributes = Collections.singletonMap(Capabilities.SYNTHETIC_REQUIREMENT, Boolean.TRUE); - Requirement bundleReq = container.createRequirement(BundleNamespace.BUNDLE_NAMESPACE, directives, attributes); + Requirement bundleReq = ModuleContainer.createRequirement(BundleNamespace.BUNDLE_NAMESPACE, directives, attributes); Collection<BundleCapability> bundleCaps = container.getFrameworkWiring().findProviders(bundleReq); InternalUtils.filterCapabilityPermissions(bundleCaps); Collection<RequiredBundle> result = new ArrayList<RequiredBundle>(); @@ -158,7 +158,7 @@ public class PackageAdminImpl implements PackageAdmin { } VersionRange range = versionRange == null ? null : new VersionRange(versionRange); String filter = (range != null ? "(&" : "") + "(" + IdentityNamespace.IDENTITY_NAMESPACE + "=" + symbolicName + ")" + (range != null ? range.toFilterString(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE) + ")" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ - Requirement identityReq = container.createRequirement(IdentityNamespace.IDENTITY_NAMESPACE, Collections.<String, String> singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter), Collections.<String, Object> emptyMap()); + Requirement identityReq = ModuleContainer.createRequirement(IdentityNamespace.IDENTITY_NAMESPACE, Collections.<String, String> singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter), Collections.<String, Object> emptyMap()); Collection<BundleCapability> identityCaps = container.getFrameworkWiring().findProviders(identityReq); if (identityCaps.isEmpty()) { |