diff --git a/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF
index 047afbde428..99bf13295d0 100644
--- a/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Core OSGi Tests
Bundle-SymbolicName: org.eclipse.osgi.tests;singleton:=true
-Bundle-Version: 3.20.100.qualifier
+Bundle-Version: 3.20.200.qualifier
Bundle-Vendor: Eclipse.org
Require-Bundle:
org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)",
diff --git a/bundles/org.eclipse.osgi.tests/pom.xml b/bundles/org.eclipse.osgi.tests/pom.xml
index e032ca99ffc..0361e4dd55e 100644
--- a/bundles/org.eclipse.osgi.tests/pom.xml
+++ b/bundles/org.eclipse.osgi.tests/pom.xml
@@ -19,7 +19,7 @@
org.eclipse.osgi
org.eclipse.osgi.tests
- 3.20.100-SNAPSHOT
+ 3.20.200-SNAPSHOT
eclipse-test-plugin
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java
index 4bd75eee64c..22f0c87774d 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java
@@ -3959,7 +3959,8 @@ protected void assertNotMoreThanPermutationCreated(ResolutionReport report,
fail("Maximum of " + max + " permutations expected but was " + permutations);
} else if (permutations < max) {
System.out.println(
- "## Permutations are below the threshold, consider adjusting the testcase to assert the lower count!");
+ "## Permutations (" + permutations + ") are below the threshold (" + max
+ + "), consider adjusting the testcase to assert the lower count!");
}
return;
}
@@ -4367,8 +4368,8 @@ private static void assertWires(List required, List... p
public void testLocalUseConstraintViolations() throws Exception {
ResolutionReport result = resolveTestSet("set1");
// TODO get down permutation count!
- assertSucessfulWith(result, 52);
- assertNotMoreThanPermutationCreated(result, ResolutionReport::getSubstitutionPermutations, 23);
+ assertSucessfulWith(result, 49);
+ assertNotMoreThanPermutationCreated(result, ResolutionReport::getSubstitutionPermutations, 20);
}
private ResolutionReport resolveTestSet(String name) throws Exception {
diff --git a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF
index 73c86e2b391..9d40447fffe 100644
--- a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Export-Package: org.eclipse.core.runtime.adaptor;x-friends:="org.eclipse.core.runtime",
org.eclipse.core.runtime.internal.adaptor;x-internal:=true,
org.eclipse.equinox.log;version="1.1";uses:="org.osgi.framework,org.osgi.service.log",
- org.eclipse.osgi.container;version="1.7.0";
+ org.eclipse.osgi.container;version="1.8.0";
uses:="org.eclipse.osgi.report.resolution,
org.osgi.framework.wiring,
org.eclipse.osgi.framework.eventmgr,
@@ -107,7 +107,7 @@ Bundle-Activator: org.eclipse.osgi.internal.framework.SystemBundleActivator
Bundle-Description: %systemBundle
Bundle-Copyright: %copyright
Bundle-Vendor: %eclipse.org
-Bundle-Version: 3.21.0.qualifier
+Bundle-Version: 3.21.100.qualifier
Bundle-Localization: systembundle
Bundle-DocUrl: http://www.eclipse.org
Eclipse-ExtensibleAPI: true
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 d93eb6d3a06..2386a8b4b13 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
@@ -261,6 +261,34 @@ public static String toString(Capability capability) {
return Constants.PROVIDE_CAPABILITY + ": " + capability.toString(); //$NON-NLS-1$
}
+ /**
+ * Generates a human readable string representation of the the given
+ * {@link Resource} using the IDENTITY_NAMESPACE
+ *
+ * @param resource the {@link Resource} for which a string representation is
+ * desired
+ *
+ * @since 3.21
+ */
+ public static String toString(Resource resource) {
+ String id = null;
+ Version version = null;
+ List caps = resource.getCapabilities(null);
+ for (Capability cap : caps) {
+ if (cap.getNamespace().equals(IdentityNamespace.IDENTITY_NAMESPACE)) {
+ id = cap.getAttributes().get(IdentityNamespace.IDENTITY_NAMESPACE).toString();
+ version = (Version) cap.getAttributes().get(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE);
+ }
+ }
+ if (id != null) {
+ if (version != null) {
+ return String.format("%s %s", id, version); //$NON-NLS-1$
+ }
+ return id;
+ }
+ return resource.toString();
+ }
+
private static String createOSGiCapability(Capability cap) {
Map attributes = new HashMap<>(cap.getAttributes());
Map directives = cap.getDirectives();
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 6efc6216841..eb1b0dcd4f9 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
@@ -16,6 +16,7 @@
import static org.eclipse.osgi.internal.container.NamespaceList.WIRE;
import java.security.Permission;
+import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -37,6 +38,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
import org.apache.felix.resolver.Logger;
import org.apache.felix.resolver.PermutationType;
import org.apache.felix.resolver.ResolutionError;
@@ -504,6 +506,74 @@ public void logUsesConstraintViolation(Resource resource, ResolutionError error)
}
}
+ public void logRequirement(String message, Requirement requirement) {
+ debug(String.format(message, ModuleContainer.toString(requirement)));
+ }
+
+ public void logCapability(String message, Capability requirement) {
+ debug(String.format(message, ModuleContainer.toString(requirement)));
+ }
+
+ @Override
+ public void logCandidates(Resource resource, Function> candidateLookup) {
+ if (DEBUG_USES) {
+ Wiring wiring = getWirings().get(resource);
+ List reqs = (wiring != null) ? wiring.getResourceRequirements(null)
+ : resource.getRequirements(null);
+ List dreqs = (wiring != null)
+ ? getDynamicRequirements(wiring.getResourceRequirements(null))
+ : getDynamicRequirements(resource.getRequirements(null));
+ boolean hasMulti = hasMulti(reqs, candidateLookup);
+ Debug.println(String.format(" %s%s (%s)", getMultiMarker(hasMulti), //$NON-NLS-1$
+ ModuleContainer.toString(resource),
+ ((wiring != null) ? "RESOLVED)" : "UNRESOLVED)"))); //$NON-NLS-1$ //$NON-NLS-2$
+ printRe(reqs, candidateLookup);
+ printRe(dreqs, candidateLookup);
+ }
+ }
+
+ private String getMultiMarker(boolean hasMulti) {
+ return hasMulti ? "[?]" : "[!]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private boolean hasMulti(List reqs, Function> candidateLookup) {
+ for (Requirement req : reqs) {
+ List remaining = candidateLookup.apply(req);
+ if (remaining.size() > 1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private int printRe(List reqs, Function> candidateLookup) {
+ int dup = 0;
+ for (Requirement req : reqs) {
+ List remaining = candidateLookup.apply(req);
+ boolean hasMulti = remaining.size() > 1;
+ dup++;
+ Debug.println(MessageFormat.format(" {0}{1}: ", getMultiMarker(hasMulti), //$NON-NLS-1$
+ ModuleContainer.toString(req)));
+ for (Capability cap : remaining) {
+ Debug.println(String.format(" %s", ModuleContainer.toString(cap))); //$NON-NLS-1$
+ }
+ }
+ return dup;
+ }
+
+ private List getDynamicRequirements(List reqs) {
+ List result = new ArrayList<>();
+ if (reqs != null) {
+ for (Requirement req : reqs) {
+ String resolution = req.getDirectives().get(PackageNamespace.REQUIREMENT_RESOLUTION_DIRECTIVE);
+ if ((resolution != null) && resolution.equals(PackageNamespace.RESOLUTION_DYNAMIC)) {
+ result.add(req);
+ }
+ }
+ }
+ return result;
+ }
+
Map getUsesConstraintViolations() {
return errors == null ? Collections.emptyMap() : errors;
}
diff --git a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Candidates.java b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Candidates.java
index 0b59f6dac0b..25aab4e6072 100644
--- a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Candidates.java
+++ b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Candidates.java
@@ -18,6 +18,7 @@
*/
package org.apache.felix.resolver;
+import java.io.PrintStream;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -34,6 +35,8 @@
class Candidates
{
+ private static final boolean FILTER_USES = Boolean
+ .parseBoolean(System.getProperty("felix.resolver.candidates.filteruses", "true"));
static class PopulateResult {
boolean success;
ResolutionError error;
@@ -709,7 +712,7 @@ public Capability getFirstCandidate(Requirement req)
return null;
}
- public void removeFirstCandidate(Requirement req)
+ public Capability removeFirstCandidate(Requirement req)
{
CandidateSelector candidates = m_candidateMap.get(req);
// Remove the conflicting candidate.
@@ -721,6 +724,7 @@ public void removeFirstCandidate(Requirement req)
// Update the delta with the removed capability
CopyOnWriteSet capPath = m_delta.getOrCompute(req);
capPath.add(cap);
+ return cap;
}
public CandidateSelector clearMultipleCardinalityCandidates(Requirement req, Collection caps)
@@ -1145,54 +1149,15 @@ public Candidates copy()
m_delta.deepClone());
}
- public void dump(ResolveContext rc)
- {
- // Create set of all revisions from requirements.
- Set resources = new CopyOnWriteSet();
- for (Entry entry
- : m_candidateMap.entrySet())
- {
- resources.add(entry.getKey().getResource());
- }
- // Now dump the revisions.
- System.out.println("=== BEGIN CANDIDATE MAP ===");
- for (Resource resource : resources)
- {
- Wiring wiring = rc.getWirings().get(resource);
- System.out.println(" " + resource
- + " (" + ((wiring != null) ? "RESOLVED)" : "UNRESOLVED)"));
- List reqs = (wiring != null)
- ? wiring.getResourceRequirements(null)
- : resource.getRequirements(null);
- for (Requirement req : reqs)
- {
- CandidateSelector candidates = m_candidateMap.get(req);
- if ((candidates != null) && (!candidates.isEmpty()))
- {
- System.out.println(" " + req + ": " + candidates);
- }
- }
- reqs = (wiring != null)
- ? Util.getDynamicRequirements(wiring.getResourceRequirements(null))
- : Util.getDynamicRequirements(resource.getRequirements(null));
- for (Requirement req : reqs)
- {
- CandidateSelector candidates = m_candidateMap.get(req);
- if ((candidates != null) && (!candidates.isEmpty()))
- {
- System.out.println(" " + req + ": " + candidates);
- }
- }
- }
- System.out.println("=== END CANDIDATE MAP ===");
- }
-
public Candidates permutate(Requirement req)
{
if (!Util.isMultiple(req) && canRemoveCandidate(req))
{
Candidates perm = copy();
- perm.removeFirstCandidate(req);
+ Capability removed = perm.removeFirstCandidate(req);
+ if (FILTER_USES) {
+ ProblemReduction.removeUsesViolations(perm, req, m_session.getLogger());
+ }
return perm;
}
return null;
@@ -1341,4 +1306,25 @@ public ResolutionException toException() {
}
+ /**
+ * Returns the current provided {@link Capability} for the given resource if it
+ * is a candidate for the {@link Requirement}
+ *
+ * @param resource the resource to check
+ * @param requirement the requirement to check
+ * @return the {@link Capability} this Resource currently provides for the given
+ * {@link Requirement} or null
if none is provided.
+ */
+ public Capability getCapability(Resource resource, Requirement requirement) {
+ List providers = getCandidates(requirement);
+ if (providers != null) {
+ for (Capability capability : providers) {
+ if (capability.getResource().equals(resource)) {
+ return capability;
+ }
+ }
+ }
+ return null;
+ }
+
}
diff --git a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Logger.java b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Logger.java
index b82c0d9e424..f4a6eebaed1 100644
--- a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Logger.java
+++ b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Logger.java
@@ -18,6 +18,10 @@
*/
package org.apache.felix.resolver;
+import java.util.List;
+import java.util.function.Function;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
/**
@@ -132,6 +136,31 @@ public void logUsesConstraintViolation(Resource resource, ResolutionError error)
// do nothing by default
}
+ /**
+ * Called to debug the current mapping of {@link Requirement}s to
+ * {@link Capability}s in a resolve operation
+ *
+ * @param resource the resource for this log message
+ * @param candidateLookup a mapping between a requirement and a list of all
+ * current candidate {@link Capability}s eligible for
+ * resolving
+ */
+ public void logCandidates(Resource resource,
+ Function> candidateLookup)
+ {
+ // do nothing by default
+ }
+
+ public void logRequirement(String message, Requirement requirement)
+ {
+ debug(String.format(message, requirement));
+ }
+
+ public void logCapability(String message, Capability requirement)
+ {
+ debug(String.format(message, requirement));
+ }
+
/**
* Called whenever a new permutation is added by the resolver.
*
diff --git a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ProblemReduction.java b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ProblemReduction.java
new file mode 100644
index 00000000000..fea2cab9f0d
--- /dev/null
+++ b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ProblemReduction.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.resolver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+
+/**
+ * The idea of the {@link ProblemReduction} class is to strike out
+ * {@link Capability}s that might satisfy {@link Requirement}s but violates some
+ * contracts that would lead to a guaranteed unresolvable state.
+ */
+class ProblemReduction {
+
+ private static final Capability[] EMPTY_CAPABILITIES = new Capability[0];
+
+ /**
+ * Removes all violating providers for a given {@link Requirement} and
+ * {@link Candidates} in a local search, that is if the requirement has any uses
+ * it checks if there are other packages used by this one and removes any
+ * offending providers from the top of the list.
+ *
+ * @param candidates candidates to filter
+ * @param requirement the requirement where the search should start
+ * @return a list of Candidates that where dropped as part of the filtering
+ */
+ static List removeUsesViolations(Candidates candidates, Requirement requirement, Logger logger) {
+ Resource targetResource = requirement.getResource();
+ // fetch the current candidate for this requirement
+ Capability currentCandidate = candidates.getFirstCandidate(requirement);
+ Resource candidateResource = currentCandidate.getResource();
+ // now check if it has any uses constraints
+ Set uses = new TreeSet<>(Util.getUses(currentCandidate));
+ if (uses.isEmpty()) {
+ // there is nothing this one can conflict in this current set of candidates
+ return Collections.emptyList();
+ }
+
+
+ if (logger.isDebugEnabled()) {
+ logger.logRequirement("=== remove uses violations for %s", requirement);
+ logger.logCapability("== current candidate is %s", currentCandidate);
+ logger.logCandidates(targetResource, req -> getCapabilityList(candidates, req));
+ }
+ boolean repeat;
+ int round = 0;
+ List dropped = new ArrayList<>();
+ do {
+ repeat = false;
+ round++;
+ if (logger.isDebugEnabled()) {
+ logger.debug("Round " + round + ":");
+ for (String usedPackage : uses) {
+ logger.debug(" uses: " + usedPackage);
+ }
+ }
+ // now look at all other imports of the target resource if it is a package that
+ // is part of a used package
+ for (Requirement packageRequirement : targetResource.getRequirements(PackageNamespace.PACKAGE_NAMESPACE)) {
+ if (packageRequirement == requirement) {
+ continue;
+ }
+ Capability providedPackage = candidates.getCapability(candidateResource, packageRequirement);
+ if (providedPackage == null) {
+ // we do not provide anything for this package
+ continue;
+ }
+ if (uses.contains(Util.getPackageName(providedPackage))) {
+ // this is a package where we are a candidate and that has a uses constraint, so
+ // this package must be provided by us as well or we run into a uses-violation
+ // later on!
+ Capability capability = removeViolators(candidates, candidateResource, packageRequirement, dropped);
+ // if we have added any additional uses we need to reiterate...
+ repeat |= uses.addAll(Util.getUses(capability));
+ }
+ }
+ } while (repeat);
+ if (logger.isDebugEnabled() && !dropped.isEmpty()) {
+ logger.debug("After removal (" + dropped.size() + " dropped)");
+ logger.logCandidates(targetResource, req -> getCapabilityList(candidates, req));
+ }
+ return dropped;
+ }
+
+ private static Capability removeViolators(Candidates candidates, Resource candidateResource,
+ Requirement packageRequirement, List dropped) {
+ Capability capability;
+ while ((capability = candidates.getFirstCandidate(packageRequirement)).getResource() != candidateResource) {
+ dropped.add(candidates.copy());
+ candidates.removeFirstCandidate(packageRequirement);
+ }
+ return capability;
+ }
+
+ private static List getCapabilityList(Candidates candidates, Requirement requirement) {
+ List list = candidates.getCandidates(requirement);
+ if (list == null) {
+ return Collections.emptyList();
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ResolverImpl.java b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ResolverImpl.java
index 77963fbe4d8..0a5d0a4347f 100644
--- a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ResolverImpl.java
+++ b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/ResolverImpl.java
@@ -18,19 +18,50 @@
*/
package org.apache.felix.resolver;
-import java.security.*;
-import java.util.*;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
-import java.util.concurrent.*;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.ToIntFunction;
import org.apache.felix.resolver.reason.ReasonException;
import org.apache.felix.resolver.util.ArrayMap;
import org.apache.felix.resolver.util.CandidateSelector;
import org.apache.felix.resolver.util.OpenHashMap;
-import org.osgi.framework.namespace.*;
-import org.osgi.resource.*;
-import org.osgi.service.resolver.*;
+import org.osgi.framework.namespace.BundleNamespace;
+import org.osgi.framework.namespace.ExecutionEnvironmentNamespace;
+import org.osgi.framework.namespace.HostNamespace;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.resource.Capability;
+import org.osgi.resource.Namespace;
+import org.osgi.resource.Requirement;
+import org.osgi.resource.Resource;
+import org.osgi.resource.Wire;
+import org.osgi.resource.Wiring;
+import org.osgi.service.resolver.HostedCapability;
+import org.osgi.service.resolver.ResolutionException;
+import org.osgi.service.resolver.ResolveContext;
+import org.osgi.service.resolver.Resolver;
public class ResolverImpl implements Resolver
{
@@ -138,6 +169,10 @@ ConcurrentMap> getUsesCache() {
return m_usesCache;
}
+ public Logger getLogger() {
+ return logger;
+ }
+
void permutateIfNeeded(PermutationType type, Requirement req, Candidates permutation) {
List candidates = permutation.getCandidates(req);
if ((candidates != null) && (candidates.size() > 1))
diff --git a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Util.java b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Util.java
index 973cd5b72c6..37b6775ce77 100644
--- a/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Util.java
+++ b/bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Util.java
@@ -18,8 +18,11 @@
*/
package org.apache.felix.resolver;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
import org.osgi.framework.Version;
import org.osgi.framework.namespace.BundleNamespace;
import org.osgi.framework.namespace.IdentityNamespace;
@@ -81,13 +84,13 @@ public static boolean isOptional(Requirement req)
public static boolean isMultiple(Requirement req)
{
- return Namespace.CARDINALITY_MULTIPLE.equals(req.getDirectives()
+ return Namespace.CARDINALITY_MULTIPLE.equals(req.getDirectives()
.get(Namespace.REQUIREMENT_CARDINALITY_DIRECTIVE)) && !isDynamic(req);
}
public static boolean isDynamic(Requirement req)
{
- return PackageNamespace.RESOLUTION_DYNAMIC.equals(req.getDirectives()
+ return PackageNamespace.RESOLUTION_DYNAMIC.equals(req.getDirectives()
.get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE));
}
@@ -97,22 +100,23 @@ public static boolean isReexport(Requirement req)
.get(BundleNamespace.REQUIREMENT_VISIBILITY_DIRECTIVE));
}
- public static List getDynamicRequirements(List reqs)
- {
- List result = new ArrayList();
- if (reqs != null)
- {
- for (Requirement req : reqs)
- {
- String resolution = req.getDirectives()
- .get(PackageNamespace.REQUIREMENT_RESOLUTION_DIRECTIVE);
- if ((resolution != null)
- && resolution.equals(PackageNamespace.RESOLUTION_DYNAMIC))
- {
- result.add(req);
- }
+ public static String getPackageName(Capability capability) {
+ if (capability != null && PackageNamespace.PACKAGE_NAMESPACE.equals(capability.getNamespace())) {
+ Object object = capability.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE);
+ if (object instanceof String) {
+ return (String) object;
+ }
+ }
+ return "";
+ }
+
+ public static Set getUses(Capability capability) {
+ if (capability != null && PackageNamespace.PACKAGE_NAMESPACE.equals(capability.getNamespace())) {
+ String uses = capability.getDirectives().get(PackageNamespace.CAPABILITY_USES_DIRECTIVE);
+ if (uses != null && !uses.isEmpty()) {
+ return Arrays.stream(uses.split(",")).map(String::trim).collect(Collectors.toSet());
}
}
- return result;
+ return Collections.emptySet();
}
}
\ No newline at end of file
diff --git a/bundles/org.eclipse.osgi/pom.xml b/bundles/org.eclipse.osgi/pom.xml
index 1d0c3458435..c8d0db88c02 100644
--- a/bundles/org.eclipse.osgi/pom.xml
+++ b/bundles/org.eclipse.osgi/pom.xml
@@ -19,7 +19,7 @@
org.eclipse.osgi
org.eclipse.osgi
- 3.21.0-SNAPSHOT
+ 3.21.100-SNAPSHOT
eclipse-plugin
diff --git a/features/org.eclipse.equinox.core.feature/feature.xml b/features/org.eclipse.equinox.core.feature/feature.xml
index 9b30abc82ff..c79a9fa006b 100644
--- a/features/org.eclipse.equinox.core.feature/feature.xml
+++ b/features/org.eclipse.equinox.core.feature/feature.xml
@@ -2,7 +2,7 @@
diff --git a/features/org.eclipse.equinox.core.sdk/feature.xml b/features/org.eclipse.equinox.core.sdk/feature.xml
index 8c08f312424..ea7111dc955 100644
--- a/features/org.eclipse.equinox.core.sdk/feature.xml
+++ b/features/org.eclipse.equinox.core.sdk/feature.xml
@@ -2,7 +2,7 @@
diff --git a/features/org.eclipse.equinox.server.core/feature.xml b/features/org.eclipse.equinox.server.core/feature.xml
index 0d4b17fe006..9ee3851b51d 100644
--- a/features/org.eclipse.equinox.server.core/feature.xml
+++ b/features/org.eclipse.equinox.server.core/feature.xml
@@ -2,7 +2,7 @@