diff options
author | Thomas Watson | 2016-02-02 03:42:51 +0000 |
---|---|---|
committer | Thomas Watson | 2017-06-16 12:38:08 +0000 |
commit | ad0a1c7723fd796be14047262db64e50a0c06e9b (patch) | |
tree | 334df37e67f7fa616a7dcc2eeacf04e2f21fbce2 | |
parent | 4b92523affc9cf6cf76f42e138d7ee41bf316b35 (diff) | |
download | rt.equinox.framework-ad0a1c7723fd796be14047262db64e50a0c06e9b.tar.gz rt.equinox.framework-ad0a1c7723fd796be14047262db64e50a0c06e9b.tar.xz rt.equinox.framework-ad0a1c7723fd796be14047262db64e50a0c06e9b.zip |
Bug 486941 - [osgi R7] Framework extensions may require capabilities
from host or other attached fragments
Change-Id: I0b893396db9f0644c6f7e578f26a7971e45e7448
Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
9 files changed, 438 insertions, 96 deletions
diff --git a/bundles/org.eclipse.osgi.tests/.classpath b/bundles/org.eclipse.osgi.tests/.classpath index 47d870ee3..776247a23 100644 --- a/bundles/org.eclipse.osgi.tests/.classpath +++ b/bundles/org.eclipse.osgi.tests/.classpath @@ -123,12 +123,11 @@ <classpathentry kind="src" output="bundle_tests/test.uninstall.start1" path="bundles_src/test.uninstall.start1"/> <classpathentry kind="src" output="bundle_tests/test.uninstall.start2" path="bundles_src/test.uninstall.start2"/> <classpathentry kind="src" output="bundle_tests/ext.framework.osgiee.a.jar" path="bundles_src/ext.framework.osgiee.a"/> - <classpathentry kind="src" output="bundle_tests/ext.framework.osgiee.b.jar" path="bundles_src/ext.framework.osgiee.b"/> <classpathentry kind="src" output="bundle_tests/classloader.hooks.a" path="bundles_src/classloader.hooks.a"/> <classpathentry kind="src" output="bundle_tests/test.bug438904.host" path="bundles_src/test.bug438904.host"/> <classpathentry kind="src" output="bundle_tests/test.bug438904.frag" path="bundles_src/test.bug438904.frag"/> <classpathentry kind="src" output="bundle_tests/test.bug438904.global" path="bundles_src/test.bug438904.global"/> - <classpathentry kind="src" output="bundle_tests/test.system.nls" path="bundles_src/test.system.nls"/> + <classpathentry kind="src" output="bundle_tests/test.system.nls" path="bundles_src/test.system.nls"/> <classpathentry kind="src" output="bundle_tests/test.bug449484" path="bundles_src/test.bug449484"/> <classpathentry kind="src" output="bundle_tests/wrapper.hooks.a" path="bundles_src/wrapper.hooks.a"/> <classpathentry kind="src" output="bundle_tests/test.protocol.handler" path="bundles_src/test.protocol.handler"/> diff --git a/bundles/org.eclipse.osgi.tests/build.properties b/bundles/org.eclipse.osgi.tests/build.properties index 219cffe7a..3e6da70e7 100644 --- a/bundles/org.eclipse.osgi.tests/build.properties +++ b/bundles/org.eclipse.osgi.tests/build.properties @@ -250,8 +250,6 @@ source.bundle_tests/test.uninstall.start2.jar = bundles_src/test.uninstall.start manifest.bundle_tests/test.uninstall.start2.jar = META-INF/MANIFEST.MF source.bundle_tests/ext.framework.osgiee.a.jar = bundles_src/ext.framework.osgiee.a/ manifest.bundle_tests/ext.framework.osgiee.a.jar = META-INF/MANIFEST.MF -source.bundle_tests/ext.framework.osgiee.b.jar = bundles_src/ext.framework.osgiee.b/ -manifest.bundle_tests/ext.framework.osgiee.b.jar = META-INF/MANIFEST.MF source.bundle_tests/classloader.hooks.a.jar = bundles_src/classloader.hooks.a/ manifest.bundle_tests/classloader.hooks.a.jar = META-INF/MANIFEST.MF source.bundle_tests/test.bug438904.host.jar = bundles_src/test.bug438904.host/ @@ -398,7 +396,6 @@ jars.compile.order = bundle_tests/ext.framework.b.jar,\ bundle_tests/test.uninstall.start1.jar,\ bundle_tests/test.uninstall.start2.jar,\ bundle_tests/ext.framework.osgiee.a.jar,\ - bundle_tests/ext.framework.osgiee.b.jar,\ bundle_tests/classloader.hooks.a.jar,\ bundle_tests/test.bug438904.host.jar,\ bundle_tests/test.bug438904.frag.jar,\ diff --git a/bundles/org.eclipse.osgi.tests/bundles_src/ext.framework.osgiee.b/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi.tests/bundles_src/ext.framework.osgiee.b/META-INF/MANIFEST.MF deleted file mode 100755 index d86ed5807..000000000 --- a/bundles/org.eclipse.osgi.tests/bundles_src/ext.framework.osgiee.b/META-INF/MANIFEST.MF +++ /dev/null @@ -1,5 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-SymbolicName: ext.framework.osgiee.b -Fragment-Host: system.bundle; extension:=framework -Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.2))" diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ExtensionBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ExtensionBundleTests.java index f95ce3796..ea44651c2 100644 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ExtensionBundleTests.java +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ExtensionBundleTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2013 IBM Corporation and others. + * Copyright (c) 2007, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -13,8 +13,6 @@ package org.eclipse.osgi.tests.bundles; import java.util.List; import junit.framework.Test; import junit.framework.TestSuite; -import org.eclipse.osgi.internal.messages.Msg; -import org.eclipse.osgi.util.NLS; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; import org.osgi.framework.namespace.ExecutionEnvironmentNamespace; @@ -83,13 +81,4 @@ public class ExtensionBundleTests extends AbstractBundleTests { BundleWire eeWire = wiring.getRequiredWires(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE).get(0); assertEquals("Wrong provider for osgi.ee: " + eeWire.getProvider().getBundle(), 0, eeWire.getProvider().getBundle().getBundleId()); } - - public void testExtensionBundleWithRequireCapabilityOtherThanOsgiEeFailsToInstall() { - try { - installer.installBundle("ext.framework.osgiee.a"); - fail("Extension bundle with Require-Capability not in osgi.ee namespace did not fail to install"); - } catch (BundleException e) { - assertTrue(e.getMessage().equals(NLS.bind(Msg.OSGiManifestBuilderFactory_ExtensionReqCapError, "osgi.wiring.package"))); - } - } } 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 1bab9f5b5..96b67023b 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 @@ -2839,6 +2839,308 @@ public class TestModuleContainer extends AbstractTest { } @Test + public void testSystemBundleFragmentsPackageImport() throws BundleException, IOException { + // install the system.bundle + Module systemBundle = createContainerWithSystemBundle(true); + ModuleContainer container = systemBundle.getContainer(); + + // install an system.bundle fragment that imports framework package + Map<String, String> systemFragManifest = new HashMap<String, String>(); + systemFragManifest.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag"); + systemFragManifest.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + systemFragManifest.put(Constants.IMPORT_PACKAGE, "org.osgi.framework"); + + Module systemFrag = installDummyModule(systemFragManifest, "systemFrag", container); + + ResolutionReport report = container.resolve(Arrays.asList(systemFrag), true); + Assert.assertNull("Failed to resolve system.bundle.", report.getResolutionException()); + + List<ModuleWire> hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + assertEquals("Wrong number of fragments.", 1, hostWires.size()); + Assert.assertEquals("Unexpected fragment revision: " + hostWires, systemFrag.getCurrentRevision(), hostWires.get(0).getRequirer()); + + List<ModuleWire> systemBundleRequiredWires = systemBundle.getCurrentRevision().getWiring().getRequiredModuleWires(null); + assertEquals("No required wires expected.", 0, systemBundleRequiredWires.size()); + } + + @Test + public void testSystemBundleFragmentsNonPayloadRequirements() throws BundleException, IOException { + // install the system.bundle + Module systemBundle = createContainerWithSystemBundle(true); + ModuleContainer container = systemBundle.getContainer(); + + // install an system.bundle fragment that imports framework package + Map<String, String> systemFragManifest = new HashMap<String, String>(); + systemFragManifest.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag"); + systemFragManifest.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + systemFragManifest.put(Constants.REQUIRE_CAPABILITY, "osgi.ee; filter:=\"(osgi.ee=JavaSE)\""); + + Module systemFrag = installDummyModule(systemFragManifest, "systemFrag", container); + + ResolutionReport report = container.resolve(Arrays.asList(systemFrag), true); + Assert.assertNull("Failed to resolve system.bundle.", report.getResolutionException()); + + List<ModuleWire> hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + assertEquals("Wrong number of fragments.", 1, hostWires.size()); + Assert.assertEquals("Unexpected fragment revision: " + hostWires, systemFrag.getCurrentRevision(), hostWires.get(0).getRequirer()); + + List<ModuleWire> systemBundleRequiredWires = systemBundle.getCurrentRevision().getWiring().getRequiredModuleWires(null); + assertEquals("No required wires expected.", 0, systemBundleRequiredWires.size()); + + List<ModuleWire> fragRequiredWires = systemFrag.getCurrentRevision().getWiring().getRequiredModuleWires(null); + assertEquals("Wrong number of required wires.", 2, fragRequiredWires.size()); + assertWires(fragRequiredWires, systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(null)); + } + + @Test + public void testSystemBundleFragmentsWithPayloadRequirements() throws BundleException, IOException { + // install the system.bundle + Module systemBundle = createContainerWithSystemBundle(true); + ModuleContainer container = systemBundle.getContainer(); + + // install an system.bundle fragment that requires a payload requirement from system.bundle + Map<String, String> systemFragManifest = new HashMap<String, String>(); + systemFragManifest.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag"); + systemFragManifest.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + systemFragManifest.put(Constants.REQUIRE_CAPABILITY, "equinox.test; filter:=\"(equinox.test=system)\""); + + Module systemFrag = installDummyModule(systemFragManifest, "systemFrag", container); + + ResolutionReport report = container.resolve(Arrays.asList(systemFrag), true); + Assert.assertNull("Failed to resolve system.bundle.", report.getResolutionException()); + + List<ModuleWire> hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + assertEquals("Wrong number of fragments.", 1, hostWires.size()); + Assert.assertEquals("Unexpected fragment revision: " + hostWires, systemFrag.getCurrentRevision(), hostWires.get(0).getRequirer()); + + List<ModuleWire> systemBundleRequiredWires = systemBundle.getCurrentRevision().getWiring().getRequiredModuleWires(null); + assertEquals("Wrong number of wires.", 1, systemBundleRequiredWires.size()); + assertEquals("Wrong requirer.", systemBundle.getCurrentRevision(), systemBundleRequiredWires.get(0).getRequirer()); + assertEquals("Wrong requirement.", systemFrag.getCurrentRevision(), systemBundleRequiredWires.get(0).getRequirement().getRevision()); + + List<ModuleWire> fragRequiredWires = systemFrag.getCurrentRevision().getWiring().getRequiredModuleWires(null); + assertEquals("Wrong number of required wires.", 1, fragRequiredWires.size()); + assertWires(fragRequiredWires, hostWires); + } + + @Test + public void testSystemBundleFragmentRequiresOtherFragment() throws BundleException, IOException { + // install the system.bundle + Module systemBundle = createContainerWithSystemBundle(true); + ModuleContainer container = systemBundle.getContainer(); + + // install an system.bundle fragment that provides a capability + Map<String, String> systemFragManifest1 = new HashMap<String, String>(); + systemFragManifest1.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest1.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag1"); + systemFragManifest1.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + systemFragManifest1.put(Constants.PROVIDE_CAPABILITY, "fragment.capability; fragment.capability=test"); + Module systemFrag1 = installDummyModule(systemFragManifest1, "systemFrag1", container); + + // install an system.bundle fragment that requires a fragment capability + Map<String, String> systemFragManifest2 = new HashMap<String, String>(); + systemFragManifest2.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest2.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag2"); + systemFragManifest2.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + systemFragManifest2.put(Constants.REQUIRE_CAPABILITY, "fragment.capability; filter:=\"(fragment.capability=test)\""); + Module systemFrag2 = installDummyModule(systemFragManifest2, "systemFrag2", container); + + ResolutionReport report = container.resolve(Arrays.asList(systemFrag2), true); + Assert.assertNull("Failed to resolve system.bundle.", report.getResolutionException()); + + List<ModuleWire> hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + assertEquals("Wrong number of fragments.", 2, hostWires.size()); + + List<ModuleWire> systemBundleRequiredWires = systemBundle.getCurrentRevision().getWiring().getRequiredModuleWires(null); + assertEquals("Wrong number of wires.", 1, systemBundleRequiredWires.size()); + assertEquals("Wrong requirer.", systemBundle.getCurrentRevision(), systemBundleRequiredWires.get(0).getRequirer()); + assertEquals("Wrong requirement.", systemFrag2.getCurrentRevision(), systemBundleRequiredWires.get(0).getRequirement().getRevision()); + assertEquals("Wrong provider.", systemBundle.getCurrentRevision(), systemBundleRequiredWires.get(0).getProvider()); + assertEquals("Wrong capability.", systemFrag1.getCurrentRevision(), systemBundleRequiredWires.get(0).getCapability().getRevision()); + + List<ModuleWire> fragRequiredWires = systemFrag2.getCurrentRevision().getWiring().getRequiredModuleWires(null); + assertEquals("Wrong number of required wires.", 1, fragRequiredWires.size()); + assertWires(fragRequiredWires, hostWires); + } + + @Test + public void testSystemBundleFragmentRequiresOtherFragmentFailResolution() throws BundleException, IOException { + // install the system.bundle + Module systemBundle = createContainerWithSystemBundle(true); + ModuleContainer container = systemBundle.getContainer(); + + // install an system.bundle fragment that provides a capability + Map<String, String> systemFragManifest1 = new HashMap<String, String>(); + systemFragManifest1.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest1.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag1"); + systemFragManifest1.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + systemFragManifest1.put(Constants.PROVIDE_CAPABILITY, "fragment.capability; fragment.capability=test1"); + Module systemFrag1 = installDummyModule(systemFragManifest1, "systemFrag1", container); + + // install an system.bundle fragment that requires a fragment capability, but fails to match + Map<String, String> systemFragManifest2 = new HashMap<String, String>(); + systemFragManifest2.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest2.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag2"); + systemFragManifest2.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + systemFragManifest2.put(Constants.REQUIRE_CAPABILITY, "fragment.capability; filter:=\"(fragment.capability=test4)\""); + systemFragManifest2.put(Constants.PROVIDE_CAPABILITY, "fragment.capability; fragment.capability=test2"); + Module systemFrag2 = installDummyModule(systemFragManifest2, "systemFrag2", container); + + // install an system.bundle fragment that requires a fragment capability from a fragment that fails to resolve + Map<String, String> systemFragManifest3 = new HashMap<String, String>(); + systemFragManifest3.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest3.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag3"); + systemFragManifest3.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + systemFragManifest3.put(Constants.REQUIRE_CAPABILITY, "fragment.capability; filter:=\"(fragment.capability=test2)\""); + systemFragManifest3.put(Constants.PROVIDE_CAPABILITY, "fragment.capability; fragment.capability=test3"); + Module systemFrag3 = installDummyModule(systemFragManifest3, "systemFrag3", container); + + ResolutionReport report = container.resolve(Arrays.asList(systemFrag3), true); + Assert.assertNotNull("Expected failure message", report.getResolutionException()); + + List<ModuleWire> hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + assertEquals("Wrong number of fragments.", 1, hostWires.size()); + List<ModuleWire> systemFrag1HostWires = systemFrag1.getCurrentRevision().getWiring().getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); + assertWires(systemFrag1HostWires, hostWires); + + // install a bundle that can satisfy the failed requirement, but it should not be allowed since it is not a fragment + Map<String, String> provideCapabilityManifest1 = new HashMap<String, String>(); + provideCapabilityManifest1.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + provideCapabilityManifest1.put(Constants.BUNDLE_SYMBOLICNAME, "provideCapabilityBundle1"); + provideCapabilityManifest1.put(Constants.PROVIDE_CAPABILITY, "fragment.capability; fragment.capability=test4"); + installDummyModule(provideCapabilityManifest1, "provideCapabilityBundle1", container); + + hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + assertEquals("Wrong number of fragments.", 1, hostWires.size()); + systemFrag1HostWires = systemFrag1.getCurrentRevision().getWiring().getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); + assertWires(systemFrag1HostWires, hostWires); + + // install a fragment that satisfies the failed requirement + Map<String, String> systemFragManifest4 = new HashMap<String, String>(); + systemFragManifest4.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest4.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag4"); + systemFragManifest4.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + systemFragManifest4.put(Constants.PROVIDE_CAPABILITY, "fragment.capability; fragment.capability=test4"); + Module systemFrag4 = installDummyModule(systemFragManifest4, "systemFrag4", container); + + report = container.resolve(Arrays.asList(systemFrag3), true); + Assert.assertNull("Failed to resolve.", report.getResolutionException()); + + hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + assertEquals("Wrong number of fragments.", 4, hostWires.size()); + systemFrag1HostWires = systemFrag1.getCurrentRevision().getWiring().getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); + List<ModuleWire> systemFrag2HostWires = systemFrag2.getCurrentRevision().getWiring().getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); + List<ModuleWire> systemFrag3HostWires = systemFrag3.getCurrentRevision().getWiring().getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); + List<ModuleWire> systemFrag4HostWires = systemFrag4.getCurrentRevision().getWiring().getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); + assertWires(systemFrag1HostWires, hostWires); + assertWires(systemFrag2HostWires, hostWires); + assertWires(systemFrag3HostWires, hostWires); + assertWires(systemFrag4HostWires, hostWires); + + List<ModuleCapability> fragmentCapabilities = systemBundle.getCurrentRevision().getWiring().getModuleCapabilities("fragment.capability"); + assertEquals("Wrong number of fragment capabilities.", 4, fragmentCapabilities.size()); + // Use set since the order of required and provided wires will be different + Set<ModuleWire> hostRequiredFragmentCapWires = new HashSet<ModuleWire>(systemBundle.getCurrentRevision().getWiring().getRequiredModuleWires("fragment.capability")); + Set<ModuleWire> hostProvidedFragmentCapWires = new HashSet<ModuleWire>(systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires("fragment.capability")); + assertEquals("Wrong number of wires.", 2, hostProvidedFragmentCapWires.size()); + assertEquals("Wrong wires found from host.", hostRequiredFragmentCapWires, hostProvidedFragmentCapWires); + } + + @Test + public void testMultipleSystemBundleFragmentsWithSameName() throws BundleException, IOException { + // install the system.bundle + Module systemBundle = createContainerWithSystemBundle(true); + ModuleContainer container = systemBundle.getContainer(); + + // install multiple versions of the same fragment + Map<String, String> systemFragManifest1 = new HashMap<String, String>(); + systemFragManifest1.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest1.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag"); + systemFragManifest1.put(Constants.BUNDLE_VERSION, "1.0"); + systemFragManifest1.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + Module systemFrag1 = installDummyModule(systemFragManifest1, "systemFrag1", container); + + // first attempt to resolve the lowest version before installing the others + ResolutionReport report = container.resolve(Arrays.asList(systemFrag1), true); + Assert.assertNull("Unexpected failure message", report.getResolutionException()); + + List<ModuleWire> hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + assertEquals("Wrong number of fragments.", 1, hostWires.size()); + List<ModuleWire> systemFrag1HostWires = systemFrag1.getCurrentRevision().getWiring().getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); + assertWires(systemFrag1HostWires, hostWires); + + Map<String, String> systemFragManifest2 = new HashMap<String, String>(); + systemFragManifest2.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest2.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag"); + systemFragManifest2.put(Constants.BUNDLE_VERSION, "2.0"); + systemFragManifest2.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + Module systemFrag2 = installDummyModule(systemFragManifest2, "systemFrag2", container); + + Map<String, String> systemFragManifest3 = new HashMap<String, String>(); + systemFragManifest3.put(Constants.BUNDLE_MANIFESTVERSION, "2"); + systemFragManifest3.put(Constants.BUNDLE_SYMBOLICNAME, "systemFrag"); + systemFragManifest3.put(Constants.BUNDLE_VERSION, "3.0"); + systemFragManifest3.put(Constants.FRAGMENT_HOST, Constants.SYSTEM_BUNDLE_SYMBOLICNAME); + Module systemFrag3 = installDummyModule(systemFragManifest3, "systemFrag3", container); + + report = container.resolve(Arrays.asList(systemFrag2), true); + Assert.assertNotNull("Expected failure message", report.getResolutionException()); + report = container.resolve(Arrays.asList(systemFrag3), true); + Assert.assertNotNull("Expected failure message", report.getResolutionException()); + + hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + assertEquals("Wrong number of fragments.", 1, hostWires.size()); + systemFrag1HostWires = systemFrag1.getCurrentRevision().getWiring().getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); + assertWires(systemFrag1HostWires, hostWires); + + // uninstall the fragments so we can start over + container.uninstall(systemFrag1); + container.uninstall(systemFrag2); + container.uninstall(systemFrag3); + + // refresh the system bundle to get only it resolved + report = container.refresh(Collections.singleton(systemBundle)); + Assert.assertNull("Unexpected failure message", report.getResolutionException()); + hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + assertEquals("Wrong number of fragments.", 0, hostWires.size()); + + // install the fragments again + systemFrag1 = installDummyModule(systemFragManifest1, "systemFrag1", container); + systemFrag2 = installDummyModule(systemFragManifest2, "systemFrag2", container); + systemFrag3 = installDummyModule(systemFragManifest3, "systemFrag3", container); + + report = container.resolve(Arrays.asList(systemFrag1), true); + Assert.assertNotNull("Expected failure message", report.getResolutionException()); + report = container.resolve(Arrays.asList(systemFrag2), true); + Assert.assertNotNull("Expected failure message", report.getResolutionException()); + report = container.resolve(Arrays.asList(systemFrag3), true); + Assert.assertNull("Unexpected failure message", report.getResolutionException()); + + hostWires = systemBundle.getCurrentRevision().getWiring().getProvidedModuleWires(HostNamespace.HOST_NAMESPACE); + List<ModuleWire> systemFrag3HostWires = systemFrag3.getCurrentRevision().getWiring().getRequiredModuleWires(HostNamespace.HOST_NAMESPACE); + assertWires(systemFrag3HostWires, hostWires); + } + + private Module createContainerWithSystemBundle(boolean resolveSystemBundle) throws BundleException, IOException { + DummyContainerAdaptor adaptor = createDummyAdaptor(); + ModuleContainer container = adaptor.getContainer(); + + // install the system.bundle + String systemCapability = "osgi.ee; osgi.ee=\"JavaSE\"; version:List<Version>=\"1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6\", equinox.test; equinox.test=system, osgi.native; osgi.native.osname=test"; + Module systemBundle = installDummyModule("system.bundle.MF", Constants.SYSTEM_BUNDLE_LOCATION, Constants.SYSTEM_BUNDLE_SYMBOLICNAME, null, systemCapability, container); + if (resolveSystemBundle) { + ResolutionReport report = container.resolve(Collections.singleton(systemBundle), true); + Assert.assertNull("Found resolution exception.", report.getResolutionException()); + Assert.assertEquals("System is not resolved.", State.RESOLVED, systemBundle.getState()); + } + + return systemBundle; + } + + @Test public void testSplitPackageUses01() throws BundleException { DummyContainerAdaptor adaptor = createDummyAdaptor(); ModuleContainer container = adaptor.getContainer(); 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 6e1f16f5c..90321aa1e 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 @@ -77,8 +77,9 @@ final class ModuleResolver { DEBUG_REPORT = debugAll || options.getBooleanOption(OPTION_REPORT, false); } - private static final Collection<String> NON_PAYLOAD_CAPABILITIES = Arrays.asList(IdentityNamespace.IDENTITY_NAMESPACE); + static final Collection<String> NON_PAYLOAD_CAPABILITIES = Arrays.asList(IdentityNamespace.IDENTITY_NAMESPACE); static final Collection<String> NON_PAYLOAD_REQUIREMENTS = Arrays.asList(HostNamespace.HOST_NAMESPACE, ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE); + static final Collection<String> NON_SUBSTITUTED_REQUIREMENTS = Arrays.asList(PackageNamespace.PACKAGE_NAMESPACE, BundleNamespace.BUNDLE_NAMESPACE); final ThreadLocal<Boolean> threadResolving = new ThreadLocal<>(); final ModuleContainerAdaptor adaptor; @@ -542,8 +543,8 @@ final class ModuleResolver { private final Collection<ModuleRevision> triggers; private final Collection<ModuleRevision> optionals; private final boolean triggersMandatory; - private final ModuleDatabase moduleDatabase; - private final Map<ModuleRevision, ModuleWiring> wirings; + final ModuleDatabase moduleDatabase; + final Map<ModuleRevision, ModuleWiring> wirings; private final Set<ModuleRevision> previouslyResolved; private final DynamicModuleRequirement dynamicReq; private volatile ResolverHook hook = null; @@ -636,7 +637,7 @@ final class ModuleResolver { return filterProviders(requirement, candidates, true); } - private List<Capability> filterProviders(Requirement requirement, List<ModuleCapability> candidates, boolean filterResolvedHosts) { + List<Capability> filterProviders(Requirement requirement, List<ModuleCapability> candidates, boolean filterResolvedHosts) { ListIterator<ModuleCapability> iCandidates = candidates.listIterator(); filterDisabled(iCandidates); removeNonEffectiveCapabilities(iCandidates); @@ -1196,6 +1197,96 @@ final class ModuleResolver { value.add(capability); } + class DynamicFragments { + private final ModuleCapability hostCapability; + private final Map<String, ModuleRevision> fragments = new HashMap<>(); + private final Set<ModuleRevision> validProviders = new HashSet<>(); + boolean fragmentAdded = false; + + DynamicFragments(ModuleWiring hostWiring, ModuleCapability hostCapability) { + this.hostCapability = hostCapability; + validProviders.add(hostWiring.getRevision()); + for (ModuleWire hostWire : hostWiring.getProvidedModuleWires(HostNamespace.HOST_NAMESPACE)) { + validProviders.add(hostWire.getRequirer()); + fragments.put(hostWire.getRequirer().getSymbolicName(), hostWire.getRequirer()); + } + } + + void addFragment(ModuleRevision fragment) { + ModuleRevision existing = fragments.get(fragment.getSymbolicName()); + if (existing == null) { + fragments.put(fragment.getSymbolicName(), fragment); + validProviders.add(fragment); + fragmentAdded = true; + } + } + + Map<Resource, List<Wire>> getNewWires() { + if (!fragmentAdded) { + return Collections.emptyMap(); + } + Map<Resource, List<Wire>> result = new HashMap<>(); + boolean retry; + do { + retry = false; + result.clear(); + fragmentsLoop: for (Iterator<Map.Entry<String, ModuleRevision>> iFragments = fragments.entrySet().iterator(); iFragments.hasNext();) { + Map.Entry<String, ModuleRevision> fragmentEntry = iFragments.next(); + if (wirings.get(fragmentEntry.getValue()) == null) { + for (ModuleRequirement req : fragmentEntry.getValue().getModuleRequirements(null)) { + ModuleRevision requirer = NON_PAYLOAD_REQUIREMENTS.contains(req.getNamespace()) ? req.getRevision() : hostCapability.getRevision(); + List<Wire> newWires = result.get(requirer); + if (newWires == null) { + newWires = new ArrayList<>(); + result.put(requirer, newWires); + } + if (HostNamespace.HOST_NAMESPACE.equals(req.getNamespace())) { + newWires.add(new ModuleWire(hostCapability, hostCapability.getRevision(), req, requirer)); + } else { + if (failToWire(req, requirer, newWires)) { + iFragments.remove(); + validProviders.remove(req.getRevision()); + retry = true; + break fragmentsLoop; + } + } + } + } + } + } while (retry); + return result; + } + + private boolean failToWire(ModuleRequirement requirement, ModuleRevision requirer, List<Wire> wires) { + List<ModuleCapability> matching = moduleDatabase.findCapabilities(requirement); + List<Wire> newWires = new ArrayList<>(0); + filterProviders(requirement, matching, false); + for (ModuleCapability candidate : matching) { + // If the requirer equals the requirement revision then this is a non-payload requirement. + // We let non-payload requirements come from anywhere. + // Payload requirements must come from the host or one of the fragments attached to the host + if (requirer.equals(requirement.getRevision()) || validProviders.contains(candidate.getRevision())) { + ModuleRevision provider = NON_PAYLOAD_CAPABILITIES.contains(candidate.getNamespace()) ? candidate.getRevision() : hostCapability.getRevision(); + // if there are multiple candidates; then check for cardinality + if (newWires.isEmpty() || Namespace.CARDINALITY_MULTIPLE.equals(requirement.getDirectives().get(Namespace.REQUIREMENT_CARDINALITY_DIRECTIVE))) { + newWires.add(new ModuleWire(candidate, provider, requirement, requirer)); + } + } + } + if (newWires.isEmpty()) { + if (!Namespace.RESOLUTION_OPTIONAL.equals(requirement.getDirectives().get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE))) { + // could not resolve mandatory requirement; + return true; + } + } + // only create the wire if the namespace is a non-substituted namespace (e.g. NOT package) + if (!NON_SUBSTITUTED_REQUIREMENTS.contains(requirement.getNamespace())) { + wires.addAll(newWires); + } + return false; + } + } + private Map<Resource, List<Wire>> resolveNonPayLoadFragments() { // This is to support dynamic attachment of fragments that do not // add any payload requirements to their host. @@ -1203,75 +1294,63 @@ final class ModuleResolver { // host is always resolved. // It is also useful for things like NLS fragments that are installed later // without the need to refresh the host. - Collection<ModuleRevision> nonPayLoadFrags = new ArrayList<>(); + List<ModuleRevision> dynamicAttachableFrags = new ArrayList<>(); if (triggersMandatory) { for (ModuleRevision moduleRevision : triggers) { - if (nonPayLoad(moduleRevision)) { - nonPayLoadFrags.add(moduleRevision); + if ((moduleRevision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) { + dynamicAttachableFrags.add(moduleRevision); } } } for (ModuleRevision moduleRevision : optionals) { - if (nonPayLoad(moduleRevision)) { - nonPayLoadFrags.add(moduleRevision); + if ((moduleRevision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) { + dynamicAttachableFrags.add(moduleRevision); } } - if (nonPayLoadFrags.isEmpty()) { + if (dynamicAttachableFrags.isEmpty()) { return Collections.emptyMap(); } - Map<Resource, List<Wire>> dynamicAttachment = new HashMap<>(0); - for (ModuleRevision nonPayLoad : nonPayLoadFrags) { - List<Wire> allNonPayloadWires = new ArrayList<>(0); - for (ModuleRequirement requirement : nonPayLoad.getModuleRequirements(null)) { - List<ModuleCapability> matching = moduleDatabase.findCapabilities(requirement); - List<Wire> newWires = new ArrayList<>(0); - filterProviders(requirement, matching, false); - for (ModuleCapability candidate : matching) { - if (HostNamespace.HOST_NAMESPACE.equals(requirement.getNamespace())) { - String attachDirective = candidate.getDirectives().get(HostNamespace.CAPABILITY_FRAGMENT_ATTACHMENT_DIRECTIVE); + Collections.sort(dynamicAttachableFrags, new Comparator<ModuleRevision>() { + @Override + public int compare(ModuleRevision r1, ModuleRevision r2) { + // we only care about versions here + return -(r1.getVersion().compareTo(r2.getVersion())); + } + }); + + Map<ModuleCapability, DynamicFragments> hostDynamicFragments = new HashMap<>(); + // first find the hosts to dynamically attach to + for (ModuleRevision dynamicAttachableFragment : dynamicAttachableFrags) { + List<ModuleRequirement> requirements = dynamicAttachableFragment.getModuleRequirements(null); + for (ModuleRequirement requirement : requirements) { + if (HostNamespace.HOST_NAMESPACE.equals(requirement.getNamespace())) { + List<ModuleCapability> matchingHosts = moduleDatabase.findCapabilities(requirement); + filterProviders(requirement, matchingHosts, false); + for (ModuleCapability hostCandidate : matchingHosts) { + ModuleWiring hostWiring = wirings.get(hostCandidate.getRevision()); + String attachDirective = hostCandidate.getDirectives().get(HostNamespace.CAPABILITY_FRAGMENT_ATTACHMENT_DIRECTIVE); boolean attachAlways = attachDirective == null || HostNamespace.FRAGMENT_ATTACHMENT_ALWAYS.equals(attachDirective); // only do this if the candidate host is already resolved and it allows dynamic attachment - if (!attachAlways || wirings.get(candidate.getRevision()) == null) { + if (!attachAlways || hostWiring == null) { continue; } + DynamicFragments dynamicFragments = hostDynamicFragments.get(hostCandidate); + if (dynamicFragments == null) { + dynamicFragments = new DynamicFragments(hostWiring, hostCandidate); + hostDynamicFragments.put(hostCandidate, dynamicFragments); + } + dynamicFragments.addFragment(requirement.getRevision()); } - // if there are multiple candidates; then check for cardinality - if (newWires.isEmpty() || Namespace.CARDINALITY_MULTIPLE.equals(requirement.getDirectives().get(Namespace.REQUIREMENT_CARDINALITY_DIRECTIVE))) { - newWires.add(new ModuleWire(candidate, candidate.getRevision(), requirement, nonPayLoad)); - } - } - if (newWires.isEmpty()) { - if (!Namespace.RESOLUTION_OPTIONAL.equals(requirement.getDirectives().get(Namespace.REQUIREMENT_RESOLUTION_DIRECTIVE))) { - // could not resolve mandatory requirement; - // clear out the wires to prevent resolution - allNonPayloadWires.clear(); - break; - } - } else { - allNonPayloadWires.addAll(newWires); } } - if (!allNonPayloadWires.isEmpty()) { - // we found some wires to resolve the fragment - dynamicAttachment.put(nonPayLoad, allNonPayloadWires); - } } - return dynamicAttachment; - } - - private boolean nonPayLoad(ModuleRevision moduleRevision) { - if ((moduleRevision.getTypes() & BundleRevision.TYPE_FRAGMENT) == 0) { - // not a fragment - return false; - } - for (Requirement req : moduleRevision.getRequirements(null)) { - if (!NON_PAYLOAD_REQUIREMENTS.contains(req.getNamespace())) { - // fragment adds payload to host - return false; - } + // now try to get the new wires for each host + Map<Resource, List<Wire>> dynamicWires = new HashMap<>(); + for (DynamicFragments dynamicFragments : hostDynamicFragments.values()) { + dynamicWires.putAll(dynamicFragments.getNewWires()); } - return true; + return dynamicWires; } private Map<Resource, List<Wire>> resolveDynamic() throws ResolutionException { 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 4b8256e2e..adb94d0a2 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 @@ -208,23 +208,8 @@ public final class OSGiManifestBuilderFactory { throw new BundleException(message + " : " + NLS.bind(Msg.HEADER_EXTENSION_ERROR, hostName), BundleException.MANIFEST_ERROR); //$NON-NLS-1$ } } else { - if (manifest.get(Constants.IMPORT_PACKAGE) != null) - throw new BundleException(Msg.OSGiManifestBuilderFactory_ExtensionImportError, BundleException.MANIFEST_ERROR); if (manifest.get(Constants.REQUIRE_BUNDLE) != null) throw new BundleException(Msg.OSGiManifestBuilderFactory_ExtensionReqBundleError, BundleException.MANIFEST_ERROR); - if (manifest.get(Constants.REQUIRE_CAPABILITY) != null) { - ManifestElement[] manifestElements = ManifestElement.parseHeader(Constants.REQUIRE_CAPABILITY, manifest.get(Constants.REQUIRE_CAPABILITY)); - if (manifestElements != null) { - for (ManifestElement manifestElement : manifestElements) { - for (String value : manifestElement.getValueComponents()) { - if (!ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE.equals(value)) { - throw new BundleException(NLS.bind(Msg.OSGiManifestBuilderFactory_ExtensionReqCapError, value), BundleException.MANIFEST_ERROR); - } - } - } - } - - } if (manifest.get(Constants.BUNDLE_NATIVECODE) != null) throw new BundleException(Msg.OSGiManifestBuilderFactory_ExtensionNativeError, BundleException.MANIFEST_ERROR); diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/messages/ExternalMessages.properties b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/messages/ExternalMessages.properties index dc3660828..a6e5ed09a 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/messages/ExternalMessages.properties +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/messages/ExternalMessages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2003, 2013 IBM Corporation and others. +# Copyright (c) 2003, 2016 IBM Corporation and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at @@ -139,10 +139,8 @@ ModuleResolutionReport_UsesConstraintError=Bundle was not resolved because of a ModuleResolver_RecursiveError=Detected a recursive resolve operation. ModuleResolver_SingletonDisabledError=Could not resolve mandatory modules because another singleton was selected or the module was disabled: -OSGiManifestBuilderFactory_ExtensionImportError=Extension bundles cannot import packages. OSGiManifestBuilderFactory_ExtensionNativeError=Extension bundles cannot have native code. OSGiManifestBuilderFactory_ExtensionReqBundleError=Extension bundles cannot require bundles. -OSGiManifestBuilderFactory_ExtensionReqCapError=Extension bundles cannot require capabilities outside of the osgi.ee namespace: {0}. OSGiManifestBuilderFactory_InvalidManifestError=Invalid Manifest header "{0}": {1} SystemModule_LockError=Could not lock the system bundle state for shutdown. diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/messages/Msg.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/messages/Msg.java index fffc117e0..814cfe35d 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/messages/Msg.java +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/internal/messages/Msg.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2013 IBM Corporation and others. + * Copyright (c) 2004, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -147,10 +147,8 @@ public class Msg extends NLS { public static String ModuleResolver_RecursiveError; public static String ModuleResolver_SingletonDisabledError; - public static String OSGiManifestBuilderFactory_ExtensionImportError; public static String OSGiManifestBuilderFactory_ExtensionNativeError; public static String OSGiManifestBuilderFactory_ExtensionReqBundleError; - public static String OSGiManifestBuilderFactory_ExtensionReqCapError; public static String OSGiManifestBuilderFactory_InvalidManifestError; public static String BundleContextImpl_LoadActivatorError; |