package test.annotationheaders; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.util.Arrays; import java.util.Map.Entry; import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.regex.Matcher; import java.util.regex.Pattern; import aQute.bnd.annotation.headers.BundleCategory; import aQute.bnd.annotation.headers.BundleContributors; import aQute.bnd.annotation.headers.BundleCopyright; import aQute.bnd.annotation.headers.BundleDevelopers; import aQute.bnd.annotation.headers.BundleDocURL; import aQute.bnd.annotation.headers.Category; import aQute.bnd.annotation.headers.ProvideCapability; import aQute.bnd.annotation.headers.RequireCapability; import aQute.bnd.annotation.licenses.ASL_2_0; import aQute.bnd.header.Attrs; import aQute.bnd.header.Parameters; import aQute.bnd.osgi.Builder; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Domain; import aQute.bnd.osgi.Jar; import aQute.lib.io.IO; import junit.framework.TestCase; public class AnnotationHeadersTest extends TestCase { /** * Say I want to define a capability namespace for web applications, e.g. * Provide-Capability: webapp; webapp=Petstore. Web application components * necessarily require an HTTP implementation so they should * Require-Capability: osgi.implementation; * filter:="(osgi.implementation=osgi.http)". I want to define an annotation * that I can put onto a component that implies both the above provide and * require. I tried the following: * * <pre> * @ProvideCapability(ns = "webapp") * @RequireCapability(ns = "osgi.implementation", filter = "(osgi.implementation=osgi.http)") * @interface WebApplication { * String name(); * } * * @WebApplication(name = "Petstore") * @Component * public class PetstoreAppComponent { * // .. * } * </pre> * * However this only generated the Provide, it did not generate the Require. * If I switch the order of annotations so that @RequireCapability is first, * then it only generates the Require. */ public void testMultipleManifestHeaders() throws Exception { try (Builder b = new Builder();) { b.addClasspath(IO.getFile("bin")); b.setPrivatePackage("test.annotationheaders.multiple"); b.build(); assertTrue(b.check()); b.getJar().getManifest().write(System.out); Attributes mainAttributes = b.getJar().getManifest().getMainAttributes(); Parameters req = new Parameters( mainAttributes.getValue(Constants.REQUIRE_CAPABILITY)); Parameters cap = new Parameters( mainAttributes.getValue(Constants.PROVIDE_CAPABILITY)); assertTrue(cap.get("provide") != null); assertTrue(req.get("require") != null); } } /** * Default values of annotation attributes not included for customized * webresource annotations #976 * <p> * When I add a customized webresource annotation to a type definition, the * default attributes are not included in the Require-Capability header. For * example with the Jsonrpc webresource annotation this leads to the * following Require-Capability in the manifest: * osgi.enroute.webresource;filter:= * "(&(osgi.enroute.webresource=/osgi/enroute/jsonrpc)(&(version>=1.1.1)(!(version>=2.0.0))))". * Only when I explicitly add resource={"jsonrpc.js"} this is reflected in * the manifest: osgi.enroute.webresource;resource:List * <String>="jsonrpc.js";filter:= * "(&(osgi.enroute.webresource=/osgi/enroute/jsonrpc)(&(version>=1.1.1)(!(version>=2.0.0))))", * although jsonrpc.js is set as default for the resource attribute. */ public void testDefaultAttrs() throws Exception { try (Builder b = new Builder();) { b.addClasspath(IO.getFile("bin")); b.setPrivatePackage("test.annotationheaders.attrs.defaults"); b.build(); assertTrue(b.check()); b.getJar().getManifest().write(System.out); Domain d = Domain.domain(b.getJar().getManifest()); Parameters rc = d.getRequireCapability(); assertNotNull(rc); assertEquals(2, rc.size()); Attrs attrs = rc.get("default-attrs"); assertEquals("42", attrs.get("foo")); Parameters pc = d.getProvideCapability(); assertNotNull(pc); assertEquals(1, pc.size()); attrs = pc.get("default-attrs"); assertEquals("42", attrs.get("foo")); } } public void testWithAttrs() throws Exception { Builder b = new Builder(); try { b.addClasspath(new File("bin")); b.setProperty("Private-Package", "test.annotationheaders.attrs"); b.build(); assertTrue(b.check()); Manifest m = b.getJar().getManifest(); m.write(System.out); Parameters p = new Parameters(m.getMainAttributes().getValue("Provide-Capability")); Attrs attrs = p.get("nsx"); assertNotNull(attrs); assertEquals(Long.valueOf(3), attrs.getTyped("foo")); p = new Parameters(m.getMainAttributes().getValue("Bundle-License")); attrs = p.get("license"); assertNotNull(attrs); assertEquals("abc", attrs.get("foo")); p = new Parameters(m.getMainAttributes().getValue("Require-Capability")); // namespaces must be "osgi.ee", "nsx" and "nsy" ONLY assertNotNull(p.get("nsx")); assertNotNull(p.get("nsy")); assertNotNull(p.get("nsz")); assertNotNull(p.get("param")); assertNotNull(p.get("osgi.ee")); assertEquals("spurious Require-Capability namespaces", 5, p.size()); attrs = p.get("nsx"); assertEquals(Arrays.asList("abc", "def"), attrs.getTyped("foo")); attrs = p.get("nsy"); assertEquals("hello", attrs.get("value")); attrs = p.get("nsz"); assertEquals("(nsz=*)", attrs.get("filter:")); assertEquals("world", attrs.get("hello")); attrs = p.get("param"); assertEquals("(&(a=hello)(b=goodbye))", attrs.get("filter:")); } finally { b.close(); } } @RequireCapability(ns = "osgi.webresource", filter = "(&(osgi.webresource=/google/angular)${frange;${@version}})") @interface Angular { } @RequireCapability(ns = "not.there", filter = "(a=3)") @interface Notused { } @BundleDevelopers("Peter.Kriens@aQute.biz;name='Peter Kriens';organization=aQute") @interface pkriens {} @BundleContributors(value = "Mieke.Kriens@aQute.biz", name = "Mieke Kriens", organization = "aQute") @interface mkriens {} @BundleContributors(value = "Thomas.Kriens@aQute.biz", name = "Thomas Kriens", organization = "aQute") @interface tkriens {} @BundleContributors(value = "Mischa.Kriens@aQute.biz", name = "Mischa Kriens", organization = "aQute") @interface mischakriens {} @RequireCapability(ns = "abcdef", filter = "(&(abcdef=xyz)${frange;${@version}})") @ASL_2_0 @pkriens @mkriens @tkriens class A { } @BundleDocURL("http://www.aQute.biz") @BundleCopyright("(c) ${tstamp;yyyy} aQute All Rights Reserved and other baloney") @pkriens @mkriens @tkriens @BundleCategory(Category.adoption) class B { } @BundleCopyright("[[\n\rXyz: Hello world. , ; = \\]]") class Z { } @BundleCopyright("v=${@version} p=${@package} c=${@class} s=${@class-short}") @Angular class C { } // // Check if we can interface X { @RequireCapability(ns = "x", filter = "(x=xx)") @interface Require {} @ProvideCapability(ns = "x", name = "xx") @interface Provide {} } @X.Provide class XImpl {} @ProvideCapability(ns = "extrattrs", name = "extrattrs", value = "extra=YES") interface ExtraAttrs { } @RequireCapability(ns = "nofilter", filter = "") @interface NoFilterRequirement {} @NoFilterRequirement class NoFilterImpl {} public void testBasic() throws Exception { Builder b = new Builder(); b.addClasspath(new File("bin")); b.setProperty("Private-Package", "test.annotationheaders"); b.build(); assertTrue(b.check()); Manifest manifest = b.getJar().getManifest(); manifest.write(System.out); Parameters provideWithExtraAttrs = new Parameters( manifest.getMainAttributes().getValue(Constants.PROVIDE_CAPABILITY)); Attrs attrs = provideWithExtraAttrs.get("extrattrs"); assertNotNull(attrs); assertEquals("extrattrs=extrattrs;extra=YES", attrs.toString()); String rc = manifest.getMainAttributes().getValue(Constants.REQUIRE_CAPABILITY); assertNotNull(rc); System.out.println(rc); assertTrue(rc.contains("osgi.webresource=/google")); assertTrue(rc.contains(">=1.2.3")); // from package info assertTrue(rc.contains(">=2.0.0")); // from package info assertFalse(rc.contains("xx")); assertTrue(rc.contains(",nofilter,")); String pc = manifest.getMainAttributes().getValue(Constants.PROVIDE_CAPABILITY); assertNotNull(pc); System.out.println(pc); assertTrue(pc.contains("x=xx")); assertFalse(rc.contains("not.there")); String bl = manifest.getMainAttributes().getValue(Constants.BUNDLE_LICENSE); assertNotNull(bl); System.out.println(bl); assertTrue(bl.contains("http://www.opensource.org/licenses/apache2.0.php;")); assertTrue(bl.contains("MIT")); assertFalse(bl.contains("GPL")); String dv = manifest.getMainAttributes().getValue(Constants.BUNDLE_DEVELOPERS); assertNotNull(dv); System.out.println(dv); assertTrue(dv.contains("Peter Kriens")); dv = manifest.getMainAttributes().getValue(Constants.BUNDLE_CONTRIBUTORS); assertNotNull(dv); System.out.println(dv); assertTrue(dv.contains("Mieke Kriens")); assertTrue(dv.contains("Thomas Kriens")); assertFalse(dv.contains("Mischa Kriens")); dv = manifest.getMainAttributes().getValue(Constants.BUNDLE_COPYRIGHT); assertNotNull(dv); System.out.println(dv); assertTrue(dv.contains("other baloney")); Matcher m = Pattern.compile("([0-9]{4})").matcher(dv); assertTrue(m.find()); assertTrue(Integer.parseInt(m.group(1)) >= 2014); assertTrue(dv.contains("v=1.2.3")); assertTrue(dv.contains("p=test.annotationheaders")); assertTrue(dv.contains("c=test.annotationheaders.AnnotationHeadersTest$C")); assertTrue(dv.contains("s=AnnotationHeadersTest$C")); dv = manifest.getMainAttributes().getValue(Constants.BUNDLE_DOCURL); assertNotNull(dv); System.out.println(dv); assertTrue(dv.contains("http://www.aQute.biz")); Parameters cpr = new Parameters(manifest.getMainAttributes().getValue(Constants.BUNDLE_COPYRIGHT)); for (Entry<String,Attrs> e : cpr.entrySet()) { System.out.println("cpr: " + e); } ByteArrayOutputStream bout = new ByteArrayOutputStream(); Jar.writeManifest(manifest, bout); String s = new String(bout.toByteArray(), "UTF-8"); System.out.println(s); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); Manifest m2 = new Manifest(bin); String v = m2.getMainAttributes().getValue(Constants.BUNDLE_COPYRIGHT); assertNotNull(v); assertTrue(v.contains("Hello world")); assertNull(m2.getMainAttributes().getValue("Xyz")); b.close(); } }