Bug 123648 Need a way to allow Eclipse Resolver to resolve to lowest version number
diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/Resolver.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/Resolver.java
index 499186e..fd04b5f 100644
--- a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/Resolver.java
+++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/Resolver.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.osgi.service.resolver;
+import java.util.Comparator;
import java.util.Dictionary;
/**
* An implementation of a resolver which resolves the constraints of the bundles
@@ -113,4 +114,32 @@
* a value of <code>null</code> is returned if none is available.
*/
public ExportPackageDescription resolveDynamicImport(BundleDescription importingBundle, String requestedPackage);
+
+ /**
+ * Sets the selection policy for this resolver. A selection policy is used to sort
+ * possible suppliers of a version constraint in descending order. That is an order
+ * which is from most desired to least desired. The objects passed to the
+ * selection policy {@link Comparator#compare(Object, Object)} method
+ * will be of type {@link BaseDescription}. The selection policy should return a
+ * negative number, zero, or a positive number depending on if the first object is
+ * more desired, equal amount of desire, or less desired than the second object respectively.
+ * <p>
+ * If no selection policy is set then a default policy will be used which sorts according
+ * to the following rules:
+ * <ol>
+ * <li> The resolution status of the bundle which supplies the base description. Resolved bundles take priority over unresolved ones.
+ * <li> The version of the base description. Higher versions take priority over lower versions.
+ * <li> The bundle ID which supplies the base description. Lower IDs take priority over higher IDs.
+ * </ol>
+ * @param selectionPolicy the selection policy for this resolver
+ * @since 3.2
+ */
+ public void setSelectionPolicy(Comparator selectionPolicy);
+
+ /**
+ * Returns the selection policy for this resolver or null if it is not set
+ * @return the selection policy for this resolver or null if it is not set
+ * @since 3.2
+ */
+ public Comparator getSelectionPolicy();
}
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java
index e24b614..a6133cc 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverImpl.java
@@ -55,6 +55,7 @@
// Keys are BundleDescriptions, values are ResolverBundles
private HashMap bundleMapping = null;
private GroupingChecker groupingChecker;
+ private Comparator selectionPolicy;
public ResolverImpl(BundleContext context, boolean checkPermissions) {
this.permissionChecker = new PermissionChecker(context, checkPermissions, this);
@@ -66,8 +67,8 @@
// Initializes the resolver
private void initialize() {
- resolverExports = new VersionHashMap();
- resolverBundles = new VersionHashMap();
+ resolverExports = new VersionHashMap(this);
+ resolverBundles = new VersionHashMap(this);
unresolvedBundles = new ArrayList();
bundleMapping = new HashMap();
BundleDescription[] bundles = state.getBundles();
@@ -268,8 +269,13 @@
BundleDescription sameNameDesc = ((ResolverBundle) sameName[j]).getBundle();
if (sameName[j] == bundle || !sameNameDesc.isSingleton() || rejectedSingletons.contains(sameNameDesc))
continue; // Ignore the bundle we are selecting, non-singletons and rejected singletons
- // if the bundle sameNameDesc is resolved or has a greater version then reject the other bundle
- if (sameNameDesc.isResolved() || sameNameDesc.getVersion().compareTo(bundle.getBundle().getVersion()) > 0) {
+ boolean rejectedPolicy;
+ if (selectionPolicy == null)
+ // if the bundle sameNameDesc is resolved or has a greater version then reject the other bundle
+ rejectedPolicy = sameNameDesc.isResolved() || sameNameDesc.getVersion().compareTo(bundle.getBundle().getVersion()) > 0;
+ else
+ rejectedPolicy = selectionPolicy.compare(sameNameDesc, bundle.getBundle()) < 0;
+ if (rejectedPolicy) {
rejectedSingletons.add(bundle.getBundle());
return;
}
@@ -430,7 +436,8 @@
if (sameName[j] == bundles[i] || !sameNameDesc.isSingleton() || !sameNameDesc.isResolved() || rejectedSingletons.contains(sameNameDesc))
continue; // Ignore the bundle we are selecting, non-singletons, and non-resolved
result = true;
- if (sameNameDesc.getVersion().compareTo(bundleDesc.getVersion()) > 0 && sameNameBundle.getRefs() >= bundles[i].getRefs()) {
+ boolean rejectedPolicy = selectionPolicy != null ? selectionPolicy.compare(sameNameDesc, bundleDesc) < 0 : sameNameDesc.getVersion().compareTo(bundleDesc.getVersion()) > 0;
+ if (rejectedPolicy && sameNameBundle.getRefs() >= bundles[i].getRefs()) {
// this bundle is not selected; add it to the rejected list
if (!rejectedSingletons.contains(bundles[i].getBundle()))
rejectedSingletons.add(bundles[i].getBundle());
@@ -1122,4 +1129,12 @@
VersionHashMap getResolverExports() {
return resolverExports;
}
+
+ public void setSelectionPolicy(Comparator selectionPolicy) {
+ this.selectionPolicy = selectionPolicy;
+ }
+
+ public Comparator getSelectionPolicy() {
+ return selectionPolicy;
+ }
}
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/VersionHashMap.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/VersionHashMap.java
index 341e94a..5545306 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/VersionHashMap.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/VersionHashMap.java
@@ -13,6 +13,11 @@
import java.util.*;
public class VersionHashMap extends MappedList implements Comparator {
+ private ResolverImpl resolver;
+
+ public VersionHashMap(ResolverImpl resolver) {
+ this.resolver = resolver;
+ }
// sorts using the Comparator#compare method to sort
protected void sort(Object[] values) {
@@ -93,6 +98,9 @@
throw new IllegalArgumentException();
VersionSupplier vs1 = (VersionSupplier) o1;
VersionSupplier vs2 = (VersionSupplier) o2;
+ // if the selection policy is set then use that
+ if (resolver.getSelectionPolicy() != null)
+ return resolver.getSelectionPolicy().compare(vs1.getBaseDescription(), vs2.getBaseDescription());
if (vs1.getBundle().isResolved() != vs2.getBundle().isResolved())
return vs1.getBundle().isResolved() ? -1 : 1;
int versionCompare = -(vs1.getVersion().compareTo(vs2.getVersion()));