Bug 201489 [osgi R5] multiple versions of a fragment should not attach to the same host
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/StateResolverTest.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/StateResolverTest.java
index 7b1da6f..563b5a7 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/StateResolverTest.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/StateResolverTest.java
@@ -1795,6 +1795,56 @@
assertTrue("3.4", aExports[1] == bImports[1]);
}
+ public void testFragmentsMultipleVersion() throws BundleException {
+ State state = buildEmptyState();
+ int bundleID = 0;
+ // test the selection algorithm of the resolver to pick the bundles which
+ // resolve the largest set of bundles; with fragments using Import-Package
+ Hashtable manifest = new Hashtable();
+
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "A");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0");
+ BundleDescription a1 = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME) + '_' + (String) manifest.get(Constants.BUNDLE_VERSION), bundleID++);
+
+ manifest.clear();
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "AFrag");
+ manifest.put(Constants.BUNDLE_VERSION, "1.0");
+ manifest.put(Constants.FRAGMENT_HOST, "A");
+ BundleDescription aFrag1 = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME) + '_' + (String) manifest.get(Constants.BUNDLE_VERSION), bundleID++);
+
+ manifest.clear();
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "A");
+ manifest.put(Constants.BUNDLE_VERSION, "2.0");
+ BundleDescription a2 = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME) + '_' + (String) manifest.get(Constants.BUNDLE_VERSION), bundleID++);
+
+ manifest.clear();
+ manifest.put(Constants.BUNDLE_MANIFESTVERSION, "2");
+ manifest.put(Constants.BUNDLE_SYMBOLICNAME, "AFrag");
+ manifest.put(Constants.BUNDLE_VERSION, "2.0");
+ manifest.put(Constants.FRAGMENT_HOST, "A");
+ BundleDescription aFrag2 = state.getFactory().createBundleDescription(state, manifest, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME) + '_' + (String) manifest.get(Constants.BUNDLE_VERSION), bundleID++);
+
+ state.addBundle(a1);
+ state.addBundle(aFrag1);
+ state.addBundle(a2);
+ state.addBundle(aFrag2);
+ state.resolve();
+ assertTrue("0.1", a1.isResolved());
+ assertTrue("0.2", aFrag1.isResolved());
+ assertTrue("0.3", a2.isResolved());
+ assertTrue("0.4", aFrag2.isResolved());
+
+ state.removeBundle(a2);
+ state.resolve(false);
+ assertTrue("1.1", a1.isResolved());
+ assertTrue("1.2", aFrag2.isResolved());
+ assertFalse("1.3", aFrag1.isResolved());
+ assertEquals("1.4", a1, aFrag2.getHost().getSupplier());
+ }
+
public void testReexportPackage() throws BundleException {
State state = buildEmptyState();
Hashtable manifest = new Hashtable();
diff --git a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF
index 726a00a..3a902ee 100644
--- a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF
@@ -54,7 +54,7 @@
Bundle-Description: %systemBundle
Bundle-Copyright: %copyright
Bundle-Vendor: %eclipse.org
-Bundle-Version: 3.3.2.qualifier
+Bundle-Version: 3.3.3.qualifier
Bundle-Localization: systembundle
Bundle-DocUrl: http://www.eclipse.org
Eclipse-ExtensibleAPI: true
diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverBundle.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverBundle.java
index 063f159..f3da5c8 100644
--- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverBundle.java
+++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/module/ResolverBundle.java
@@ -322,6 +322,14 @@
fragment.setNewFragmentExports(true);
initFragments();
+ // need to make sure there is not already another version of this fragment
+ // already attached to this host
+ for (Iterator iFragments = fragments.iterator(); iFragments.hasNext();) {
+ ResolverBundle existingFragment = (ResolverBundle) iFragments.next();
+ String bsn = existingFragment.getName();
+ if (bsn != null && bsn.equals(fragment.getName()))
+ return new ResolverExport[0];
+ }
if (fragments.contains(fragment))
return new ResolverExport[0];
fragments.add(fragment);
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 fb62a6c..763a8f0 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
@@ -285,7 +285,22 @@
}
// Attach fragment to its host
- private void attachFragment(ResolverBundle bundle, ArrayList rejectedSingletons) {
+ private void attachFragment(ResolverBundle bundle, ArrayList rejectedSingletons, ArrayList processedFragments) {
+ if (processedFragments.contains(bundle.getName()))
+ return;
+ processedFragments.add(bundle.getName());
+ // we want to attach multiple versions of the same fragment
+ // from highest version to lowest to give the higher versions first pick
+ // of the available host bundles.
+ Object[] fragments = resolverBundles.get(bundle.getName());
+ for (int i = 0; i < fragments.length; i++) {
+ ResolverBundle fragment = (ResolverBundle) fragments[i];
+ if (!fragment.isResolved())
+ attachFragment0(fragment, rejectedSingletons);
+ }
+ }
+
+ private void attachFragment0(ResolverBundle bundle, ArrayList rejectedSingletons) {
if (!bundle.isFragment() || !bundle.isResolvable() || rejectedSingletons.contains(bundle.getBundle()))
return;
// no need to select singletons now; it will be done when we select the rest of the singleton bundles (bug 152042)
@@ -462,8 +477,9 @@
// need to sort bundles to keep consistent order for fragment attachment (bug 174930)
Arrays.sort(bundles);
// First attach all fragments to the matching hosts
+ ArrayList processedFragments = new ArrayList(bundles.length);
for (int i = 0; i < bundles.length; i++)
- attachFragment(bundles[i], rejectedSingletons);
+ attachFragment(bundles[i], rejectedSingletons, processedFragments);
// Lists of cyclic dependencies recording during resolving
ArrayList cycle = new ArrayList(1); // start small