/* * 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.framework; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import junit.framework.TestCase; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.osgi.framework.launch.Framework; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWiring; import org.osgi.resource.Capability; import org.osgi.resource.Resource; public class RequirementsCapabilitiesTest extends TestCase { private File tempDir; private Framework felix; private File cacheDir; @Override protected void setUp() throws Exception { super.setUp(); tempDir = File.createTempFile("felix-temp", ".dir"); assertTrue("precondition", tempDir.delete()); assertTrue("precondition", tempDir.mkdirs()); cacheDir = new File(tempDir, "felix-cache"); assertTrue("precondition", cacheDir.mkdir()); String cache = cacheDir.getPath(); Map<String,String> params = new HashMap<String, String>(); params.put("felix.cache.profiledir", cache); params.put("felix.cache.dir", cache); params.put(Constants.FRAMEWORK_STORAGE, cache); felix = new Felix(params); felix.init(); felix.start(); } @Override protected void tearDown() throws Exception { super.tearDown(); felix.stop(); // Note that this method is async felix = null; deleteDir(tempDir); tempDir = null; cacheDir = null; } public void testIdentityCapabilityBundleFragment() throws Exception { String bmf = "Bundle-SymbolicName: cap.bundle\n" + "Bundle-Version: 1.2.3.Blah\n" + "Bundle-ManifestVersion: 2\n" + "Import-Package: org.osgi.framework\n"; File bundleFile = createBundle(bmf); String fmf = "Bundle-SymbolicName: cap.frag\n" + "Bundle-Version: 1.0.0\n" + "Fragment-Host: cap.bundle\n" + "Bundle-ManifestVersion: 2\n" + "Export-Package: org.foo.bar;version=\"2.0.0\"\n" + "Import-Package: org.osgi.util.tracker\n"; File fragFile = createBundle(fmf); Bundle b = felix.getBundleContext().installBundle(bundleFile.toURI().toASCIIString()); Bundle f = felix.getBundleContext().installBundle(fragFile.toURI().toASCIIString()); // Check the bundle capabilities. // First check the capabilities on the Bundle Revision, which is available on installed bundles BundleRevision bbr = b.adapt(BundleRevision.class); List<Capability> bwbCaps = bbr.getCapabilities("osgi.wiring.bundle"); assertEquals(1, bwbCaps.size()); Map<String, Object> expectedBWBAttrs = new HashMap<String, Object>(); expectedBWBAttrs.put("osgi.wiring.bundle", "cap.bundle"); expectedBWBAttrs.put("bundle-version", Version.parseVersion("1.2.3.Blah")); Capability expectedBWBCap = new TestCapability("osgi.wiring.bundle", expectedBWBAttrs, Collections.<String, String>emptyMap()); assertCapsEquals(expectedBWBCap, bwbCaps.get(0)); List<Capability> bwhCaps = bbr.getCapabilities("osgi.wiring.host"); assertEquals(1, bwhCaps.size()); Map<String, Object> expectedBWHAttrs = new HashMap<String, Object>(); expectedBWHAttrs.put("osgi.wiring.host", "cap.bundle"); expectedBWHAttrs.put("bundle-version", Version.parseVersion("1.2.3.Blah")); Capability expectedBWHCap = new TestCapability("osgi.wiring.host", expectedBWHAttrs, Collections.<String, String>emptyMap()); assertCapsEquals(expectedBWHCap, bwhCaps.get(0)); List<Capability> bwiCaps = bbr.getCapabilities("osgi.identity"); assertEquals(1, bwiCaps.size()); Map<String, Object> expectedBWIAttrs = new HashMap<String, Object>(); expectedBWIAttrs.put("osgi.identity", "cap.bundle"); expectedBWIAttrs.put("type", "osgi.bundle"); expectedBWIAttrs.put("version", Version.parseVersion("1.2.3.Blah")); Capability expectedBWICap = new TestCapability("osgi.identity", expectedBWIAttrs, Collections.<String, String>emptyMap()); assertCapsEquals(expectedBWICap, bwiCaps.get(0)); assertEquals("The Bundle should not directly expose osgi.wiring.package", 0, bbr.getCapabilities("osgi.wiring.package").size()); // Check the fragment's capabilities. // First check the capabilities on the Bundle Revision, which is available on installed fragments BundleRevision fbr = f.adapt(BundleRevision.class); List<Capability> fwpCaps = fbr.getCapabilities("osgi.wiring.package"); assertEquals(1, fwpCaps.size()); Map<String, Object> expectedFWAttrs = new HashMap<String, Object>(); expectedFWAttrs.put("osgi.wiring.package", "org.foo.bar"); expectedFWAttrs.put("version", Version.parseVersion("2")); expectedFWAttrs.put("bundle-symbolic-name", "cap.frag"); expectedFWAttrs.put("bundle-version", Version.parseVersion("1.0.0")); Capability expectedFWCap = new TestCapability("osgi.wiring.package", expectedFWAttrs, Collections.<String, String>emptyMap()); assertCapsEquals(expectedFWCap, fwpCaps.get(0)); List<Capability> fiCaps = fbr.getCapabilities("osgi.identity"); assertEquals(1, fiCaps.size()); Map<String, Object> expectedFIAttrs = new HashMap<String, Object>(); expectedFIAttrs.put("osgi.identity", "cap.frag"); expectedFIAttrs.put("type", "osgi.fragment"); expectedFIAttrs.put("version", Version.parseVersion("1.0.0")); Capability expectedFICap = new TestCapability("osgi.identity", expectedFIAttrs, Collections.<String, String>emptyMap()); assertCapsEquals(expectedFICap, fiCaps.get(0)); // Start the bundle. This will make the BundleWiring available on both the bundle and the fragment b.start(); // Check the Bundle Wiring on the fragment. It should only contain the osgi.identity capability // All the other capabilities should have migrated to the bundle's BundleWiring. BundleWiring fbw = f.adapt(BundleWiring.class); List<BundleCapability> fbwCaps = fbw.getCapabilities(null); assertEquals("Fragment should only have 1 capability: it's osgi.identity", 1, fbwCaps.size()); assertCapsEquals(expectedFICap, fbwCaps.get(0)); // Check the Bundle Wiring on the bundle. It should contain all the capabilities originally on the // bundle and also contain the osgi.wiring.package capability from the fragment. BundleWiring bbw = b.adapt(BundleWiring.class); List<BundleCapability> bwbCaps2 = bbw.getCapabilities("osgi.wiring.bundle"); assertEquals(1, bwbCaps2.size()); assertCapsEquals(expectedBWBCap, bwbCaps2.get(0)); List<BundleCapability> bwhCaps2 = bbw.getCapabilities("osgi.wiring.host"); assertEquals(1, bwhCaps2.size()); assertCapsEquals(expectedBWHCap, bwhCaps2.get(0)); List<BundleCapability> bwiCaps2 = bbw.getCapabilities("osgi.identity"); assertEquals(1, bwiCaps2.size()); assertCapsEquals(expectedBWICap, bwiCaps2.get(0)); List<BundleCapability> bwpCaps2 = bbw.getCapabilities("osgi.wiring.package"); assertEquals("Bundle should have inherited the osgi.wiring.package capability from the fragment", 1, bwpCaps2.size()); assertCapsEquals(expectedFWCap, bwpCaps2.get(0)); } public void testIdentityCapabilityFrameworkExtension() throws Exception { String femf = "Bundle-SymbolicName: fram.ext\n" + "Bundle-Version: 1.2.3.test\n" + "Fragment-Host: system.bundle; extension:=framework\n" + "Bundle-ManifestVersion: 2\n" + "Export-Package: org.foo.bar;version=\"2.0.0\"\n"; File feFile = createBundle(femf); Bundle fe = felix.getBundleContext().installBundle(feFile.toURI().toASCIIString()); BundleRevision fbr = fe.adapt(BundleRevision.class); List<Capability> feCaps = fbr.getCapabilities("osgi.identity"); assertEquals(1, feCaps.size()); Map<String, Object> expectedFEAttrs = new HashMap<String, Object>(); expectedFEAttrs.put("osgi.identity", "fram.ext"); expectedFEAttrs.put("type", "osgi.fragment"); expectedFEAttrs.put("version", Version.parseVersion("1.2.3.test")); Capability expectedFICap = new TestCapability("osgi.identity", expectedFEAttrs, Collections.<String, String>emptyMap()); assertCapsEquals(expectedFICap, feCaps.get(0)); } private File createBundle(String manifest) throws IOException { File f = File.createTempFile("felix-bundle", ".jar", tempDir); Manifest mf = new Manifest(new ByteArrayInputStream(manifest.getBytes("utf-8"))); mf.getMainAttributes().putValue("Manifest-Version", "1.0"); JarOutputStream os = new JarOutputStream(new FileOutputStream(f), mf); os.close(); return f; } private static void assertCapsEquals(Capability expected, Capability actual) { assertEquals(expected.getNamespace(), actual.getNamespace()); assertSubMap(expected.getAttributes(), actual.getAttributes()); assertSubMap(expected.getDirectives(), actual.getDirectives()); // We ignore the resource in the comparison } private static void assertSubMap(Map<?,?> subMap, Map<?,?> fullMap) { for (Map.Entry<?,?> entry : subMap.entrySet()) { assertEquals(entry.getValue(), fullMap.get(entry.getKey())); } } private static void deleteDir(File root) throws IOException { if (root.isDirectory()) { for (File file : root.listFiles()) { deleteDir(file); } } assertTrue(root.delete()); } static class TestCapability implements Capability { private final String namespace; private final Map<String, Object> attributes; private final Map<String, String> directives; TestCapability(String ns, Map<String,Object> attrs, Map<String,String> dirs) { namespace = ns; attributes = attrs; directives = dirs; } public String getNamespace() { return namespace; } public Map<String, Object> getAttributes() { return attributes; } public Map<String, String> getDirectives() { return directives; } public Resource getResource() { return null; } } }