package test; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import java.util.regex.Matcher; import java.util.regex.Pattern; import aQute.bnd.header.Attrs; import aQute.bnd.header.OSGiHeader; import aQute.bnd.header.Parameters; import aQute.bnd.osgi.Analyzer; import aQute.bnd.osgi.Builder; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Domain; import aQute.bnd.osgi.EmbeddedResource; import aQute.bnd.osgi.Jar; import aQute.bnd.osgi.Packages; import aQute.bnd.osgi.Processor; import aQute.bnd.osgi.Resource; import aQute.bnd.osgi.Verifier; import aQute.bnd.test.BndTestCase; import aQute.bnd.version.Version; import aQute.lib.collections.SortedList; import aQute.lib.hex.Hex; import aQute.lib.io.IO; import aQute.service.reporter.Report.Location; @SuppressWarnings("resource") public class BuilderTest extends BndTestCase { /** * In the bnd file for bndlib, we include DS annotations 1.3 and osgi.cmpn 5 * (which includes DS annotations 1.2) on the -buildpath. We use a * -split-package directive to select the first package (DS annotations 1.3) * for the bundle. However during -sources: true processing, bnd ignores the * -split-package directive and includes the sources from all the -buildpath * entries. The means that the DS annotations 1.2 source, coming later in * the -buildpath, overlays the DS annotations 1.3 source. The result is a * mish-mash of DS annotations 1.2 and 1.3 source in OSGI-OPT/src. */ public static void testSplitSourcesFirst() throws Exception { Builder bmaker = new Builder(); try { bmaker.addClasspath(new File("bin")); bmaker.addClasspath(new File("jar/osgi.jar")); bmaker.addClasspath(new File("jar/osgi-3.0.0.jar")); bmaker.setSourcepath(new File[] { new File("src") }); bmaker.setProperty("-sources", "true"); bmaker.setProperty("Export-Package", "org.osgi.framework;-split-package:=first, a"); Jar jar = bmaker.build(); assertTrue(bmaker.check()); assertNotNull(jar.getResource("OSGI-OPT/src/a/A.java")); assertNotNull(jar.getResource("OSGI-OPT/src/a/B.java")); InputStream in = jar.getResource("OSGI-OPT/src/org/osgi/framework/Bundle.java").openInputStream(); assertNotNull(in); byte[] fw = IO.read(in); assertEquals(39173, fw.length); } finally { bmaker.close(); } } public static void testSplitSourcesMergeLast() throws Exception { Builder bmaker = new Builder(); try { bmaker.addClasspath(new File("bin")); bmaker.addClasspath(new File("jar/osgi.jar")); bmaker.addClasspath(new File("jar/osgi-3.0.0.jar")); bmaker.setSourcepath(new File[] { new File("src") }); bmaker.setProperty("-sources", "true"); bmaker.setProperty("Export-Package", "org.osgi.framework;-split-package:=merge-last, a"); Jar jar = bmaker.build(); assertNotNull(jar.getResource("OSGI-OPT/src/a/A.java")); assertNotNull(jar.getResource("OSGI-OPT/src/a/B.java")); assertTrue(bmaker.check("Version for package org.osgi.framework is set to different values")); InputStream in = jar.getResource("OSGI-OPT/src/org/osgi/framework/Bundle.java").openInputStream(); assertNotNull(in); byte[] fw = IO.read(in); assertEquals(25783, fw.length); } finally { bmaker.close(); } } /** * #1017 Wrong import version range being generated On one project I depend * on bundle A and bundle B. Both only export packages in version 1.0. No * package is exported by both of them. But B also embeds one package from A * in version 2.0 (via * http://njbartlett.name/2014/05/26/static-linking.html) but that one * package is not exported from B. Now if the classpath first contains B * then A the import-package statement being generated for that package * (being embedded in B in version 2.0 and exported from A in 1.0) has a * version range starting with 2.0 (which is wrong). Only if the classpath * contains A first and then B, it takes the right import version range for * that package (namely starting with 1.0) I use the maven-bundle-plugin * 2.5.3 with bndlib 2.4.0. */ public void test1017UsingPrivatePackagesVersion() throws Exception { Builder A = new Builder(); A.addClasspath(new File("jar/osgi.jar")); A.setExportPackage("org.osgi.service.event"); A.build(); assertTrue(A.check()); Builder B = new Builder(); B.addClasspath(new File("jar/osgi.jar")); B.setExportPackage("org.osgi.service.wireadmin"); B.setPrivatePackage("org.osgi.service.event"); B.setIncludeResource("org/osgi/service/event/packageinfo;literal='version 2.0.0'"); B.build(); assertTrue(B.check()); Builder B_A = new Builder(); B_A.addClasspath(B.getJar()); B_A.addClasspath(A.getJar()); B_A.addClasspath(new File("bin")); B_A.setPrivatePackage("test.reference_to_eventadmin"); B_A.build(); assertTrue(B_A.check()); assertEquals("[1.0,2)", B_A.getImports().getByFQN("org.osgi.service.event").getVersion()); Builder A_B = new Builder(); A_B.addClasspath(A.getJar()); A_B.addClasspath(B.getJar()); A_B.addClasspath(new File("bin")); A_B.setPrivatePackage("test.reference_to_eventadmin"); A_B.build(); assertTrue(A_B.check()); assertEquals("[1.0,2)", A_B.getImports().getByFQN("org.osgi.service.event").getVersion()); } /** * #971 bnd does not import exported package used by an imported/exported * package When building org.osgi.impl.service.async bundle in OSGi build, * the bundle exports the org.osgi.util.promise and org.osgi.util.function * packages. org.osgi.util.promise uses org.osgi.util.function. bnd * correctly exports both packages but only imports org.osgi.util.promise. * * <pre> * Export-Package: * org.osgi.service.async;version="1.0";uses:="org.osgi.framework,org.osgi. * util.promise",org.osgi.service.async.delegate;version="1.0";uses:="org. * osgi.util.promise",org.osgi.util.promise;version="1.0";uses:="org.osgi. * util.function",org.osgi.util.function;version="1.0" Import-Package: * org.osgi.framework;version="[1.6,2)",org.osgi.framework.wiring;version="[ * 1.0,2)",org.osgi.service.async;version="[1.0,1.1)",org.osgi.service.async * .delegate;version="[1.0,2)",org.osgi.service.log;version="[1.3,2)",org. * osgi.util.promise;version="[1.0,1.1)",org.osgi.util.tracker;version="[1.5 * ,2)" Tool: Bnd-3.0.0.201506011706 * </pre> * * So effectively the offer to import org.osgi.util.promise is broken. If * the framework wanted to resolve the bundle by importing * org.osgi.util.promise, that package has a uses constraint on * org.osgi.util.function and since the bundle only exports * org.osgi.util.function, the framework can only resolve the bundle to * another exporter of org.osgi.util.promise if that exporter imports * org.osgi.util.function from this bundle. Obviously that wont work for * additional bundle attempting the same thing. bnd fails to also import * org.osgi.util.function. This issue exists in bnd 2.4.1 and master. We * have 4 packages * * <pre> * p1 -> p2 exported (makes p2 importable) p2 -> none exported (force to * import by p1) p3 -> p1 private (makes p1 importable) p4 -> p3 exported * (p4 cannot be imported due to private ref) * * <pre> */ public void testNoImportForUsedExport_971() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setExportPackage("test.missingimports_971.p1,test.missingimports_971.p2,test.missingimports_971.p4"); b.setPrivatePackage("test.missingimports_971.p3"); b.build(); assertTrue(b.check()); assertTrue(b.getExports().containsFQN("test.missingimports_971.p1")); assertTrue(b.getExports().containsFQN("test.missingimports_971.p2")); assertTrue(b.getExports().containsFQN("test.missingimports_971.p4")); assertTrue(b.getImports().containsFQN("test.missingimports_971.p1")); assertTrue(b.getImports().containsFQN("test.missingimports_971.p2")); b.getJar().getManifest().write(System.out); } /* * Private package header doesn't allow the use of negation (!) #840 */ public void testNegationInPrivatePackage_840() throws Exception { Builder b = new Builder(); b.setProperty(Constants.STRICT, "true"); b.addClasspath(IO.getFile("jar/osgi.jar")); b.setPrivatePackage("!org.osgi.service.event,org.osgi.service.*"); b.build(); assertTrue(b.check()); } /* * Warn about missing packages in export */ public void testWarnAboutMissingExports() throws Exception { Builder b = new Builder(); b.setProperty(Constants.STRICT, "true"); b.addClasspath(IO.getFile("jar/osgi.jar")); b.setIncludeResource("foo;literal='bla'"); // get rid of warningt b.setExportPackage("bar"); b.build(); assertTrue(b.check("\\QExport-Package or -exportcontents refers to missing package 'bar'\\E")); } /* * Warn about imports to private imports */ public void testWarnAboutPrivateImportsFromExport() throws Exception { Builder p3 = setupP3(); p3.setExportPackage("test.activator;version=2"); p3.setPrivatePackage("test.activator.inherits"); p3.build(); assertTrue(p3.check("Import package org\\.osgi\\..* not found in any bundle ")); p3.getJar().getManifest().write(System.out); } /* * Warn about imports to private imports */ public void testWarnAboutPrivateImports() throws Exception { Builder p3 = setupP3(); p3.setExportPackage("test.activator.inherits;version=0.0.0"); p3.build(); assertTrue(p3.check("Import package test.activator not found in any bundle on the -buildpath.")); p3.getJar().getManifest().write(System.out); } private Builder setupP3() throws Exception { Builder p1 = new Builder(); p1.setProperty("Bundle-SymbolicName", "p1"); p1.setProperty("Bundle-Version", "1.2.3"); p1.setPrivatePackage("test.activator"); p1.addClasspath(new File("bin")); p1.addClasspath(new File("jar/osgi.jar")); p1.build(); assertTrue(p1.check()); Builder p2 = new Builder(); p1.setProperty("Bundle-SymbolicName", "p2"); p2.setExportPackage("test.activator.inherits"); p2.addClasspath(new File("bin")); p2.build(); assertTrue(p2.check()); Builder p3 = new Builder(); p3.setProperty("Bundle-SymbolicName", "p3"); p3.setProperty("-check", "ALL"); p3.addClasspath(p1.getJar()); p3.addClasspath(p2.getJar()); return p3; } /** * #708 if a bundle has a.b.c but imports a.b then bnd cannot find the * version of a.b because the scanning of a.b.c already has set the * information for a.b to "nothing". The learnPackage() method must be * adapted so that "empty" package do not occupy a position This was * diagnosed by Balázs Zsoldos balazs.zsoldos@everit.biz * * @throws Exception */ public void testOverlappingPackageMissesImportVersions() throws Exception { Builder exporter = new Builder(); exporter.setExportPackage("test._708.a.b"); exporter.addClasspath(new File("bin")); exporter.build(); assertTrue(exporter.check()); // // We need to build a temp entry because if we include 'bin' // on the final build then we see the a.b package there, and // there it has information // Builder temp = new Builder(); temp.setPrivatePackage("test._708.a.b.c"); temp.addClasspath(new File("bin")); temp.build(); assertTrue(temp.check()); Builder importer = new Builder(); importer.setPrivatePackage("test._708.a.b.c"); importer.addClasspath(temp.getJar()); importer.addClasspath(exporter.getJar()); importer.build(); assertTrue(importer.check()); assertEquals("test._708.a.b;version=\"1.2.3\"", exporter.getJar().getManifest().getMainAttributes().getValue("Export-Package")); assertEquals("test._708.a.b;version=\"[1.2,2)\"", importer.getJar().getManifest().getMainAttributes().getValue("Import-Package")); } /** * Test if the Manifest gets the last modified date */ public void testLastModifiedForManifest() throws Exception { File file = new File("tmp.jar"); try { long time = System.currentTimeMillis(); Builder b = new Builder(); b.addClasspath(IO.getFile("jar/osgi.jar")); b.setExportPackage("org.osgi.framework"); Jar build = b.build(); try { assertTrue(b.check()); build.write("tmp.jar"); Jar ajr = new Jar(file); try { Resource r = ajr.getResource("META-INF/MANIFEST.MF"); assertNotNull(r); long t = r.lastModified(); Date date = new Date(t); System.out.println(date + " " + t); // TODO we need to adapt the timestamp handling assertTrue(date + " " + t, t == 1142555622000L); } finally { ajr.close(); } } finally { build.close(); } } finally { file.delete(); } } /** * A Require-Bundle should not fail on missing imports, just warn * * @throws Exception */ public void testMissingImportWithRequireBundle() throws Exception { Builder b = new Builder(); try { b.addClasspath(new File("bin")); b.setPedantic(true); b.setExportPackage("test.classreference;version=1"); b.setImportPackage("!*"); b.setProperty("Require-Bundle", "com.abc"); b.build(); assertTrue(b.check()); Verifier v = new Verifier(b.getJar()); v.verify(); assertTrue(v.check()); } finally { b.close(); } } /** * #479 I have now tested this locally. Apparently the fix doesn't change * the reported behavior. In my test bundle, I have removed all imports. Bnd * builds this with no errors reported. I add: DynamicImport-Package: dummy */ public void testMissingImportsWithDynamicImport() throws Exception { Builder b = new Builder(); try { b.addClasspath(new File("bin")); b.setPedantic(true); b.setExportPackage("test.classreference;version=1"); b.setImportPackage("!*"); b.setProperty(Constants.DYNAMICIMPORT_PACKAGE, "dummy"); b.build(); assertTrue(b.check()); Verifier v = new Verifier(b.getJar()); try { v.verify(); assertTrue(v.check("Unresolved references to \\[javax.swing\\] by class\\(es\\)")); } finally { v.close(); } } finally { b.close(); } } /** * #479 I have now tested this locally. Apparently the fix doesn't change * the reported behavior. In my test bundle, I have removed all imports. Bnd * builds this with no errors reported. I add: DynamicImport-Package: dummy */ public void testMissingImportsWithoutDynamicImport() throws Exception { Builder b = new Builder(); try { b.addClasspath(new File("bin")); b.setPedantic(true); b.setExportPackage("test.classreference;version=1"); b.setImportPackage("!*"); b.build(); assertTrue(b.check()); Verifier v = new Verifier(b.getJar()); try { v.verify(); assertTrue(v.check("Unresolved references to \\[javax.swing\\] by class\\(es\\)")); } finally { v.close(); } } finally { b.close(); } } /** * <pre> * [2013-12-11 15:55:14] BJ Hargrave: init: [echo] Enter project * org.osgi.test.cases.prefs (${top}) [bndprepare] 2 WARNINGS [bndprepare] * No translation found for macro: * classes;extending;junit.framework.TestCase;concrete [bndprepare] No * translation found for macro: classes,concrete [2013-12-11 15:55:31] BJ * Hargrave: I am getting this on the latest bnd.master in the OSGi test * projects * </pre> * * @throws Exception */ public static void testClassQuery() throws Exception { Builder a = new Builder(); try { a.addClasspath(new File("bin")); a.setExportPackage("test.component"); a.setProperty("testcases", "${sort;${classes;extending;junit.framework.TestCase;concrete}}"); a.setProperty("Test-Cases", "${testcases}"); a.setProperty("-dsannotations", "!*"); a.setProperty("-metatypeannotations", "!*"); Jar jar = a.build(); assertTrue(a.check()); Manifest m = jar.getManifest(); Parameters p = new Parameters(m.getMainAttributes().getValue("Test-Cases")); assertTrue(p.size() >= 4); } finally { a.close(); } } /** * Bundle ActivationPolicy * * @throws Exception */ public void testBundleActivationPolicy() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("bin")); ; b.setProperty("Bundle-ActivationPolicy", "lazy"); b.setProperty("Export-Package", "test.activator"); b.build(); assertTrue(b.check()); } finally { b.close(); } } /** * #388 Manifest header to get GIT head * * @throws IOException */ public void testGitHead() throws IOException { Builder b = new Builder(); try { String s = b.getReplacer().process("${githead}"); assertTrue(Hex.isHex(s)); } finally { b.close(); } } /** * If a package-info.java + packageinfo are present then normally * package-info takes precedence if it sets a Version. This test sees that * if no version is sets, packageinfo is used. */ public void testPackageInfo_no_version() throws Exception { Builder b = new Builder(); try { b.addClasspath(new File("bin")); b.setExportPackage("test.packageinfo.both_no_version"); Jar build = b.build(); assertTrue(b.check()); Attrs imports = b.getExports().getByFQN("test.packageinfo.both_no_version"); assertEquals("1.2.3", imports.getVersion()); } finally { b.close(); } } /** * An old osgi 3.0.0 jar had an old packageinfo in it. This included some * never well developed syntax which now clashes with the proprty syntax. * * @throws Exception */ public void testVeryOldPackageInfo() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi-3.0.0.jar")); b.setExportPackage("org.osgi.util.measurement;version=100, org.osgi.util.tracker;version=100, *"); Jar build = b.build(); assertTrue( b.check("Version for package org.osgi.util.measurement is set to different values in the source ", "Version for package org.osgi.util.tracker is set to different values in the source")); } finally { b.close(); } } /** * Using a package info without the version keyword gives strange results in * the manifest, should generate an error. */ public void testBadPackageInfo() throws Exception { Builder b = new Builder(); try { b.addClasspath(new File("bin")); b.setExportPackage("test.package_info_versioniskey"); b.build(); String message = b.getErrors().get(0); assertTrue("The lacking version error first", message.contains("package info for test.package_info_versioniskey attribute [1.0.0=''],")); Location location = b.getLocation(message); assertNotNull("Supposed to have a location", location); assertNotNull("And that must have a file", location.file); assertEquals("Which should be the packaginfo file", "packageinfo", new File(location.file).getName()); assertEquals(4, location.line); assertEquals(5, location.length); assertTrue(b.check("package info for test.package_info_versioniskey attribute \\[1.0.0=''\\],")); } finally { b.close(); } } /** * https://github.com/bndtools/bnd/issues/359 Starts with a bundle that has * one package 'a' containing classes A and B. First removes B from 'a', and * checks that the last modified date of the resulting bundle changed. Then * removes A from 'a', and checks again that the last modified data changed. */ public static void testRemoveClassFromPackage() throws Exception { try { Builder b = new Builder(); try { IO.getFile("bin/a1/a").mkdirs(); IO.copy(IO.getFile("bin/a/A.class"), IO.getFile("bin/a1/a/A.class")); IO.copy(IO.getFile("bin/a/B.class"), IO.getFile("bin/a1/a/B.class")); Jar classpath = new Jar(IO.getFile("bin/a1")); b.addClasspath(classpath); b.setPrivatePackage("a"); Jar result = b.build(); Resource ra = result.getResource("a/A.class"); Resource rb = result.getResource("a/B.class"); long lm1 = result.lastModified(); assertTrue("Last modified date of bundle > 0", lm1 > 0); // windows has a very low resolution sometimes Thread.sleep(isWindows() ? 1000 : 100); IO.getFile("bin/a1/a/B.class").delete(); classpath.remove("a/B.class"); classpath.updateModified(System.currentTimeMillis(), "Removed file B"); result = b.build(); long lm2 = result.lastModified(); assertTrue("Last modified date of bundle has increased after deleting class from package", lm2 > lm1); // windows has a very low resolution sometimes Thread.sleep(isWindows() ? 1000 : 100); IO.getFile("bin/a1/a/A.class").delete(); classpath.remove("a/A.class"); classpath.updateModified(System.currentTimeMillis(), "Removed file A"); // windows has a very low resolution sometimes Thread.sleep(isWindows() ? 1000 : 100); result = b.build(); long lm3 = result.lastModified(); assertTrue("Last modified date of bundle has increased after deleting last class from package", lm3 > lm2); } finally { b.close(); } } finally { try { IO.getFile("bin/a1/a/A.class").delete(); } catch (Exception e) {} try { IO.getFile("bin/a1/a/B.class").delete(); } catch (Exception e) {} try { IO.getFile("bin/a1/a").delete(); } catch (Exception e) {} try { IO.getFile("bin/a1").delete(); } catch (Exception e) {} } } private static boolean isWindows() { return File.separatorChar == '\\'; } /** * https://github.com/bndtools/bnd/issues/315 Turns out bnd doesn't seem to * support a class in a capitalized package name. I accidentally called a * package with a capital letter and I get the strange error message and a * refusal to build it. (See title for error message) My package could be * named "Coffee" and the package named "CoffeeClient", The bnd.bnd file * could have: Private-Package: Coffee I'm running 2.0.0REL with Eclipse * Juno. */ public static void testUpperCasePackage() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("bin")); b.setExportPackage("UPPERCASEPACKAGE"); b.build(); assertTrue(b.check()); b.getExports().containsFQN("UPPERCASEPACKAGE"); } finally { b.close(); } } /** * Dave Smith <dave.smith@candata.com> I have pulled the latest from git and * am testing out 2.0 with our current application. I am getting the * following error message on the bnd.bnd file null, for cmd : classes, * arguments [classes;CONCRETE;ANNOTATION;javax.persistence.Entity] My bnd * file does have the following line ... Hibernate-Db = * ${classes;CONCRETE;ANNOTATION;javax.persistence.Entity} * * @throws Exception */ public static void testClasses() throws Exception { Builder b = new Builder(); try { b.setProperty("x", "${classes;CONCRETE;ANNOTATION;aQute.bnd.annotation.component.Component}"); b.setProperty("y", "${classes;CONCRETE;ANNOTATED;aQute.bnd.annotation.component.Component}"); b.setProperty("z", "${classes;CONCRETE;ANNOTATEDX;x.y.Z}"); b.setPrivatePackage("test"); b.addClasspath(IO.getFile("bin")); b.build(); String s = b.getProperty("x"); assertEquals(s, b.getProperty("y")); assertTrue(s.contains("test.Target")); assertEquals("${classes;CONCRETE;ANNOTATEDX;x.y.Z}", b.getProperty("z")); assertTrue(b.check("ANNOTATEDX")); } finally { b.close(); } } /** * Check if we can create digests * * @throws Exception */ public static void testDigests() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile(new File(""), "jar/osgi.jar")); b.setExportPackage("org.osgi.framework"); b.setProperty(Constants.DIGESTS, "MD5, SHA1"); Jar jar = b.build(); assertTrue(b.check()); File f = File.createTempFile("test", ".jar"); jar.write(f); Jar other = new Jar(f); Manifest manifest = other.getManifest(); assertNotNull(manifest); Attributes attrs = manifest.getAttributes("org/osgi/framework/BundleActivator.class"); assertNotNull(attrs); assertEquals("RTRhr3kadnulINegRhpmog==", attrs.getValue("MD5-Digest")); assertEquals("BfVfpnE3Srx/0UWwtzNecrAGf8A=", attrs.getValue("SHA-Digest")); other.close(); } finally { b.close(); } } /** * FELIX-3407 Utterly confusing example that states that generic references * are not picked up. The classes under test are in * {@link test.genericinterf.a.A}, {@link test.genericinterf.b.B}, and * {@link test.genericinterf.c.C}. */ public static void testGenericPickup() throws Exception { Builder b = new Builder(); try { b.setPrivatePackage("test.genericinterf.a"); b.addClasspath(new File("bin")); b.build(); assertTrue(b.check()); System.out.println(b.getImports()); assertTrue(b.getImports().containsFQN("test.genericinterf.b")); assertTrue(b.getImports().containsFQN("test.genericinterf.c")); } finally { b.close(); } } /** * Github #130 Consider the following descriptor file: Bundle-Activator: * org.example.Activator Private-Package: org.example Now suppose that at * build time, bnd cannot find the package org.example, or it is empty. Bnd * sees the Bundle-Activator instruction as creating a dependency, so it * generates a manifest containing an import for that package: * Import-Package: org.example This is unexpected. If a Private-Package * instruction is given with a specific package name (i.e. not a wildcard), * and that package does not exist or is empty, then bnd should fail or * print an error. * * @throws Exception */ public static void testPrivatePackageNonExistent() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.setBundleActivator("com.example.Activator"); b.setPrivatePackage("com.example"); b.setIncludeResource("p;literal='x'"); b.build(); assertTrue(b.check("on the class path: \\[com.example\\]", "Bundle-Activator com.example.Activator is being imported")); } finally { b.close(); } } /** * #41 Test the EE macro */ public static void testEEMacro() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/ifc112.jar")); b.setPrivatePackage("netscape.util.*"); b.setBundleRequiredExecutionEnvironment("${ee}"); Jar jar = b.build(); assertTrue(b.check()); Domain domain = Domain.domain(jar.getManifest()); Parameters ee = domain.getBundleRequiredExecutionEnvironment(); System.err.println(ee); assertTrue(ee.containsKey("JRE-1.1")); } finally { b.close(); } } public static void testEEMacro2() throws Exception { String[] packages = { "eclipse_1_1", "eclipse_1_2", "eclipse_1_3", "eclipse_1_4", "eclipse_1_5", "eclipse_1_6", "eclipse_1_7", "eclipse_jsr14", "sun_1_8" }; String[] ees = { "JRE-1.1", "J2SE-1.2", "J2SE-1.3", "J2SE-1.4", "J2SE-1.5", "JavaSE-1.6", "JavaSE-1.7", "J2SE-1.4", "JavaSE-1.8" }; String[] versions = { "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.4", "1.8" }; Pattern p = Pattern.compile("\\(&\\(osgi.ee=JavaSE\\)\\(version=(" + Version.VERSION_STRING + ")\\)\\)"); for (int i = 0; i < packages.length; i++) { Builder b = new Builder(); try { b.addClasspath(IO.getFile("compilerversions/compilerversions.jar")); b.setPrivatePackage(packages[i]); b.setBundleRequiredExecutionEnvironment("${ee}"); Jar jar = b.build(); assertTrue(b.check()); Domain domain = Domain.domain(jar.getManifest()); Parameters ee = domain.getBundleRequiredExecutionEnvironment(); System.err.println(ee); assertEquals(ees[i], ee.toString()); // // Check the requirements // Parameters een = domain.getRequireCapability(); assertFalse(een.isEmpty()); Attrs attrs = een.get("osgi.ee"); String filter = attrs.get("filter:"); Matcher m = p.matcher(filter); assertTrue(m.matches()); assertEquals(versions[i], m.group(1)); } finally { b.close(); } } } /** * bnd issues Consider the following descriptor file: * * <pre> * Bundle-Activator: org.example.Activator Private-Package: org.example * </pre> * * Now suppose that at build time, bnd cannot find the package org.example, * or it is empty. Bnd sees the Bundle-Activator instruction as creating a * dependency, so it generates a manifest containing an import for that * package: * * <pre> * Import-Package: org.example * </pre> * * This is unexpected. If a Private-Package instruction is given with a * specific package name (i.e. not a wildcard), and that package does not * exist or is empty, then bnd should fail or print an error. */ public static void testReportEmptyPrivatePackage() throws Exception { Builder b = new Builder(); try { b.addClasspath(new File("bin")); b.setPrivatePackage("does.not.exist"); b.build(); assertTrue(b.check("The JAR is empty", "Unused Private-Package instruction")); } finally { b.close(); } } /** * Test the name section */ public static void testNamesection() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.setProperty(Constants.NAMESECTION, "org/osgi/service/event/*;MD5='${md5;${@}}';SHA1='${sha1;${@}}';MD5H='${md5;${@};hex}'"); b.setProperty(Constants.PRIVATEPACKAGE, "org.osgi.service.event"); Jar build = b.build(); assertOk(b); build.calcChecksums(new String[] { "MD5", "SHA1" }); assertTrue(b.check()); Manifest m = build.getManifest(); m.write(System.err); assertNotNull(m.getAttributes("org/osgi/service/event/EventAdmin.class").getValue("MD5")); assertNotNull(m.getAttributes("org/osgi/service/event/EventAdmin.class").getValue("SHA1")); assertEquals(m.getAttributes("org/osgi/service/event/EventAdmin.class").getValue("MD5-Digest"), m.getAttributes("org/osgi/service/event/EventAdmin.class").getValue("MD5")); } finally { b.close(); } } /** * Test the digests */ // public void testDigests() throws Exception { // Builder b = new Builder(); // b.addClasspath(IO.getFile("jar/osgi.jar")); // b.setProperty(Constants.DIGESTS, "MD5, SHA1"); // b.setProperty(Constants.PRIVATE_PACKAGE, "*"); // Jar build = b.build(); // assertOk(b); // // Manifest m = build.getManifest(); // assertEquals(261, build.getResources().size()); // // for (Entry<String,Resource> e : build.getResources().entrySet()) { // System.out.println("Path " + e.getKey()); // // Attributes attrs = m.getAttributes(e.getKey()); // assertNotNull(e.getKey(), attrs); // boolean md5 = false, sha1 = false; // // for (Entry<Object,Object> ee : attrs.entrySet()) { // String name = ee.getKey().toString().toLowerCase(); // if (name.endsWith("-digest")) { // String value = ee.getValue().toString().trim(); // assertNotNull("original digest", value); // // byte[] original = Base64.decodeBase64(value); // assertNotNull("original digest", original); // // String alg = name.substring(0, name.length() - 7); // if (alg.equals("md5")) // md5 = true; // if (alg.equals("sha1")) // sha1 = true; // // MessageDigest md = MessageDigest.getInstance(alg); // InputStream in = e.getValue().openInputStream(); // byte[] buffer = new byte[8000]; // int size = in.read(buffer); // while (size > 0) { // md.update(buffer, 0, size); // size = in.read(buffer); // } // byte calculated[] = md.digest(); // assertTrue("comparing digests " + e.getKey() + " " + value + " " + // Base64.encodeBase64(calculated), // Arrays.equals(original, calculated)); // } // } // assertTrue("expected md5", md5); // assertTrue("expected sha1", sha1); // } // } /** * Check of the use of x- directives are not skipped. bnd allows x- * directives in the import/export clauses but strips other ones. * * @throws Exception */ public static void testXDirectives() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.setProperty("Export-Package", "org.osgi.framework;x-foo:=true;bar:=false"); Jar jar = b.build(); assertTrue(b.check("bar:")); Manifest m = jar.getManifest(); String s = m.getMainAttributes().getValue("Export-Package"); assertTrue(s.contains("x-foo:")); } finally { b.close(); } } /** * Check of SNAPSHOT is replaced with the -snapshot instr * * @throws Exception */ public static void testSnapshot() throws Exception { Builder b = new Builder(); try { b.setProperty("-resourceonly", "true"); b.setProperty("-snapshot", "TIMESTAMP"); b.setProperty("Bundle-Version", "1.0-SNAPSHOT"); Jar jar = b.build(); assertTrue(b.check("The JAR is empty")); Manifest m = jar.getManifest(); assertEquals("1.0.0.TIMESTAMP", m.getMainAttributes().getValue("Bundle-Version")); } finally { b.close(); } } /** * Check if do not copy works on files */ public static void testDoNotCopy() throws Exception { Builder b = new Builder(); try { b.setProperty("-resourceonly", "true"); b.setProperty("-donotcopy", ".*\\.jar|\\..*"); b.setProperty("Include-Resource", "jar"); b.build(); assertTrue(b.check()); Set<String> names = b.getJar().getResources().keySet(); assertEquals(12, names.size()); assertTrue(names.contains("AnnotationWithJSR14.jclass")); assertTrue(names.contains("mandatorynoversion.bnd")); assertTrue(names.contains("mina.bar")); assertTrue(names.contains("minax.bnd")); assertTrue(names.contains("rox.bnd")); assertTrue(names.contains("WithAnnotations.jclass")); } finally { b.close(); } } /** * Check if do not copy works on files */ public static void testDoNotCopyDS() throws Exception { Builder b = new Builder(); try { b.setProperty("-resourceonly", "true"); b.setProperty("Include-Resource", "jar/"); b.build(); assertTrue(b.check()); Set<String> names = b.getJar().getResources().keySet(); assertFalse(names.contains(".DS_Store")); } finally { b.close(); } } /** * No error is generated when a file is not found. */ public static void testFileNotFound() throws Exception { Builder b = new Builder(); try { b.setPedantic(true); b.setProperty("-classpath", "xyz.jar"); b.setProperty("Include-Resource", "lib=lib, jar/osgi.jar"); b.setProperty("-resourceonly", "true"); b.build(); assertTrue(b.check("Input file does not exist: lib", "Cannot find entry on -classpath: xyz.jar")); } finally { b.close(); } } /** * bnd seems to pick the wrong version if a packageinfo is available * multiple times. * * @throws Exception */ public static void testMultiplePackageInfo() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.addClasspath(IO.getFile("jar/osgi.core.jar")); b.setProperty(Constants.PRIVATEPACKAGE, "org.osgi.service.packageadmin;-split-package:=first"); b.build(); assertTrue(b.check()); String version = b.getImports().getByFQN("org.osgi.framework").get(Constants.VERSION_ATTRIBUTE); assertEquals("[1.3,2)", version); } finally { b.close(); } } /** * Test the from: directive on expanding packages. */ public static void testFromOSGiDirective() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.addClasspath(IO.getFile("jar/org.eclipse.osgi-3.5.0.jar")); b.setProperty("Export-Package", "org.osgi.framework;from:=osgi"); b.build(); assertTrue(b.check()); assertEquals("1.3", b.getExports().getByFQN("org.osgi.framework").get("version")); assertEquals("osgi", b.getExports().getByFQN("org.osgi.framework").get(Constants.FROM_DIRECTIVE)); } finally { b.close(); } } public static void testFromEclipseDirective() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.addClasspath(IO.getFile("jar/org.eclipse.osgi-3.5.0.jar")); b.setProperty("Export-Package", "org.osgi.framework;from:=org.eclipse.osgi-3.5.0"); b.build(); assertTrue(b.check()); assertEquals("1.3", b.getExports().getByFQN("org.osgi.framework").get("version")); } finally { b.close(); } } /** * Test the provide package */ public static void testProvidedVersion() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.addClasspath(new File("bin")); b.setProperty(Constants.EXPORT_PACKAGE, "org.osgi.service.event;provide:=true"); b.setProperty("Private-Package", "test.refer"); Jar jar = b.build(); assertTrue(b.check()); String ip = jar.getManifest().getMainAttributes().getValue(Constants.IMPORT_PACKAGE); Parameters map = Processor.parseHeader(ip, null); assertEquals("[1.0,1.1)", map.get("org.osgi.service.event").get("version")); } finally { b.close(); } } public static void testUnProvidedVersion() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.addClasspath(new File("bin")); b.setProperty(Constants.EXPORT_PACKAGE, "org.osgi.service.event;provide:=false"); b.setProperty("Private-Package", "test.refer"); Jar jar = b.build(); assertTrue(b.check()); String ip = jar.getManifest().getMainAttributes().getValue(Constants.IMPORT_PACKAGE); Parameters map = Processor.parseHeader(ip, null); assertEquals("[1.0,2)", map.get("org.osgi.service.event").get("version")); } finally { b.close(); } } /** * Complaint that exported versions were not picked up from external bundle. */ public static void testExportedVersionsNotPickedUp() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/jsr311-api-1.1.1.jar")); b.setProperty("Export-Package", "javax.ws.rs.core"); Jar jar = b.build(); assertTrue(b.check()); String ip = jar.getManifest().getMainAttributes().getValue(Constants.EXPORT_PACKAGE); Parameters map = Processor.parseHeader(ip, null); assertEquals("1.1.1", map.get("javax.ws.rs.core").get("version")); } finally { b.close(); } } /** * Test where the version comes from: Manifest or packageinfo * * @throws Exception */ public static void testExportVersionSource() throws Exception { Manifest manifest = new Manifest(); manifest.getMainAttributes().putValue("Export-Package", "org.osgi.service.event;version=100"); // Remove packageinfo Jar manifestOnly = new Jar(IO.getFile("jar/osgi.jar")); try { manifestOnly.remove("org/osgi/service/event/packageinfo"); manifestOnly.setManifest(manifest); // Remove manifest Jar packageInfoOnly = new Jar(IO.getFile("jar/osgi.jar")); packageInfoOnly.setManifest(new Manifest()); Jar both = new Jar(IO.getFile("jar/osgi.jar")); both.setManifest(manifest); // Only version in manifest Builder bms = new Builder(); try { bms.addClasspath(manifestOnly); bms.setProperty("Export-Package", "org.osgi.service.event"); bms.build(); assertTrue(bms.check()); String s = bms.getExports().getByFQN("org.osgi.service.event").get("version"); assertEquals("100", s); // Only version in packageinfo Builder bpinfos = new Builder(); bpinfos.addClasspath(packageInfoOnly); bpinfos.setProperty("Export-Package", "org.osgi.service.event"); bpinfos.build(); assertTrue(bpinfos.check()); s = bpinfos.getExports().getByFQN("org.osgi.service.event").get("version"); assertEquals("1.0.1", s); } finally { bms.close(); } } finally { manifestOnly.close(); } } /** * Test where the version comes from: Manifest or packageinfo * * @throws Exception */ public static void testImportVersionSource() throws Exception { Jar fromManifest = new Jar("manifestsource"); Jar fromPackageInfo = new Jar("packageinfosource"); Jar fromBoth = new Jar("both"); try { Manifest mms = new Manifest(); mms.getMainAttributes().putValue("Export-Package", "org.osgi.service.event; version=100"); fromManifest.setManifest(mms); fromPackageInfo.putResource("org/osgi/service/event/packageinfo", new EmbeddedResource("version 99".getBytes(), 0)); Manifest mboth = new Manifest(); mboth.getMainAttributes().putValue("Export-Package", "org.osgi.service.event; version=101"); fromBoth.putResource("org/osgi/service/event/packageinfo", new EmbeddedResource("version 199".getBytes(), 0)); fromBoth.setManifest(mboth); // Only version in manifest Builder bms = new Builder(); try { bms.addClasspath(fromManifest); bms.setProperty("Import-Package", "org.osgi.service.event"); bms.build(); assertTrue(bms.check("The JAR is empty")); String s = bms.getImports().getByFQN("org.osgi.service.event").get("version"); assertEquals("[100.0,101)", s); // Only version in packageinfo Builder bpinfos = new Builder(); try { bpinfos.addClasspath(fromPackageInfo); bpinfos.setProperty("Import-Package", "org.osgi.service.event"); bpinfos.build(); assertTrue(bms.check()); s = bpinfos.getImports().getByFQN("org.osgi.service.event").get("version"); assertEquals("[99.0,100)", s); // Version in manifest + packageinfo Builder bboth = new Builder(); try { bboth.addClasspath(fromBoth); bboth.setProperty("Import-Package", "org.osgi.service.event"); bboth.build(); assertTrue(bms.check()); s = bboth.getImports().getByFQN("org.osgi.service.event").get("version"); assertEquals("[101.0,102)", s); } finally { bboth.close(); } } finally { bpinfos.close(); } } finally { bms.close(); } } finally { fromManifest.close(); fromPackageInfo.close(); fromBoth.close(); } } public static void testNoImportDirective() throws Exception { Builder b = new Builder(); try { b.setProperty("Export-Package", "org.osgi.util.measurement, org.osgi.service.http;-noimport:=true"); b.setProperty("Private-Package", "org.osgi.framework, test.refer"); b.addClasspath(IO.getFile("jar/osgi.jar")); b.addClasspath(new File("bin")); Jar jar = b.build(); assertTrue(b.check()); Manifest m = jar.getManifest(); String imports = m.getMainAttributes().getValue("Import-Package"); assertTrue(imports.contains("org.osgi.util.measurement")); // referred // to // but // no // private // references // (does // not // use // fw). assertFalse(imports.contains("org.osgi.service.http")); // referred // to // but no // private // references // (does not // use // fw). } finally { b.close(); } } public static void testNoImportDirective2() throws Exception { Builder b = new Builder(); try { b.setProperty("Export-Package", "org.osgi.util.measurement;-noimport:=true, org.osgi.service.http"); b.setProperty("Private-Package", "org.osgi.framework, test.refer"); b.addClasspath(IO.getFile("jar/osgi.jar")); b.addClasspath(new File("bin")); Jar jar = b.build(); assertTrue(b.check()); Manifest m = jar.getManifest(); String imports = m.getMainAttributes().getValue("Import-Package"); assertFalse(imports.contains("org.osgi.util.measurement")); // referred // to // but // no // private // references // (does // not // use // fw). assertTrue(imports.contains("org.osgi.service.http")); // referred // to // but no // private // references // (does not // use // fw). } finally { b.close(); } } public static void testAutoNoImport() throws Exception { Builder b = new Builder(); try { b.setProperty("Export-Package", "org.osgi.service.event, org.osgi.service.packageadmin, org.osgi.util.measurement, org.osgi.service.http;-noimport:=true"); b.setProperty("Private-Package", "org.osgi.framework, test.refer"); b.addClasspath(IO.getFile("jar/osgi.jar")); b.addClasspath(new File("bin")); Jar jar = b.build(); assertTrue(b.check("has 1, private references")); Manifest m = jar.getManifest(); String imports = m.getMainAttributes().getValue("Import-Package"); assertFalse(imports.contains("org.osgi.service.packageadmin")); // no // internal // references assertFalse(imports.contains("org.osgi.util.event")); // refers to // private // framework assertTrue(imports.contains("org.osgi.util.measurement")); // referred // to // but // no // private // references // (does // not // use // fw). assertFalse(imports.contains("org.osgi.service.http")); // referred // to // but no // private // references // (does not // use // fw). } finally { b.close(); } } public static void testSimpleWab() throws Exception { Builder b = new Builder(); try { b.setProperty("-wab", ""); b.setProperty("Private-Package", "org.osgi.service.event"); b.addClasspath(IO.getFile("jar/osgi.jar")); Jar jar = b.build(); assertTrue(b.check()); Manifest m = jar.getManifest(); m.write(System.err); assertNotNull(b.getImports().getByFQN("org.osgi.framework")); } finally { b.close(); } } public static void testWab() throws Exception { Builder b = new Builder(); try { b.setProperty("-wablib", "jar/asm.jar, jar/easymock.jar"); b.setProperty("-wab", "jar/osgi.jar"); b.setProperty("-includeresource", "OSGI-INF/xml/x.xml;literal=\"text\""); b.setProperty("Private-Package", "org.osgi.framework"); b.addClasspath(IO.getFile("jar/osgi.jar")); Jar jar = b.build(); assertTrue(b.check()); Manifest m = jar.getManifest(); assertNotNull(m); assertEquals("WEB-INF/classes,WEB-INF/lib/asm.jar,WEB-INF/lib/easymock.jar", m.getMainAttributes().getValue("Bundle-ClassPath")); assertNotNull(jar.getResource("WEB-INF/lib/asm.jar")); assertNotNull(jar.getResource("WEB-INF/classes/org/osgi/framework/BundleContext.class")); assertNotNull(jar.getResource("osgi.jar")); assertNotNull(jar.getResource("OSGI-INF/xml/x.xml")); } finally { b.close(); } } public static void testRemoveHeaders() throws Exception { Builder b = new Builder(); try { b.setProperty("Private-Package", "org.osgi.framework"); b.setProperty("T1", "1"); b.setProperty("T2", "1"); b.setProperty("T1_2", "1"); b.setProperty("-removeheaders", "!T1_2,T1*"); b.addClasspath(IO.getFile("jar/osgi.jar")); Jar jar = b.build(); assertTrue(b.check()); Manifest m = jar.getManifest(); assertNotNull(m); assertEquals("1", m.getMainAttributes().getValue("T2")); assertEquals("1", m.getMainAttributes().getValue("T1_2")); assertEquals(null, m.getMainAttributes().getValue("T1")); } finally { b.close(); } } public static void testNoManifest() throws Exception { Builder b = new Builder(); try { b.setProperty("-nomanifest", "true"); b.setProperty(Constants.BUNDLE_CLASSPATH, "WEB-INF/classes"); b.setProperty("Include-Resource", "WEB-INF/classes=@jar/asm.jar"); Jar jar = b.build(); assertTrue(b.check()); File f = new File("tmp.jar"); f.deleteOnExit(); jar.write(f); JarInputStream jin = new JarInputStream(new FileInputStream(f)); Manifest m = jin.getManifest(); assertNull(m); } finally { b.close(); } } public static void testClassesonNoBCP() throws Exception { Builder b = new Builder(); try { b.setProperty("-resourceonly", "true"); b.setProperty("Include-Resource", "WEB-INF/classes=@jar/asm.jar"); b.setProperty("-nomanifest", "true"); b.build(); assertTrue(b.check("Classes found in the wrong directory")); } finally { b.close(); } } public static void testClassesonBCP() throws Exception { Builder b = new Builder(); try { b.setProperty("-resourceonly", "true"); b.setProperty("Include-Resource", "WEB-INF/classes=@jar/asm.jar"); b.setProperty("Bundle-ClassPath", "WEB-INF/classes"); b.build(); assertTrue(b.check()); } finally { b.close(); } } /** * #196 StringIndexOutOfBoundsException in Builder.getClasspathEntrySuffix * If a class path entry was changed the isInScope threw an exception * because it assumed all cpes were directories. * * @throws Exception */ public static void testInScopeClasspathEntry() throws Exception { Builder b = new Builder(); try { b.setProperty("Export-Package", "aQute.bnd.*"); b.addClasspath(new File("bin")); b.addClasspath(IO.getFile("jar/osgi.jar")); List<File> project = Arrays.asList(b.getFile("bin/aQute/bnd/build/Project.class")); assertTrue(b.isInScope(project)); List<File> cpe = Arrays.asList(b.getFile("jar/osgi.jar")); assertTrue(b.isInScope(cpe)); } finally { b.close(); } } public static void testInScopeExport() throws Exception { Builder b = new Builder(); try { b.setProperty("Export-Package", "aQute.bnd.*"); b.addClasspath(new File("bin")); List<File> project = Arrays.asList(b.getFile("bin/aQute/bnd/build/Project.class")); assertTrue(b.isInScope(project)); List<File> nonexistent = Arrays.asList(b.getFile("bin/aQute/bnd/build/Abc.xyz")); assertTrue(b.isInScope(nonexistent)); List<File> outside = Arrays.asList(b.getFile("bin/test/AnalyzerTest.class")); assertFalse(b.isInScope(outside)); } finally { b.close(); } } public static void testInScopePrivate() throws Exception { Builder b = new Builder(); b.setProperty("Private-Package", "!aQute.bnd.build,aQute.bnd.*"); b.addClasspath(new File("bin")); List<File> project = Arrays.asList(b.getFile("bin/aQute/bnd/build/Project.class")); assertFalse(b.isInScope(project)); List<File> nonexistent = Arrays.asList(b.getFile("bin/aQute/bnd/acb/Def.xyz")); assertTrue(b.isInScope(nonexistent)); List<File> outside = Arrays.asList(b.getFile("bin/test/AnalyzerTest.class")); assertFalse(b.isInScope(outside)); } public static void testInScopeResources() throws Exception { Builder b = new Builder(); try { b.setProperty("Include-Resource", "@a.jar/!xya.txt,{@b.jar/!xya.txt}, -@c.jar/!xya.txt, dir, x=dirb, {-x=dirc}"); assertFalse(b.isInScope(Arrays.asList(b.getFile("x.jar")))); assertTrue(b.isInScope(Arrays.asList(b.getFile("a.jar")))); assertTrue(b.isInScope(Arrays.asList(b.getFile("b.jar")))); assertTrue(b.isInScope(Arrays.asList(b.getFile("dir/a.jar")))); assertTrue(b.isInScope(Arrays.asList(b.getFile("dir/x.jar")))); assertTrue(b.isInScope(Arrays.asList(b.getFile("dir/x.jar")))); assertTrue(b.isInScope(Arrays.asList(b.getFile("dirb/x.jar")))); assertTrue(b.isInScope(Arrays.asList(b.getFile("dirb/x.jar")))); assertTrue(b.isInScope(Arrays.asList(b.getFile("dirc/x.jar")))); } finally { b.close(); } } public static void testExtra() throws Exception { Builder b = new Builder(); try { b.setProperty("Include-Resource", "jar/osgi.jar;extra=itworks, www/xyz.jar=jar/osgi.jar;extra='italsoworks'"); b.setProperty("-resourceonly", "true"); Jar jar = b.build(); assertTrue(b.check()); Resource r = jar.getResource("osgi.jar"); assertNotNull(r); assertEquals("itworks", r.getExtra()); Resource r2 = jar.getResource("www/xyz.jar"); assertNotNull(r2); assertEquals("italsoworks", r2.getExtra()); } finally { b.close(); } } /** * Got a split package warning during verify when private overlaps with * export */ public static void testSplitWhenPrivateOverlapsExport() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.setProperty("Private-Package", "org.osgi.service.*"); b.setProperty("Export-Package", "org.osgi.service.event"); b.build(); assertTrue(b.check()); } finally { b.close(); } } /** * This test checks if * * @throws Exception */ public static void testMacroBasedExpansion() throws Exception { Processor proc = new Processor(); Builder builder = new Builder(proc); try { builder.setProperty("Export-Package", "${spec.packages}"); proc.setProperty("spec.packages", "${core.packages}, ${cmpn.packages}, ${mobile.packages}"); proc.setProperty("core.specs", "org.osgi.service.packageadmin, org.osgi.service.permissionadmin"); proc.setProperty("core.packages", "${replace;${core.specs};.+;$0.*}"); proc.setProperty("cmpn.specs", "org.osgi.service.event, org.osgi.service.cu"); proc.setProperty("cmpn.packages", "${replace;${cmpn.specs};.+;$0.*}"); proc.setProperty("mobile.specs", "org.osgi.service.wireadmin, org.osgi.service.log, org.osgi.service.cu"); proc.setProperty("mobile.packages", "${replace;${mobile.specs};.+;$0.*}"); builder.addClasspath(IO.getFile("jar/osgi.jar")); Jar jar = builder.build(); // The total set is not uniqued so we're having an unused pattern // this could be solved with ${uniq;${spec.packages}} but this is // just // another test assertTrue(builder.check("Unused Export-Package instructions: \\[org.osgi.service.cu.\\*~\\]")); Domain domain = Domain.domain(jar.getManifest()); Parameters h = domain.getExportPackage(); assertTrue(h.containsKey("org.osgi.service.cu")); assertTrue(h.containsKey("org.osgi.service.cu.admin")); } finally { builder.close(); proc.close(); } } /** * Make resolution dependent on the fact that a package is on the classpath * or not */ public static void testConditionalResolution() throws Exception { Builder b = new Builder(); try { b.setProperty("res", "${if;${exporters;${@package}};mandatory;optional}"); b.setProperty("Import-Package", "*;resolution:=\\${res}"); b.setProperty("Export-Package", "org.osgi.service.io, org.osgi.service.log"); b.addClasspath(IO.getFile("jar/osgi.jar")); b.build(); assertTrue(b.check()); Map<String,String> ioimports = b.getImports().getByFQN("javax.microedition.io"); Map<String,String> fwimports = b.getImports().getByFQN("org.osgi.framework"); assertNotNull(ioimports); assertNotNull(fwimports); assertTrue(ioimports.containsKey("resolution:")); assertTrue(fwimports.containsKey("resolution:")); assertEquals("optional", ioimports.get("resolution:")); assertEquals("mandatory", fwimports.get("resolution:")); } finally { b.close(); } } /** * Test private imports. We first build a jar with a import:=private packge. * Then place it * * @throws Exception */ public static void testClassnames() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.addClasspath(IO.getFile("jar/ds.jar")); b.addClasspath(IO.getFile("jar/ifc112.jar")); b.setProperty("Export-Package", "*"); b.setProperty("C1", "${classes;implementing;org.osgi.service.component.*}"); b.setProperty("C2", "${classes;extending;org.xml.sax.helpers.*}"); b.setProperty("C3", "${classes;importing;org.xml.sax}"); b.setProperty("C4", "${classes;named;*Parser*}"); b.setProperty("C5", "${classes;named;*Parser*;version;45.*}"); Jar jar = b.build(); assertTrue(b.check()); Manifest m = jar.getManifest(); m.write(System.err); Attributes main = m.getMainAttributes(); assertList( asl("org.eclipse.equinox.ds.service.ComponentContextImpl,org.eclipse.equinox.ds.service.ComponentFactoryImpl,org.eclipse.equinox.ds.service.ComponentInstanceImpl"), asl(main.getValue("C1"))); assertList(asl( "org.eclipse.equinox.ds.parser.ElementHandler, " + "org.eclipse.equinox.ds.parser.IgnoredElement," + "org.eclipse.equinox.ds.parser.ImplementationElement," + "org.eclipse.equinox.ds.parser.ParserHandler, " + "org.eclipse.equinox.ds.parser.PropertiesElement," + "org.eclipse.equinox.ds.parser.PropertyElement, " + "org.eclipse.equinox.ds.parser.ProvideElement, " + "org.eclipse.equinox.ds.parser.ReferenceElement, " + "org.eclipse.equinox.ds.parser.ServiceElement," + "org.eclipse.equinox.ds.parser.ComponentElement"), asl(main.getValue("C2"))); assertList( asl("org.eclipse.equinox.ds.parser.ComponentElement,org.eclipse.equinox.ds.parser.ElementHandler,org.eclipse.equinox.ds.parser.IgnoredElement,org.eclipse.equinox.ds.parser.ImplementationElement,org.eclipse.equinox.ds.parser.Parser,org.eclipse.equinox.ds.parser.ParserHandler,org.eclipse.equinox.ds.parser.PropertiesElement,org.eclipse.equinox.ds.parser.PropertyElement,org.eclipse.equinox.ds.parser.ProvideElement,org.eclipse.equinox.ds.parser.ReferenceElement,org.eclipse.equinox.ds.parser.ServiceElement"), asl(main.getValue("C3"))); assertList( asl("org.eclipse.equinox.ds.parser.XMLParserNotAvailableException,org.eclipse.equinox.ds.parser.Parser,org.eclipse.equinox.ds.parser.ParserHandler,netscape.application.HTMLParser,org.eclipse.equinox.ds.parser.ParserConstants,org.osgi.util.xml.XMLParserActivator"), asl(main.getValue("C4"))); assertEquals("netscape.application.HTMLParser", main.getValue("C5")); } finally { b.close(); } } static void assertList(Collection<String> a, Collection<String> b) { List<String> onlyInA = new ArrayList<String>(); onlyInA.addAll(a); onlyInA.removeAll(b); List<String> onlyInB = new ArrayList<String>(); onlyInB.addAll(b); onlyInB.removeAll(a); if (onlyInA.isEmpty() && onlyInB.isEmpty()) return; fail("Lists are not equal, only in A: " + onlyInA + ",\n and only in B: " + onlyInB); } static Collection<String> asl(String s) { return new TreeSet<String>(Processor.split(s)); } public static void testImportMicroNotTruncated() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.setProperty("Import-Package", "org.osgi.service.event;version=${@}"); b.build(); assertTrue(b.check("The JAR is empty")); String s = b.getImports().getByFQN("org.osgi.service.event").get("version"); assertEquals("1.0.1", s); } finally { b.close(); } } public static void testImportMicroTruncated() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/osgi.jar")); b.setProperty("Import-Package", "org.osgi.service.event"); b.build(); assertTrue(b.check("The JAR is empty")); String s = b.getImports().getByFQN("org.osgi.service.event").get("version"); assertEquals("[1.0,2)", s); } finally { b.close(); } } public static void testMultipleExport2() throws Exception { File cp[] = { IO.getFile("jar/asm.jar") }; Builder bmaker = new Builder(); try { Properties p = new Properties(); p.setProperty("Export-Package", "org.objectweb.asm;version=1.1, org.objectweb.asm;version=1.2, org.objectweb.asm;version=2.3"); bmaker.setProperties(p); bmaker.setClasspath(cp); Jar jar = bmaker.build(); assertTrue(bmaker.check()); jar.getManifest().write(System.err); Manifest m = jar.getManifest(); m.write(System.err); String ip = m.getMainAttributes().getValue("Export-Package"); assertTrue(ip.indexOf("org.objectweb.asm;version=\"1.1\"") >= 0); assertTrue(ip.indexOf("org.objectweb.asm;version=\"1.2\"") >= 0); assertTrue(ip.indexOf("org.objectweb.asm;version=\"2.3\"") >= 0); } finally { bmaker.close(); } } public static void testBsnAssignmentNoFile() throws Exception { Properties p = new Properties(); p.setProperty("Private-Package", "org.objectweb.asm"); Attributes m = setup(p, null).getMainAttributes(); // We use properties so the default BSN is then the project name // because that is the base directory assertEquals(m.getValue("Bundle-SymbolicName"), "biz.aQute.bndlib.tests"); // The file name for the properties is not bnd.bnd, so the // name of the properties file is the default bsn m = setup(null, IO.getFile("src/test/com.acme/defaultbsn.bnd")).getMainAttributes(); assertEquals("com.acme.defaultbsn", m.getValue("Bundle-SymbolicName")); // If the file is called bnd.bnd, then we take the parent directory m = setup(null, IO.getFile("src/test/com.acme/bnd.bnd")).getMainAttributes(); assertEquals("com.acme", m.getValue("Bundle-SymbolicName")); // If the file is called bnd.bnd, then we take the parent directory m = setup(null, IO.getFile("src/test/com.acme/setsbsn.bnd")).getMainAttributes(); assertEquals("is.a.set.bsn", m.getValue("Bundle-SymbolicName")); // This sets the bsn, se we should see it back p.setProperty("Bundle-SymbolicName", "this.is.my.test"); m = setup(p, null).getMainAttributes(); assertEquals(m.getValue("Bundle-SymbolicName"), "this.is.my.test"); } public static Manifest setup(Properties p, File f) throws Exception { File cp[] = { IO.getFile("jar/asm.jar") }; Builder bmaker = new Builder(); if (f != null) bmaker.setProperties(f); else bmaker.setProperties(p); bmaker.setClasspath(cp); Jar jar = bmaker.build(); assertTrue(bmaker.check()); Manifest m = jar.getManifest(); return m; } public static void testDuplicateExport() throws Exception { File cp[] = { IO.getFile("jar/asm.jar") }; Builder bmaker = new Builder(); try { Properties p = new Properties(); p.setProperty("Import-Package", "*"); p.setProperty("Export-Package", "org.*;version=1.2,org.objectweb.asm;version=1.3"); bmaker.setProperties(p); bmaker.setClasspath(cp); Jar jar = bmaker.build(); assertTrue(bmaker.check()); Manifest m = jar.getManifest(); m.write(System.err); String ip = m.getMainAttributes().getValue("Export-Package"); assertTrue(ip.indexOf("org.objectweb.asm;version=\"1.2\"") >= 0); } finally { bmaker.close(); } } public static void testNoExport() throws Exception { File cp[] = { IO.getFile("jar/asm.jar") }; Builder bmaker = new Builder(); try { Properties p = new Properties(); p.setProperty("Import-Package", "*"); p.setProperty("Export-Package", "org.*'"); bmaker.setProperties(p); bmaker.setClasspath(cp); Jar jar = bmaker.build(); assertTrue(bmaker.check()); jar.getManifest().write(System.err); Manifest m = jar.getManifest(); String ip = m.getMainAttributes().getValue("Export-Package"); assertTrue(ip.indexOf("org.objectweb.asm") >= 0); } finally { bmaker.close(); } } public static void testHardcodedImport() throws Exception { File cp[] = { IO.getFile("jar/asm.jar") }; Builder bmaker = new Builder(); try { Properties p = new Properties(); p.setProperty("Import-Package", "whatever,*"); p.setProperty("Export-Package", "org.*"); bmaker.setProperties(p); bmaker.setClasspath(cp); Jar jar = bmaker.build(); assertTrue(bmaker.check()); Manifest m = jar.getManifest(); String ip = m.getMainAttributes().getValue("Import-Package"); assertTrue(ip.indexOf("whatever") >= 0); } finally { bmaker.close(); } } public static void testCopyDirectory() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.setProperty("-resourceonly", "true"); p.setProperty("Include-Resource", "bnd=bnd"); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); Map<String,Resource> map = jar.getDirectories().get("bnd"); assertNotNull(map); assertEquals(2, map.size()); } finally { bmaker.close(); } } /** * There is an error that gives a split package when you export a package * that is also private I think. * * @throws Exception */ public static void testSplitOnExportAndPrivate() throws Exception { File cp[] = { IO.getFile("jar/asm.jar") }; Builder bmaker = new Builder(); try { Properties p = new Properties(); p.setProperty("Export-Package", "org.objectweb.asm.signature"); p.setProperty("Private-Package", "org.objectweb.asm"); bmaker.setProperties(p); bmaker.setClasspath(cp); bmaker.build(); assertTrue(bmaker.check()); } finally { bmaker.close(); } } public static void testConduit() throws Exception { Properties p = new Properties(); p.setProperty("-conduit", "jar/asm.jar"); Builder b = new Builder(); try { b.setProperties(p); Jar jars[] = b.builds(); assertTrue(b.check()); assertNotNull(jars); assertEquals(1, jars.length); assertEquals("ASM", jars[0].getManifest().getMainAttributes().getValue("Implementation-Title")); } finally { b.close(); } } /** * Export a package that was loaded with resources * * @throws Exception */ public static void testExportSyntheticPackage() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.setProperty("-resourceonly", "true"); p.setProperty("Include-Resource", "resources=jar"); p.setProperty("-exportcontents", "resources"); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); Manifest manifest = jar.getManifest(); String header = manifest.getMainAttributes().getValue("Export-Package"); System.err.println(header); assertTrue(header.indexOf("resources") >= 0); } finally { bmaker.close(); } } /** * Exporting packages in META-INF * * @throws Exception */ public static void testMETAINF() throws Exception { File cp[] = { new File("src"), IO.getFile("jar/asm.jar") }; Builder bmaker = new Builder(); try { Properties p = new Properties(); p.setProperty("Include-Resource", "META-INF/xyz/asm.jar=jar/asm.jar"); p.setProperty("Export-Package", "META-INF/xyz, org.*"); bmaker.setProperties(p); bmaker.setClasspath(cp); Jar jar = bmaker.build(); assertTrue(bmaker.check("Invalid package name: 'META-INF")); jar.getManifest().write(System.err); Manifest manifest = jar.getManifest(); String header = manifest.getMainAttributes().getValue("Export-Package"); assertTrue(header.indexOf("META-INF.xyz") >= 0); } finally { bmaker.close(); } } /** * Bnd cleans up versions if they do not follow the OSGi rule. Check a * number of those versions. * * @throws Exception */ public static void testVersionCleanup() throws Exception { assertVersion("1.201209072340200", "1.0.0.201209072340200"); assertVersion("000001.0003.00000-SNAPSHOT", "1.3.0.SNAPSHOT"); assertVersion("000000.0000.00000-SNAPSHOT", "0.0.0.SNAPSHOT"); assertVersion("0-SNAPSHOT", "0.0.0.SNAPSHOT"); assertVersion("1.3.0.0-0-01-0-SNAPSHOT", "1.3.0.0-0-01-0-SNAPSHOT"); assertVersion("1.3.0.0-0-01-0", "1.3.0.0-0-01-0"); assertVersion("0.9.0.1.2.3.4.5-incubator-SNAPSHOT", "0.9.0.incubator-SNAPSHOT"); assertVersion("0.4aug123", "0.0.0.4aug123"); assertVersion("0.9.4aug123", "0.9.0.4aug123"); assertVersion("0.9.0.4aug123", "0.9.0.4aug123"); assertVersion("1.2.3", "1.2.3"); assertVersion("1.2.3-123", "1.2.3.123"); assertVersion("1.2.3.123", "1.2.3.123"); assertVersion("1.2.3.123x", "1.2.3.123x"); assertVersion("1.123x", "1.0.0.123x"); assertVersion("0.9.0.4.3.2.1.0.4aug123", "0.9.0.4aug123"); assertVersion("0.9.0.4aug123", "0.9.0.4aug123"); assertVersion("0.9.0.4.3.4.5.6.6", "0.9.0.6"); assertVersion("0.9.0-incubator-SNAPSHOT", "0.9.0.incubator-SNAPSHOT"); assertVersion("1.2.3.x", "1.2.3.x"); assertVersion("1.2.3", "1.2.3"); assertVersion("1.2", "1.2"); assertVersion("1", "1"); assertVersion("1.2.x", "1.2.0.x"); assertVersion("1.x", "1.0.0.x"); assertVersion("1.2.3-x", "1.2.3.x"); assertVersion("1.2:x", "1.2.0.x"); assertVersion("1.2-snapshot", "1.2.0.snapshot"); assertVersion("1#x", "1.0.0.x"); assertVersion("1.&^%$#date2007/03/04", "1.0.0.date20070304"); } static void assertVersion(String input, String expected) { assertEquals(expected, Builder.cleanupVersion(input)); } /** * -exportcontents provides a header that is only relevant in the analyze * phase, it augments the Export-Package header. */ public static void testExportContents() throws Exception { Builder builder = new Builder(); try { builder.setProperty(Analyzer.INCLUDE_RESOURCE, "test/activator/inherits=src/test/activator/inherits"); builder.setProperty("-exportcontents", "*;x=true;version=1"); builder.build(); assertTrue(builder.check()); Manifest manifest = builder.calcManifest(); Attributes main = manifest.getMainAttributes(); Parameters map = OSGiHeader.parseHeader(main.getValue("Export-Package")); Map<String,String> export = map.get("test.activator.inherits"); assertNotNull(export); assertEquals("1", export.get("version")); assertEquals("true", export.get("x")); } finally { builder.close(); } } /** * Check Conditional package. First import a subpackage then let the * subpackage import a super package. This went wrong in the OSGi build. We * see such a pattern in the Spring jar. The package * org.springframework.beans.factory.access refers to * org.springframework.beans.factory and org.springframework.beans. The */ public static void testConditionalBaseSuper() throws Exception { Builder b = new Builder(); try { b.setProperty(Constants.CONDITIONALPACKAGE, "test.top.*"); b.setProperty(Constants.PRIVATEPACKAGE, "test.top.middle.bottom"); b.addClasspath(new File("bin")); Jar dot = b.build(); assertTrue(b.check()); assertNotNull(dot.getResource("test/top/middle/bottom/Bottom.class")); assertNotNull(dot.getResource("test/top/middle/Middle.class")); assertNotNull(dot.getResource("test/top/Top.class")); assertFalse(b.getImports().getByFQN("test.top") != null); assertFalse(b.getImports().getByFQN("test.top.middle") != null); assertFalse(b.getImports().getByFQN("test.top.middle.bottom") != null); } finally { b.close(); } } /** * It looks like Conditional-Package can add the same package multiple * times. So lets test this. */ public static void testConditional2() throws Exception { Properties base = new Properties(); base.put(Analyzer.EXPORT_PACKAGE, "org.osgi.service.log"); base.put(Analyzer.CONDITIONAL_PACKAGE, "org.osgi.*"); Builder analyzer = new Builder(); try { analyzer.setProperties(base); analyzer.setClasspath(new File[] { IO.getFile("jar/osgi.jar") }); analyzer.build(); assertTrue(analyzer.check("private references")); Jar jar = analyzer.getJar(); assertTrue(analyzer.check()); assertNotNull(analyzer.getExports().getByFQN("org.osgi.service.log")); assertNotNull(jar.getDirectories().get("org/osgi/framework")); } finally { analyzer.close(); } } /** * Test the strategy: error */ public static void testStrategyError() throws Exception { Properties base = new Properties(); base.put(Analyzer.EXPORT_PACKAGE, "*;-split-package:=error"); Builder analyzer = new Builder(); try { analyzer.setClasspath(new File[] { IO.getFile("jar/asm.jar"), IO.getFile("jar/asm.jar") }); analyzer.setProperties(base); analyzer.build(); assertTrue(analyzer.check("The JAR is empty", "Split package")); } finally { analyzer.close(); } } /** * Test the strategy: default */ public static void testStrategyDefault() throws Exception { Properties base = new Properties(); base.put(Analyzer.EXPORT_PACKAGE, "*"); Builder analyzer = new Builder(); try { analyzer.setClasspath(new File[] { IO.getFile("jar/asm.jar"), IO.getFile("jar/asm.jar") }); analyzer.setProperties(base); analyzer.build(); assertEquals(2, analyzer.getWarnings().size()); assertTrue(analyzer.check("Split package")); } finally { analyzer.close(); } } /** * Test the strategy: merge-first */ public static void testStrategyMergeFirst() throws Exception { Properties base = new Properties(); base.put(Analyzer.EXPORT_PACKAGE, "*;-split-package:=merge-first"); Builder analyzer = new Builder(); try { analyzer.setClasspath(new File[] { IO.getFile("jar/asm.jar"), IO.getFile("jar/asm.jar") }); analyzer.setProperties(base); analyzer.build(); assertTrue(analyzer.check()); } finally { analyzer.close(); } } /** * Test the strategy: merge-last */ public static void testStrategyMergeLast() throws Exception { Properties base = new Properties(); base.put(Analyzer.EXPORT_PACKAGE, "*;-split-package:=merge-last"); Builder analyzer = new Builder(); try { analyzer.setClasspath(new File[] { IO.getFile("jar/asm.jar"), IO.getFile("jar/asm.jar") }); analyzer.setProperties(base); analyzer.build(); assertTrue(analyzer.check()); } finally { analyzer.close(); } } /** * Test Resource inclusion that do not exist * * @throws Exception */ public static void testResourceNotFound() throws Exception { Properties base = new Properties(); base.put(Analyzer.EXPORT_PACKAGE, "*;x-test:=true"); base.put(Analyzer.INCLUDE_RESOURCE, "does_not_exist"); Builder analyzer = new Builder(); try { analyzer.setClasspath(new File[] { IO.getFile("jar/asm.jar") }); analyzer.setProperties(base); analyzer.build(); assertTrue(analyzer.check("file does not exist: does_not_exist")); } finally { analyzer.close(); } } /** * Check if we can use findpath to build the Bundle-Classpath. */ public static void testFindPathInBundleClasspath() throws Exception { Properties base = new Properties(); base.put(Analyzer.INCLUDE_RESOURCE, "jar=jar"); base.put(Analyzer.BUNDLE_CLASSPATH, "${findpath;jar/.{1,4}\\.jar}"); Builder analyzer = new Builder(); try { analyzer.setProperties(base); analyzer.build(); assertTrue(analyzer.check()); Manifest manifest = analyzer.getJar().getManifest(); String bcp = manifest.getMainAttributes().getValue("Bundle-Classpath"); assertTrue(bcp.indexOf("ds.jar") >= 0); assertTrue(bcp.indexOf("asm.jar") >= 0); assertTrue(bcp.indexOf("bcel.jar") >= 0); assertTrue(bcp.indexOf("mina.jar") >= 0); assertTrue(bcp.indexOf("rox.jar") >= 0); assertTrue(bcp.indexOf("osgi.jar") >= 0); } finally { analyzer.close(); } } /** * Check if we export META-INF when we export the complete classpath. */ public static void testVersionCleanupAll() throws Exception { Properties base = new Properties(); base.put(Analyzer.EXPORT_PACKAGE, "*"); base.put(Analyzer.BUNDLE_VERSION, "0.9.0-incubator-SNAPSHOT"); Builder analyzer = new Builder(); try { analyzer.setClasspath(new File[] { IO.getFile("jar/asm.jar") }); analyzer.setProperties(base); analyzer.build(); assertTrue(analyzer.check()); Manifest manifest = analyzer.getJar().getManifest(); String version = manifest.getMainAttributes().getValue(Analyzer.BUNDLE_VERSION); assertEquals("0.9.0.incubator-SNAPSHOT", version); } finally { analyzer.close(); } } /** * We are only adding privately the core equinox ds package. We then add * conditionally all packages that should belong to this as well as any OSGi * interfaces. * * @throws Exception */ public static void testConditional() throws Exception { File cp[] = { IO.getFile("jar/osgi.jar"), IO.getFile("jar/ds.jar") }; Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("Import-Package", "*"); p.put("Private-Package", "org.eclipse.equinox.ds"); p.put("Conditional-Package", "org.eclipse.equinox.ds.*, org.osgi.service.*"); bmaker.setProperties(p); bmaker.setClasspath(cp); bmaker.build(); assertTrue(bmaker.check()); assertTrue(bmaker.getContained().getByFQN("org.eclipse.equinox.ds.instance") != null); assertTrue(bmaker.getContained().getByFQN("org.eclipse.equinox.ds.model") != null); assertTrue(bmaker.getContained().getByFQN("org.eclipse.equinox.ds.parser") != null); assertTrue(bmaker.getContained().getByFQN("org.osgi.service.cm") != null); assertTrue(bmaker.getContained().getByFQN("org.osgi.service.component") != null); assertFalse(bmaker.getContained().getByFQN("org.osgi.service.wireadmin") != null); } finally { bmaker.close(); } } /** * Check if we export META-INF when we export the complete classpath. */ public static void testMetaInfExport() throws Exception { Properties base = new Properties(); base.put(Analyzer.EXPORT_PACKAGE, "*"); Builder analyzer = new Builder(); try { analyzer.setClasspath(new File[] { IO.getFile("jar/asm.jar") }); analyzer.setProperties(base); analyzer.build(); assertTrue(analyzer.check()); assertFalse(analyzer.getExports().getByFQN("META-INF") != null); assertTrue(analyzer.getExports().getByFQN("org.objectweb.asm") != null); } finally { analyzer.close(); } } /** * Check if we imported the package with the correct version range when * there's an empty package in front of it in the classpath. First form. */ public static void testImportRangeCalculatedFromClasspath_1() throws Exception { Properties base = new Properties(); base.put(Analyzer.IMPORT_PACKAGE, "javax.servlet,javax.servlet.http"); Builder analyzer = new Builder(); try { analyzer.addClasspath(new File("bin")); analyzer.setPrivatePackage("test"); analyzer.setClasspath(new File[] { IO.getFile("jar/jsp-api.jar"), IO.getFile("jar/servlet-api.jar") }); analyzer.setProperties(base); analyzer.build(); assertTrue(analyzer.check()); Packages imports = analyzer.getImports(); Attrs attrs = imports.getByFQN("javax.servlet.http"); assertEquals("[3.0,4)", attrs.getVersion()); attrs = imports.getByFQN("javax.servlet"); assertEquals("[3.0,4)", attrs.getVersion()); } finally { analyzer.close(); } } /** * Check if we imported the package with the correct version range when * there's an empty package in front of it in the classpath. Second form. */ public static void testImportRangeCalculatedFromClasspath_2() throws Exception { Properties base = new Properties(); base.put(Analyzer.IMPORT_PACKAGE, "javax.servlet,javax.servlet.http"); String pwd = System.getProperty("user.dir"); base.put("pwd", new File(pwd).toURI().toString()); base.put("-classpath", "${pwd}/jar/jsp-api.jar,${pwd}/jar/servlet-api.jar"); Builder analyzer = new Builder(); try { analyzer.addClasspath(new File("bin")); analyzer.setPrivatePackage("test"); analyzer.setProperties(base); analyzer.build(); assertTrue(analyzer.check()); Packages imports = analyzer.getImports(); Attrs attrs = imports.getByFQN("javax.servlet.http"); assertEquals("[3.0,4)", attrs.getVersion()); attrs = imports.getByFQN("javax.servlet"); assertEquals("[3.0,4)", attrs.getVersion()); } finally { analyzer.close(); } } /** * Check if we imported the package with the correct version range when * there's an empty package in front of it in the classpath. First form * calling builds(). */ public static void testImportRangeCalculatedFromClasspath_3() throws Exception { Properties base = new Properties(); base.put(Analyzer.IMPORT_PACKAGE, "javax.servlet,javax.servlet.http"); Builder analyzer = new Builder(); try { analyzer.addClasspath(new File("bin")); analyzer.setPrivatePackage("test"); analyzer.setClasspath(new File[] { IO.getFile("jar/jsp-api.jar"), IO.getFile("jar/servlet-api.jar") }); analyzer.setProperties(base); analyzer.builds(); assertTrue(analyzer.check()); Packages imports = analyzer.getImports(); Attrs attrs = imports.getByFQN("javax.servlet.http"); assertEquals("[3.0,4)", attrs.getVersion()); attrs = imports.getByFQN("javax.servlet"); assertEquals("[3.0,4)", attrs.getVersion()); } finally { analyzer.close(); } } /** * Check if we imported the package with the correct version range when * there's an empty package in front of it in the classpath. Second form * calling builds(). */ public static void testImportRangeCalculatedFromClasspath_4() throws Exception { Properties base = new Properties(); base.put(Analyzer.IMPORT_PACKAGE, "javax.servlet,javax.servlet.http"); String pwd = System.getProperty("user.dir"); base.put("pwd", new File(pwd).toURI().toString()); base.put("-classpath", "${pwd}/jar/jsp-api.jar,${pwd}/jar/servlet-api.jar"); Builder analyzer = new Builder(); try { analyzer.addClasspath(new File("bin")); analyzer.setPrivatePackage("test"); analyzer.setProperties(base); analyzer.builds(); assertTrue(analyzer.check()); Packages imports = analyzer.getImports(); Attrs attrs = imports.getByFQN("javax.servlet.http"); assertEquals("[3.0,4)", attrs.getVersion()); attrs = imports.getByFQN("javax.servlet"); assertEquals("[3.0,4)", attrs.getVersion()); } finally { analyzer.close(); } } /** * Check that the activator is found. * * @throws Exception */ public static void testFindActivator() throws Exception { Builder bmaker = new Builder(); try { bmaker.setProperty("Bundle-Activator", "test.activator.Activator"); bmaker.setProperty("build", "xyz"); // for @Version annotation bmaker.setProperty("Private-Package", "test.*"); bmaker.setProperty("-dsannotations", "!*"); bmaker.setProperty("-metatypeannotations", "!*"); bmaker.setClasspath(new File[] { new File("bin") }); Jar jar = bmaker.build(); assertTrue(bmaker.check()); report("testFindActivator", bmaker, jar); assertEquals(0, bmaker.getErrors().size()); assertEquals(0, bmaker.getWarnings().size()); } finally { bmaker.close(); } } public static void testImportVersionRange() throws Exception { assertVersionEquals("[1.1,2.0)", "[1.1,2.0)"); assertVersionEquals("[${@},2.0)", "[1.3,2.0)"); assertVersionEquals("[${@},${@}]", "[1.3,1.3]"); } static void assertVersionEquals(String input, String output) throws Exception { File cp[] = { IO.getFile("jar/osgi.jar") }; Builder bmaker = new Builder(); try { bmaker.setClasspath(cp); Properties p = new Properties(); p.put(Analyzer.EXPORT_PACKAGE, "test.activator"); p.put(Analyzer.IMPORT_PACKAGE, "org.osgi.framework;version=\"" + input + "\""); bmaker.setProperties(p); bmaker.build(); assertTrue(bmaker.check("The JAR is empty")); Packages imports = bmaker.getImports(); Map<String,String> framework = imports.get(bmaker.getPackageRef("org.osgi.framework")); assertEquals(output, framework.get("version")); } finally { bmaker.close(); } } public static void testImportExportBadVersion() throws Exception { Builder b = new Builder(); try { b.addClasspath(IO.getFile("jar/ds.jar")); b.set(Analyzer.BUNDLE_VERSION, "0.9.5-@#SNAPSHOT"); b.set(Analyzer.EXPORT_PACKAGE, "*;version=0.9.5-@#SNAPSHOT"); b.set(Analyzer.IMPORT_PACKAGE, "*;version=0.9.5-@#SNAPSHOT"); Jar jar = b.build(); assertTrue(b.check()); Manifest m = jar.getManifest(); m.write(System.err); assertEquals(m.getMainAttributes().getValue("Bundle-Version"), "0.9.5.SNAPSHOT"); assertNotNull(b.getExports().getByFQN("org.eclipse.equinox.ds.parser")); assertEquals("0.9.5.SNAPSHOT", b.getExports().getByFQN("org.eclipse.equinox.ds.parser").getVersion()); assertNotNull(b.getImports().getByFQN("org.osgi.framework")); assertEquals("0.9.5.SNAPSHOT", b.getImports().getByFQN("org.osgi.framework").getVersion()); } finally { b.close(); } } /** * Check if can find an activator in the bundle while using a complex bundle * classpath. * * @throws Exception */ public static void testBundleClasspath3() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("Export-Package", "test.activator;-split-package:=merge-first"); p.put("Bundle-Activator", "test.activator.Activator"); p.put("Import-Package", "*"); p.put("Include-Resource", "ds.jar=jar/ds.jar"); p.put("Bundle-ClassPath", ".,ds.jar"); bmaker.setProperties(p); bmaker.setClasspath(new File[] { new File("bin"), new File("src") }); Jar jar = bmaker.build(); assertTrue(bmaker.check()); report("testBundleClasspath3", bmaker, jar); assertEquals(0, bmaker.getErrors().size()); assertEquals(0, bmaker.getWarnings().size()); } finally { bmaker.close(); } } /** * Check if can find an activator in a embedded jar while using a complex * bundle classpath. * * @throws Exception */ public static void testBundleClasspath2() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("Bundle-Activator", "org.eclipse.equinox.ds.Activator"); p.put("Private-Package", "test.activator;-split-package:=merge-first"); p.put("Import-Package", "*"); p.put("Include-Resource", "ds.jar=jar/ds.jar"); p.put("Bundle-ClassPath", ".,ds.jar"); bmaker.setProperties(p); bmaker.setClasspath(new File[] { new File("bin"), new File("src") }); Jar jar = bmaker.build(); assertTrue(bmaker.check()); report("testBundleClasspath2", bmaker, jar); assertEquals(bmaker.getErrors().size(), 0); assertEquals(bmaker.getWarnings().size(), 0); } finally { bmaker.close(); } } public static void testBundleClasspath() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("Export-Package", "test.activator;-split-package:=merge-first"); p.put("Bundle-Activator", "test.activator.Activator"); p.put("Import-Package", "*"); p.put("Bundle-ClassPath", "."); bmaker.setProperties(p); bmaker.setClasspath(new File[] { new File("bin"), new File("src") }); Jar jar = bmaker.build(); assertTrue(bmaker.check()); report("testBundleClasspath", bmaker, jar); jar.exists("testresources/activator/Activator.class"); assertEquals(bmaker.getErrors().size(), 0); assertEquals(bmaker.getWarnings().size(), 0); } finally { bmaker.close(); } } public static void testUnreferredImport() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("-classpath", "jar/mina.jar"); p.put("Export-Package", "*"); p.put("Import-Package", "org.apache.commons.collections.map,*"); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); report("testUnreferredImport", bmaker, jar); } finally { bmaker.close(); } } public static void testUnreferredNegatedImport() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("-classpath", "jar/mina.jar"); p.put("Export-Package", "*"); p.put("Import-Package", "!org.apache.commons.collections.map,*"); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); report("testUnreferredImport", bmaker, jar); } finally { bmaker.close(); } } public static void testIncludeResourceResourcesOnlyJar2() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("-classpath", "jar/ro.jar"); p.put("Export-Package", "*"); p.put("Import-Package", ""); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); report("testIncludeResourceResourcesOnlyJar2", bmaker, jar); assertTrue(bmaker.getExports().getByFQN("ro") != null); assertFalse(bmaker.getExports().getByFQN("META-INF") != null); assertEquals(3, jar.getResources().size()); } finally { bmaker.close(); } } public static void testClasspathFileNotExist() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); File cp[] = new File[] { IO.getFile("jar/idonotexist.jar") }; bmaker.setProperties(p); bmaker.setClasspath(cp); bmaker.build(); assertTrue(bmaker.check("The JAR is empty", "Missing file on classpath: .*/jar/idonotexist.jar")); } finally { bmaker.close(); } } public static void testExpandWithNegate() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); File cp[] = new File[] { IO.getFile("jar/asm.jar") }; p.put("Export-Package", "!org.objectweb.asm,*"); bmaker.setProperties(p); bmaker.setClasspath(cp); Jar jar = bmaker.build(); assertTrue(bmaker.check()); assertNull(jar.getDirectories().get("org/objectweb/asm")); assertNotNull(jar.getDirectories().get("org/objectweb/asm/signature")); assertEquals(0, bmaker.getWarnings().size()); assertEquals(0, bmaker.getErrors().size()); assertEquals(3, jar.getResources().size()); } finally { bmaker.close(); } } public static void testIncludeResourceResourcesOnlyJar() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); File cp[] = new File[] { IO.getFile("jar/ro.jar") }; p.put("Export-Package", "*"); p.put("Import-Package", ""); bmaker.setProperties(p); bmaker.setClasspath(cp); Jar jar = bmaker.build(); assertEquals(0, bmaker.getWarnings().size()); assertEquals(0, bmaker.getErrors().size()); assertEquals(3, jar.getResources().size()); } finally { bmaker.close(); } } public static void testIncludeResourceResourcesOnly() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); File cp[] = new File[] { new File("src") }; p.put("Import-Package", ""); p.put("Private-Package", "test.resourcesonly"); bmaker.setProperties(p); bmaker.setClasspath(cp); Jar jar = bmaker.build(); assertTrue(bmaker.check()); assertEquals(0, bmaker.getWarnings().size()); assertEquals(0, bmaker.getErrors().size()); assertEquals(4, jar.getResources().size()); } finally { bmaker.close(); } } public static void testIncludeResourceFromZipDefault() throws Exception { Builder bmaker = new Builder(); Properties p = new Properties(); p.put("Include-Resource", "@jar/easymock.jar"); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); assertEquals(59, jar.getResources().size()); } public static void testIncludeResourceFromZipDeep() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("Include-Resource", "@jar/easymock.jar!/**"); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); assertEquals(59, jar.getResources().size()); } finally { bmaker.close(); } } public static void testIncludeResourceFromZipOneDirectory() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("Import-Package", ""); p.put("Include-Resource", "@jar/easymock.jar!/org/easymock/**"); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); assertEquals(59, jar.getResources().size()); assertNotNull(jar.getResource("org/easymock/AbstractMatcher.class")); } finally { bmaker.close(); } } public static void testIncludeResourceFromZipOneDirectoryOther() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put(Constants.BUNDLE_CLASSPATH, "OPT-INF/test"); p.put("Import-Package", "!*"); p.put("-resourceonly", "true"); p.put("Include-Resource", "OPT-INF/test=@jar/osgi.jar!/org/osgi/service/event/**"); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); assertEquals(7, jar.getResources().size()); assertNotNull(jar.getResource("OPT-INF/test/org/osgi/service/event/EventAdmin.class")); } finally { bmaker.close(); } } public static void testIncludeResourceFromZipRecurseDirectory() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("Import-Package", "!*"); p.put("Include-Resource", "@jar/easymock.jar!/org/easymock/**"); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); assertEquals(59, jar.getResources().size()); } finally { bmaker.close(); } } public static void testIncludeLicenseFromZip() throws Exception { Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("Import-Package", ""); p.put("Include-Resource", "@jar/osgi.jar!/LICENSE"); bmaker.setProperties(p); Jar jar = bmaker.build(); assertTrue(bmaker.check()); assertEquals(1, jar.getResources().size()); assertNotNull(jar.getResource("LICENSE")); } finally { bmaker.close(); } } public static void testEasymock() throws Exception { File cp[] = { IO.getFile("jar/easymock.jar") }; Builder bmaker = new Builder(); try { Properties p = new Properties(); p.put("Import-Package", "*"); p.put("Export-Package", "*"); p.put("Bundle-SymbolicName", "easymock"); p.put("Bundle-Version", "2.2"); bmaker.setProperties(p); bmaker.setClasspath(cp); Jar jar = bmaker.build(); assertTrue(bmaker.check()); jar.getManifest().write(System.err); } finally { bmaker.close(); } } public static void testSources() throws Exception { Builder bmaker = new Builder(); try { bmaker.addClasspath(new File("bin")); bmaker.setSourcepath(new File[] { new File("src") }); bmaker.setProperty("-sources", "true"); bmaker.setProperty("Export-Package", "test.activator"); Jar jar = bmaker.build(); assertTrue(bmaker.check()); assertEquals( "[test/activator/AbstractActivator.class, test/activator/Activator.class, test/activator/Activator11.class, test/activator/Activator2.class, test/activator/Activator3.class, test/activator/ActivatorPackage.class, test/activator/ActivatorPrivate.class, test/activator/DefaultVisibilityActivator.class, test/activator/IActivator.class, test/activator/MissingNoArgsConstructorActivator.class, test/activator/NotAnActivator.class]", new SortedList<String>(jar.getDirectories().get("test/activator").keySet()).toString()); } finally { bmaker.close(); } } public void testVerify() throws Exception { System.err.println("Erroneous bundle: tb1.jar"); Jar jar = new Jar("test", getClass().getResourceAsStream("tb1.jar")); Verifier verifier = new Verifier(jar); verifier.verify(); assertTrue(verifier.check()); jar.close(); verifier.close(); } public static void report(String title, Analyzer builder, Jar jar) { System.err.println("Directories " + jar.getDirectories().keySet()); System.err.println("Warnings " + builder.getWarnings()); System.err.println("Errors " + builder.getErrors()); System.err.println("Exports " + builder.getExports()); System.err.println("Imports " + builder.getImports()); } }