package test.component; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.concurrent.CopyOnWriteArrayList; import java.util.jar.Attributes; import java.util.jar.Manifest; import javax.xml.xpath.XPathExpressionException; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.ComponentServiceObjects; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.FieldOption; import org.osgi.service.component.annotations.Modified; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.component.annotations.ServiceScope; import org.osgi.service.log.LogService; import org.osgi.service.metatype.annotations.Designate; import org.osgi.service.metatype.annotations.ObjectClassDefinition; import aQute.bnd.annotation.xml.XMLAttribute; import aQute.bnd.header.Attrs; import aQute.bnd.header.Parameters; import aQute.bnd.osgi.Builder; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Jar; import aQute.bnd.osgi.Processor; import aQute.bnd.osgi.Resource; import aQute.bnd.test.BndTestCase; import aQute.bnd.test.XmlTester; import junit.framework.AssertionFailedError; /** * Test for use of DS components specified using spec DS annotations. */ @SuppressWarnings({ "resource", "restriction", "serial" }) public class DSAnnotationTest extends BndTestCase { public static final String FELIX_1_2 = "http://felix.apache.org/xmlns/scr/v1.2.0-felix"; private static String[] SERIALIZABLE_RUNNABLE = { Serializable.class.getName(), Runnable.class.getName() }; private static String[] OBJECT = { Object.class.getName() }; /** * Property test */ @Component() public static class ValidNSVersion { } public void testValidNamespaceVersion() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*ValidNSVersion"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); b.addClasspath(new File("jar/osgi.jar")); // v1.0.0 Jar jar = b.build(); if (!b.check()) fail(); Attributes a = getAttr(jar); checkProvides(a); checkRequires(a, null); Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$ValidNSVersion.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); } /** * Property test */ @Component(xmlns = "http://www.osgi.org/xmlns/scr/v1.1.0", property = { "x:Integer=3.0", "a=1", "a=2", "b=1", "boolean:Boolean=true", "byte:Byte=1", "char:Character=1", "short:Short=3", "integer:Integer=3", "long:Long=3", "float:Float=3.0", "double:Double=3e7", "string:String=%", "wrongInteger:Integer=blabla", "\n\r\t \u0343\u0344\u0345\u0346\n:Integer=3" }) public static class PropertiesTestx { } public void testProperties() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*x"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); if (!b.check("Cannot convert data blabla to type Integer", "Cannot convert data 3.0 to type Integer")) fail(); Attributes a = getAttr(jar); checkProvides(a); checkRequires(a, null); // // Test all the defaults // Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$PropertiesTestx.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.1.0"); xt.assertAttribute("1", "scr:component/property[@name='b']/@value"); xt.assertAttribute("", "scr:component/property[@name='a']/@value"); xt.assertAttribute("Byte", "scr:component/property[@name='byte']/@type"); xt.assertAttribute("Boolean", "scr:component/property[@name='boolean']/@type"); xt.assertAttribute("Character", "scr:component/property[@name='char']/@type"); xt.assertAttribute("Short", "scr:component/property[@name='short']/@type"); xt.assertAttribute("Integer", "scr:component/property[@name='integer']/@type"); xt.assertAttribute("Long", "scr:component/property[@name='long']/@type"); xt.assertAttribute("Float", "scr:component/property[@name='float']/@type"); xt.assertAttribute("Double", "scr:component/property[@name='double']/@type"); xt.assertAttribute("Integer", "scr:component/property[@name='\u0343\u0344\u0345\u0346']/@type"); } /** * Check that a DS 1.0 compotible class with annotations ends up with the DS * 1.0 (no) namespace */ @Component() public static class DS10_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate protected void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate protected void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference protected void xsetLogService(@SuppressWarnings("unused") LogService log) { } protected void unxsetLogService(@SuppressWarnings("unused") LogService log) { } @Override public void run() { // TODO Auto-generated method stub } } @Component public static class DS11_1_very_basic { @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate protected void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference protected void setLogService(@SuppressWarnings("unused") LogService log) {} protected void unsetLogService(@SuppressWarnings("unused") LogService log) {} } @Component public static class DS11_2_very_basic { @Activate protected void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference protected void setLogService(@SuppressWarnings("unused") LogService log) {} protected void unsetLogService(@SuppressWarnings("unused") LogService log) {} } @Component public static class DS11_3_very_basic { @Activate protected void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate protected void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference void setLogService(@SuppressWarnings("unused") LogService log) {} protected void unsetLogService(@SuppressWarnings("unused") LogService log) {} } @Component public static class DS11_4_very_basic { @Activate protected void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate protected void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference protected void setLogService(@SuppressWarnings("unused") LogService log) {} void unsetLogService(@SuppressWarnings("unused") LogService log) {} } @Component public static class DS11_5_very_basic { @Activate public void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate protected void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference protected void setLogService(@SuppressWarnings("unused") LogService log) {} protected void unsetLogService(@SuppressWarnings("unused") LogService log) {} } @Component public static class DS11_6_very_basic { @Activate protected void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate public void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference protected void setLogService(@SuppressWarnings("unused") LogService log) {} protected void unsetLogService(@SuppressWarnings("unused") LogService log) {} } @Component public static class DS11_7_very_basic { @Activate protected void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate protected void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference public void setLogService(@SuppressWarnings("unused") LogService log) {} protected void unsetLogService(@SuppressWarnings("unused") LogService log) {} } @Component public static class DS11_8_very_basic { @Activate protected void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate protected void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference protected void setLogService(@SuppressWarnings("unused") LogService log) {} public void unsetLogService(@SuppressWarnings("unused") LogService log) {} } /** * Check that a DS 1.1 compotible class ends up with the DS 1.1 namespace * and appropriate activate/deactivate attributes */ @Component() public static class DS11_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") BundleContext ctx) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") int cause) {} @Reference void xsetLogService(@SuppressWarnings("unused") LogService log) { } void unxsetLogService(@SuppressWarnings("unused") LogService log) { } @Override public void run() { // TODO Auto-generated method stub } } /** * Check that a DS 1.1 bind method causes a DS 1.1 namespace */ @Component() public static class DS11_ref1_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference void xsetLogService(@SuppressWarnings("unused") LogService log, @SuppressWarnings({ "unused", "rawtypes" }) Map map) { } void unxsetLogService(@SuppressWarnings("unused") LogService log) { } @Override public void run() { // TODO Auto-generated method stub } } /** * Check that a DS 1.1 unbind method causes a DS 1.1 namespace */ @Component() public static class DS11_ref2_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Reference void xsetLogService(@SuppressWarnings("unused") LogService log) { } void unxsetLogService(@SuppressWarnings("unused") LogService log, @SuppressWarnings("unused") Map< ? , ? > map) { } @Override public void run() { // TODO Auto-generated method stub } } /** * The basic test. This test will take an all default component and a * component that has all values set. Since the activate/deactivate methods * have non-default names and there is a modified methods, this is a DS 1.1 * component. */ @Component() public static class Defaults_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void open() {} @Deactivate void close() {} @Modified void modified() {} @Reference void xsetLogService(@SuppressWarnings("unused") LogService log) { } void unxsetLogService(@SuppressWarnings("unused") LogService log) { } // void modifiedLogService(LogService log) { // // } @Override public void run() { // TODO Auto-generated method stub } } @Component(service = Object.class, configurationPolicy = ConfigurationPolicy.IGNORE, enabled = false, factory = "factory", immediate = false, name = "name", property = { "a=1", "a=2", "b=3" }, properties = "resource.props", servicefactory = false, configurationPid = "configuration-pid", xmlns = "xmlns") public static class Explicit_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void open() {} @Deactivate void close() {} @Modified void changed() {} @Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE, name = "foo", policy = ReferencePolicy.DYNAMIC, service = LogService.class, target = "(objectclass=*)", unbind = "unset", updated = "updatedLogService", policyOption = ReferencePolicyOption.GREEDY) void setLogService(@SuppressWarnings("unused") Object log) { } void unset(@SuppressWarnings("unused") Object log) { } void unset() { } void unsetLogService(@SuppressWarnings("unused") LogService log) { } void updatedLogService(@SuppressWarnings("unused") Object log) { } @Override public void run() { // TODO Auto-generated method stub } } public void testBasic() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*_basic"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "version;minimum=1.0.0"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); { // // Test all the DS 1.0 defaults // Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$DS10_basic.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream()); // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$DS10_basic", "component/implementation/@class"); // Default must be the implementation class xt.assertAttribute("test.component.DSAnnotationTest$DS10_basic", "component/@name"); xt.assertAttribute("", "component/@configuration-policy"); xt.assertAttribute("", "component/@immediate"); xt.assertAttribute("", "component/@enabled"); xt.assertAttribute("", "component/@factory"); xt.assertAttribute("", "component/service/@servicefactory"); xt.assertAttribute("", "component/@configuration-pid"); xt.assertAttribute("", "component/@activate"); xt.assertAttribute("", "component/@deactivate"); xt.assertAttribute("", "component/@modified"); xt.assertAttribute("java.io.Serializable", "component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "component/service/provide[2]/@interface"); xt.assertAttribute("0", "count(component/properties)"); xt.assertAttribute("0", "count(component/property)"); xt.assertAttribute("xsetLogService", "component/reference[1]/@name"); xt.assertAttribute("", "component/reference[1]/@target"); xt.assertAttribute("xsetLogService", "component/reference[1]/@bind"); xt.assertAttribute("unxsetLogService", "component/reference[1]/@unbind"); xt.assertAttribute("", "component/reference[1]/@cardinality"); xt.assertAttribute("", "component/reference[1]/@policy"); xt.assertAttribute("", "component/reference[1]/@target"); xt.assertAttribute("", "component/reference[1]/@policy-option"); } { // // Test package methods >> DS 1.1 // verifyDS11VeryBasic(jar, DS11_1_very_basic.class); verifyDS11VeryBasic(jar, DS11_2_very_basic.class); verifyDS11VeryBasic(jar, DS11_3_very_basic.class); verifyDS11VeryBasic(jar, DS11_4_very_basic.class); verifyDS11VeryBasic(jar, DS11_5_very_basic.class); verifyDS11VeryBasic(jar, DS11_6_very_basic.class); verifyDS11VeryBasic(jar, DS11_7_very_basic.class); verifyDS11VeryBasic(jar, DS11_8_very_basic.class); } { // // Test the DS 1.1 defaults // Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$DS11_basic.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.1.0"); // #136 // was // http://www.osgi.org/xmlns/scr/1.1.0 // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$DS11_basic", "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute("test.component.DSAnnotationTest$DS11_basic", "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute("", "scr:component/service/@servicefactory"); xt.assertAttribute("", "scr:component/@configuration-pid"); xt.assertAttribute("activate", "scr:component/@activate"); xt.assertAttribute("deactivate", "scr:component/@deactivate"); xt.assertAttribute("", "scr:component/@modified"); xt.assertAttribute("java.io.Serializable", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "scr:component/service/provide[2]/@interface"); xt.assertAttribute("0", "count(scr:component/properties)"); xt.assertAttribute("0", "count(scr:component/property)"); xt.assertAttribute("xsetLogService", "scr:component/reference[1]/@name"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("xsetLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unxsetLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("", "scr:component/reference[1]/@cardinality"); xt.assertAttribute("", "scr:component/reference[1]/@policy"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("", "scr:component/reference[1]/@policy-option"); } { // // Test a DS 1.1 bind method results in the DS 1.1 namespace // Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$DS11_ref1_basic.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.1.0"); // #136 // was // http://www.osgi.org/xmlns/scr/1.1.0 // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$DS11_ref1_basic", "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute("test.component.DSAnnotationTest$DS11_ref1_basic", "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute("", "scr:component/service/@servicefactory"); xt.assertAttribute("", "scr:component/@configuration-pid"); xt.assertAttribute("activate", "scr:component/@activate"); xt.assertAttribute("deactivate", "scr:component/@deactivate"); xt.assertAttribute("", "scr:component/@modified"); xt.assertAttribute("java.io.Serializable", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "scr:component/service/provide[2]/@interface"); xt.assertAttribute("0", "count(scr:component/properties)"); xt.assertAttribute("0", "count(scr:component/property)"); xt.assertAttribute("xsetLogService", "scr:component/reference[1]/@name"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("xsetLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unxsetLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("", "scr:component/reference[1]/@cardinality"); xt.assertAttribute("", "scr:component/reference[1]/@policy"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("", "scr:component/reference[1]/@policy-option"); } { // // Test a DS 1.1 unbind method results in the DS 1.1 namespace // Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$DS11_ref2_basic.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.1.0"); // #136 // was // http://www.osgi.org/xmlns/scr/1.1.0 // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$DS11_ref2_basic", "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute("test.component.DSAnnotationTest$DS11_ref2_basic", "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute("", "scr:component/service/@servicefactory"); xt.assertAttribute("", "scr:component/@configuration-pid"); xt.assertAttribute("activate", "scr:component/@activate"); xt.assertAttribute("deactivate", "scr:component/@deactivate"); xt.assertAttribute("", "scr:component/@modified"); xt.assertAttribute("java.io.Serializable", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "scr:component/service/provide[2]/@interface"); xt.assertAttribute("0", "count(scr:component/properties)"); xt.assertAttribute("0", "count(scr:component/property)"); xt.assertAttribute("xsetLogService", "scr:component/reference[1]/@name"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("xsetLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unxsetLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("", "scr:component/reference[1]/@cardinality"); xt.assertAttribute("", "scr:component/reference[1]/@policy"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("", "scr:component/reference[1]/@policy-option"); } { // // Test all the defaults // Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$Defaults_basic.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.1.0"); // #136 // was // http://www.osgi.org/xmlns/scr/1.1.0 // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$Defaults_basic", "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute("test.component.DSAnnotationTest$Defaults_basic", "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute("", "scr:component/service/@servicefactory"); xt.assertAttribute("", "scr:component/@configuration-pid"); xt.assertAttribute("open", "scr:component/@activate"); xt.assertAttribute("close", "scr:component/@deactivate"); xt.assertAttribute("modified", "scr:component/@modified"); xt.assertAttribute("java.io.Serializable", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "scr:component/service/provide[2]/@interface"); xt.assertAttribute("0", "count(scr:component/properties)"); xt.assertAttribute("0", "count(scr:component/property)"); xt.assertAttribute("xsetLogService", "scr:component/reference[1]/@name"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("xsetLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unxsetLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("", "scr:component/reference[1]/@cardinality"); xt.assertAttribute("", "scr:component/reference[1]/@policy"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("", "scr:component/reference[1]/@policy-option"); } { // // Test explicit // Resource r = jar.getResource("OSGI-INF/name.xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "xmlns"); // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$Explicit_basic", "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute("name", "scr:component/@name"); xt.assertAttribute("ignore", "scr:component/@configuration-policy"); xt.assertAttribute("configuration-pid", "scr:component/@configuration-pid"); xt.assertAttribute("false", "scr:component/@immediate"); xt.assertAttribute("false", "scr:component/@enabled"); xt.assertAttribute("factory", "scr:component/@factory"); xt.assertAttribute("false", "scr:component/service/@servicefactory"); xt.assertAttribute("open", "scr:component/@activate"); xt.assertAttribute("close", "scr:component/@deactivate"); xt.assertAttribute("changed", "scr:component/@modified"); xt.assertAttribute("java.lang.Object", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("1", "count(scr:component/service/provide)"); xt.assertAttribute("1", "count(scr:component/properties)"); xt.assertAttribute("2", "count(scr:component/property)"); xt.assertAttribute("(objectclass=*)", "scr:component/reference[1]/@target"); xt.assertAttribute("setLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unset", "scr:component/reference[1]/@unbind"); xt.assertAttribute("updatedLogService", "scr:component/reference[1]/@updated"); xt.assertAttribute("1..n", "scr:component/reference[1]/@cardinality"); xt.assertAttribute("dynamic", "scr:component/reference[1]/@policy"); xt.assertAttribute("(objectclass=*)", "scr:component/reference[1]/@target"); xt.assertAttribute("2", "count(scr:component/property)"); xt.assertAttribute("1", "count(scr:component/properties)"); xt.assertAttribute("resource.props", "scr:component/properties[1]/@entry"); xt.assertAttribute("greedy", "scr:component/reference[1]/@policy-option"); } Attributes a = getAttr(jar); checkProvides(a, SERIALIZABLE_RUNNABLE, OBJECT); // n.b. we should merge the 2 logService requires, so when we fix that // we'll need to update this test. // one is plain, other has cardinality multiple. checkRequires(a, "1.3.0", LogService.class.getName(), LogService.class.getName()); } private void verifyDS11VeryBasic(Jar jar, Class< ? > clazz) throws Exception, XPathExpressionException { String className = clazz.getName(); Resource r = jar.getResource("OSGI-INF/" + className + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.1.0"); // #136 // was // http://www.osgi.org/xmlns/scr/1.1.0 // Test the defaults xt.assertAttribute(className, "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute(className, "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute("", "scr:component/service/@servicefactory"); xt.assertAttribute("", "scr:component/@configuration-pid"); xt.assertAttribute("activate", "scr:component/@activate"); xt.assertAttribute("deactivate", "scr:component/@deactivate"); xt.assertAttribute("", "scr:component/@modified"); xt.assertAttribute("0", "count(scr:component/properties)"); xt.assertAttribute("0", "count(scr:component/property)"); xt.assertAttribute("LogService", "scr:component/reference[1]/@name"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("setLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unsetLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("", "scr:component/reference[1]/@cardinality"); xt.assertAttribute("", "scr:component/reference[1]/@policy"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("", "scr:component/reference[1]/@policy-option"); } /** * Check that a Felix 1.2 compotible class ends up with the Felix 1.2 * namespace and appropriate activate/deactivate attributes */ @Component(xmlns = FELIX_1_2) public static class activate_basicFelix12 implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate Map<String,Object> activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") BundleContext ctx) { return null; } @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") int cause) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference void setLogService(@SuppressWarnings("unused") LogService log) {} void unsetLogService(@SuppressWarnings("unused") LogService log) {} void updatedLogService(@SuppressWarnings("unused") LogService log) {} @Override public void run() { // TODO Auto-generated method stub } } @Component(xmlns = FELIX_1_2) public static class deactivate_basicFelix12 implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") BundleContext ctx) {} @Deactivate Map<String,Object> deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") int cause) { return null; } @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference void setLogService(@SuppressWarnings("unused") LogService log) {} void unsetLogService(@SuppressWarnings("unused") LogService log) {} void updatedLogService(@SuppressWarnings("unused") LogService log) {} @Override public void run() { // TODO Auto-generated method stub } } @Component(xmlns = FELIX_1_2) public static class modified_basicFelix12 implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") BundleContext ctx) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") int cause) {} @Modified Map<String,Object> modified(@SuppressWarnings("unused") ComponentContext cc) { return null; } @Reference void setLogService(@SuppressWarnings("unused") LogService log) {} void unsetLogService(@SuppressWarnings("unused") LogService log) {} void updatedLogService(@SuppressWarnings("unused") LogService log) {} @Override public void run() { // TODO Auto-generated method stub } } @Component(xmlns = FELIX_1_2) public static class bind_basicFelix12 implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") BundleContext ctx) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") int cause) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference Map<String,Object> setLogService(@SuppressWarnings("unused") LogService log) { return null; } void unsetLogService(@SuppressWarnings("unused") LogService log) {} void updatedLogService(@SuppressWarnings("unused") LogService log) {} @Override public void run() { // TODO Auto-generated method stub } } @Component(xmlns = FELIX_1_2) public static class unbind_basicFelix12 implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") BundleContext ctx) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") int cause) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference void setLogService(@SuppressWarnings("unused") LogService log) {} Map<String,Object> unsetLogService(@SuppressWarnings("unused") LogService log) { return null; } void updatedLogService(@SuppressWarnings("unused") LogService log) {} @Override public void run() { // TODO Auto-generated method stub } } @Component(xmlns = FELIX_1_2) public static class updated_basicFelix12 implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") BundleContext ctx) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") int cause) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference void setLogService(@SuppressWarnings("unused") LogService log) {} void unsetLogService(@SuppressWarnings("unused") LogService log) {} Map<String,Object> updatedLogService(@SuppressWarnings("unused") LogService log) { return null; } @Override public void run() { // TODO Auto-generated method stub } } public void testBasicFelix12() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*_basicFelix12"); b.setProperty("-ds-felix-extensions", "true"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a, SERIALIZABLE_RUNNABLE); checkRequires(a, null, LogService.class.getName()); // Test Felix12 activate gives Felix 1.2 namespace checkDSFelix12(jar, "test.component.DSAnnotationTest$activate_basicFelix12"); // Test Felix12 deactivate gives Felix 1.2 namespace checkDSFelix12(jar, "test.component.DSAnnotationTest$deactivate_basicFelix12"); // Test Felix12 modified gives Felix 1.2 namespace checkDSFelix12(jar, "test.component.DSAnnotationTest$modified_basicFelix12"); // Test Felix12 bind gives Felix 1.2 namespace checkDSFelix12(jar, "test.component.DSAnnotationTest$bind_basicFelix12"); // Test Felix12 bind gives Felix 1.2 namespace checkDSFelix12(jar, "test.component.DSAnnotationTest$unbind_basicFelix12"); // Test Felix12 updated gives Felix 1.2 namespace checkDSFelix12(jar, "test.component.DSAnnotationTest$updated_basicFelix12"); } private void checkDSFelix12(Jar jar, String name) throws Exception, XPathExpressionException { Resource r = jar.getResource("OSGI-INF/" + name + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", FELIX_1_2); // Test the defaults xt.assertAttribute(name, "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute(name, "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute("", "scr:component/service/@servicefactory"); xt.assertAttribute("", "scr:component/@configuration-pid"); xt.assertAttribute("activate", "scr:component/@activate"); xt.assertAttribute("deactivate", "scr:component/@deactivate"); xt.assertAttribute("modified", "scr:component/@modified"); xt.assertAttribute("java.io.Serializable", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "scr:component/service/provide[2]/@interface"); xt.assertAttribute("0", "count(scr:component/properties)"); xt.assertAttribute("0", "count(scr:component/property)"); xt.assertAttribute("LogService", "scr:component/reference[1]/@name"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("setLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unsetLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("updatedLogService", "scr:component/reference[1]/@updated"); xt.assertAttribute("", "scr:component/reference[1]/@cardinality"); xt.assertAttribute("", "scr:component/reference[1]/@policy"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("", "scr:component/reference[1]/@policy-option"); } /** * Tests all the different enum values. This also tests the ordering. */ @Component(name = "enums") public static class Enums { @Reference void setA(@SuppressWarnings("unused") LogService l) {} @Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY) void setB(@SuppressWarnings("unused") LogService l) {} void unsetB(@SuppressWarnings("unused") LogService l) {} @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.RELUCTANT) void setE(@SuppressWarnings("unused") LogService l) {} void unsetE(@SuppressWarnings("unused") LogService l) {} @Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.RELUCTANT) void setC(@SuppressWarnings("unused") LogService l) {} @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY) void setD(@SuppressWarnings("unused") LogService l) {} void unsetD(@SuppressWarnings("unused") LogService l) {} } public void testEnums() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*Enums"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "version;minimum=1.0.0"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a); checkRequires(a, null, LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/enums.xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.2.0"); xt.assertAttribute("A", "scr:component/reference[1]/@name"); xt.assertAttribute("", "scr:component/reference[1]/@cardinality"); xt.assertAttribute("", "scr:component/reference[1]/@policy"); xt.assertAttribute("", "scr:component/reference[1]/@policy-option"); xt.assertAttribute("B", "scr:component/reference[2]/@name"); xt.assertAttribute("1..n", "scr:component/reference[2]/@cardinality"); xt.assertAttribute("dynamic", "scr:component/reference[2]/@policy"); xt.assertAttribute("greedy", "scr:component/reference[2]/@policy-option"); xt.assertAttribute("C", "scr:component/reference[3]/@name"); xt.assertAttribute("1..1", "scr:component/reference[3]/@cardinality"); xt.assertAttribute("static", "scr:component/reference[3]/@policy"); xt.assertAttribute("reluctant", "scr:component/reference[3]/@policy-option"); xt.assertAttribute("D", "scr:component/reference[4]/@name"); xt.assertAttribute("0..n", "scr:component/reference[4]/@cardinality"); xt.assertAttribute("dynamic", "scr:component/reference[4]/@policy"); xt.assertAttribute("greedy", "scr:component/reference[4]/@policy-option"); xt.assertAttribute("E", "scr:component/reference[5]/@name"); xt.assertAttribute("0..1", "scr:component/reference[5]/@cardinality"); xt.assertAttribute("dynamic", "scr:component/reference[5]/@policy"); xt.assertAttribute("reluctant", "scr:component/reference[5]/@policy-option"); } /** * Test the - for the unbind and updated parameter. */ @Component(name = "methods") public static class Methods { @Reference(unbind = "-", updated = "-") void setA(@SuppressWarnings("unused") LogService l) {} void updatedA(@SuppressWarnings("unused") LogService l) {} void unsetA(@SuppressWarnings("unused") LogService l) {} @Reference(unbind = "_B", updated = "__B") void setB(@SuppressWarnings("unused") LogService l) {} void _B(@SuppressWarnings("unused") LogService l) {} void __B(@SuppressWarnings("unused") LogService l) {} void updatedB(@SuppressWarnings("unused") LogService l) {} void unsetB(@SuppressWarnings("unused") LogService l) {} @Reference void setC(@SuppressWarnings("unused") LogService l) {} void updatedC(@SuppressWarnings("unused") LogService l) {} void unsetC(@SuppressWarnings("unused") LogService l) {} @Reference void setD(@SuppressWarnings("unused") LogService l) {} } public void testMethods() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*Methods"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "version;minimum=1.0.0"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a); checkRequires(a, null, LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/methods.xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.2.0"); // use - to make sure no unbind and updated method is set xt.assertAttribute("A", "scr:component/reference[1]/@name"); xt.assertAttribute("setA", "scr:component/reference[1]/@bind"); xt.assertAttribute("", "scr:component/reference[1]/@unbind"); xt.assertAttribute("", "scr:component/reference[1]/@updated"); // override the names for the methods xt.assertAttribute("B", "scr:component/reference[2]/@name"); xt.assertAttribute("setB", "scr:component/reference[2]/@bind"); xt.assertAttribute("_B", "scr:component/reference[2]/@unbind"); xt.assertAttribute("__B", "scr:component/reference[2]/@updated"); xt.assertAttribute("C", "scr:component/reference[3]/@name"); xt.assertAttribute("setC", "scr:component/reference[3]/@bind"); xt.assertAttribute("unsetC", "scr:component/reference[3]/@unbind"); xt.assertAttribute("updatedC", "scr:component/reference[3]/@updated"); xt.assertAttribute("D", "scr:component/reference[4]/@name"); xt.assertAttribute("setD", "scr:component/reference[4]/@bind"); xt.assertAttribute("", "scr:component/reference[4]/@unbind"); xt.assertAttribute("", "scr:component/reference[4]/@updated"); } /** * Test inheritance (this is not official) */ public static class Top { @Reference void setLogService(@SuppressWarnings("unused") LogService l) {} void updatedLogService(@SuppressWarnings("unused") ServiceReference< ? > ref) { } @Reference protected void setPrivateLogService(@SuppressWarnings("unused") LogService l) { } @SuppressWarnings("unused") private void updatedPrivateLogService(ServiceReference< ? > ref) { } } @Component(name = "bottom") public static class Bottom extends Top { void unsetLogService(@SuppressWarnings("unused") LogService l, @SuppressWarnings("unused") Map<Object,Object> map) { } void unsetPrivateLogService(@SuppressWarnings("unused") ServiceReference< ? > ref) { } } public void testInheritance() throws Exception { testInheritance("-dsannotations-inherit", "true", null); } public void testInheritanceFlag() throws Exception { testInheritance(Constants.DSANNOTATIONS_OPTIONS, "inherit", null); } public void testInheritanceExtenderFlag() throws Exception { testInheritance(Constants.DSANNOTATIONS_OPTIONS, "inherit,extender", "1.3.0"); } public void testInheritance(String key, String value, String extender) throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*Bottom"); b.setProperty(key, value); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a); checkRequires(a, extender, LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/bottom.xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); xt.assertAttribute("LogService", "scr:component/reference[1]/@name"); xt.assertAttribute("setLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unsetLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("updatedLogService", "scr:component/reference[1]/@updated"); xt.assertAttribute("PrivateLogService", "scr:component/reference[2]/@name"); xt.assertAttribute("setPrivateLogService", "scr:component/reference[2]/@bind"); xt.assertAttribute("unsetPrivateLogService", "scr:component/reference[2]/@unbind"); // is private in super class xt.assertAttribute("", "scr:component/reference[2]/@updated"); } public void testBadFlag() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*Bottom"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "foo"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertEquals(1, b.getErrors().size()); assertEquals(0, b.getWarnings().size()); } /** * Test the different prototypes ... */ @Component(name = "prototypes") public static class Prototypes { @SuppressWarnings("unused") @Activate private void activate() {} @Deactivate protected void deactivate(@SuppressWarnings("unused") ComponentContext ctx) { } @Modified void modified(@SuppressWarnings("unused") BundleContext context) { } @SuppressWarnings("unused") @Reference private void setLogService(LogService l) { } protected void unsetLogService(@SuppressWarnings("unused") LogService l, @SuppressWarnings("unused") Map<Object,Object> map) { } void updatedLogService(@SuppressWarnings("unused") ServiceReference< ? > ref) { } } public void testPrototypes() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*Prototypes"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "version;minimum=1.0.0"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a); checkRequires(a, null, LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/prototypes.xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.2.0"); xt.assertAttribute("LogService", "scr:component/reference[1]/@name"); xt.assertAttribute("setLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unsetLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("updatedLogService", "scr:component/reference[1]/@updated"); } /** * Test the different prototypes ... */ @Component(name = "prototypes") public static class CheckBinds { @SuppressWarnings("unused") @Activate private void activate() {} @Deactivate protected void deactivate(@SuppressWarnings("unused") ComponentContext ctx) { } @Modified void modified(@SuppressWarnings("unused") BundleContext context) { } @SuppressWarnings("unused") @Reference private void bindLogService(LogService l) { } protected void unbindLogService(@SuppressWarnings("unused") LogService l, @SuppressWarnings("unused") Map<Object,Object> map) { } void updatedLogService(@SuppressWarnings("unused") ServiceReference< ? > ref) { } } public void testBinds() throws Exception { testBinds(null); } public void testBindsExtender() throws Exception { testBinds("1.3.0"); } public void testBinds(String extender) throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*CheckBinds"); if (extender != null) b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "extender"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS + ".min", "version;minimum=1.2.0"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a); checkRequires(a, extender, LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/prototypes.xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.2.0"); xt.assertAttribute("LogService", "scr:component/reference[1]/@name"); xt.assertAttribute("bindLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unbindLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("updatedLogService", "scr:component/reference[1]/@updated"); } @Component public static class CheckBinds13 { @Reference private void bindService(LogService l) {} protected void unbindService(LogService l) {} void updatedService(LogService l) {} @Reference private void bindSR(ServiceReference<LogService> l) {} protected void unbindSR(ServiceReference<LogService> l) {} void updatedSR(ServiceReference<LogService> l) {} @Reference(service = LogService.class) private void bindProps(Map<String,Object> l) {} protected void unbindProps(Map<String,Object> l) {} void updatedProps(Map<String,Object> l) {} @Reference private void bindSO(ComponentServiceObjects<LogService> l) {} protected void unbindSO(ComponentServiceObjects<LogService> l) {} void updatedSO(ComponentServiceObjects<LogService> l) {} @Reference private void bindTuple(Map.Entry<Map<String,Object>,LogService> l) {} protected void unbindTuple(Map.Entry<Map<String,Object>,LogService> l) {} void updatedTuple(Map.Entry<Map<String,Object>,LogService> l) {} @Reference private void bindServiceSR(LogService l, ServiceReference<LogService> l2) {} protected void unbindServiceSR(LogService l, ServiceReference<LogService> l2) {} void updatedServiceSR(LogService l, ServiceReference<LogService> l2) {} @Reference private void bindPropsSR(Map<String,Object> l, ServiceReference<LogService> l2) {} protected void unbindPropsSR(Map<String,Object> l, ServiceReference<LogService> l2) {} void updatedPropsSR(Map<String,Object> l, ServiceReference<LogService> l2) {} @Reference private void bindPropsTuple(Map<String,Object> l, Map.Entry<Map<String,Object>,LogService> l2) {} protected void unbindPropsTuple(Map<String,Object> l, Map.Entry<Map<String,Object>,LogService> l2) {} void updatedPropsTuple(Map<String,Object> l, Map.Entry<Map<String,Object>,LogService> l2) {} } public void testBinds13() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*CheckBinds13"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a); checkRequires(a, "1.3.0", LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/" + CheckBinds13.class.getName() + ".xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); for (int i = 1; i <= 8; i++) { xt.assertAttribute(LogService.class.getName(), "scr:component/reference[" + i + "]/@interface"); } } @Component(name = "NoUnbindDynamic") public static class NoUnbindDynamic { @SuppressWarnings("unused") @Reference(policy = ReferencePolicy.DYNAMIC) private void bindLogService(LogService l) {} } public void testNoUnbindDynamic() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*NoUnbindDynamic"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertEquals(1, b.getErrors().size()); assertTrue(b.getErrors().get(0).endsWith("dynamic but has no unbind method.")); } @Component(name = "testConfigPolicy", configurationPolicy = ConfigurationPolicy.IGNORE) public static class TestConfigPolicy {} public void testConfigPolicySetsNamespace() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*TestConfigPolicy"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "version;minimum=1.0.0"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a); checkRequires(a, null); Resource r = jar.getResource("OSGI-INF/testConfigPolicy.xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.1.0"); xt.assertNamespace("http://www.osgi.org/xmlns/scr/v1.1.0"); } @Component() public static class issue347 implements Serializable, Runnable { private static final long serialVersionUID = 1L; /* * #347 - When using DS 1.2 annotations @Reference on private methods * and no @Activate/@Deactivate annotations then bnd generates * component.xml without namespace (1.0) */ @SuppressWarnings("unused") @Reference private void setLogService(LogService log) {} @SuppressWarnings("unused") private void unsetLogService(LogService log) {} @SuppressWarnings("unused") private void updatedLogService(LogService log) {} @Override public void run() { // TODO Auto-generated method stub } } public void testIssue347() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*issue347"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "version;minimum=1.0.0"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a, SERIALIZABLE_RUNNABLE); checkRequires(a, null, LogService.class.getName()); { Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$issue347.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.2.0"); // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$issue347", "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute("test.component.DSAnnotationTest$issue347", "scr:component/@name"); xt.assertAttribute("setLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unsetLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("updatedLogService", "scr:component/reference[1]/@updated"); } } @Component(reference = { @Reference(name = "log", service = LogService.class, cardinality = ReferenceCardinality.AT_LEAST_ONE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, target = "(service.id=1)"), @Reference(name = "logField", service = LogService.class, cardinality = ReferenceCardinality.AT_LEAST_ONE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, target = "(service.id=1)", field = "logField", fieldOption = FieldOption.REPLACE), @Reference(name = "logMethod", service = LogService.class, cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, target = "(service.id=1)", bind = "setLogMethod", unbind = "unsetLogMethod", updated = "updatedLogMethod"), }) public static class ref_on_comp implements Serializable, Runnable { private static final long serialVersionUID = 1L; @SuppressWarnings("unused") private List<LogService> logField; protected void setLogMethod(LogService logService) {}; protected void updatedLogMethod(LogService logService) {}; protected void unsetLogMethod(LogService logService) {} @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Override public void run() {} } public void testReferenceInComponent() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*ref_on_comp"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a, SERIALIZABLE_RUNNABLE); checkRequires(a, "1.3.0", LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$ref_on_comp.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$ref_on_comp", "scr:component/implementation/@class"); xt.assertAttribute("log", "scr:component/reference[1]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[1]/@interface"); xt.assertAttribute("1..n", "scr:component/reference[1]/@cardinality"); xt.assertAttribute("logField", "scr:component/reference[2]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[2]/@interface"); xt.assertAttribute("1..n", "scr:component/reference[2]/@cardinality"); xt.assertAttribute("replace", "scr:component/reference[2]/@field-option"); // TODO field-component-type xt.assertAttribute("logMethod", "scr:component/reference[3]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[3]/@interface"); xt.assertAttribute("1..1", "scr:component/reference[3]/@cardinality"); xt.assertAttribute("setLogMethod", "scr:component/reference[3]/@bind"); xt.assertAttribute("unsetLogMethod", "scr:component/reference[3]/@unbind"); xt.assertAttribute("updatedLogMethod", "scr:component/reference[3]/@updated"); } public @interface NoDefaults { String string(); } /** * Check that a DS 1.3 activate method causes a DS 1.3 namespace */ @Component() public static class DS13_activate_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") NoDefaults anno) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference(service = LogService.class) void setLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void unsetLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void updatedLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } @Override public void run() { // TODO Auto-generated method stub } } /** * Check that a DS 1.3 deactivate method causes a DS 1.3 namespace */ @Component() public static class DS13_deactivate_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") NoDefaults anno) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference(service = LogService.class) void setLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void unsetLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void updatedLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } @Override public void run() { // TODO Auto-generated method stub } } /** * Check that a DS 1.3 modified method causes a DS 1.3 namespace */ @Component() public static class DS13_modified_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") NoDefaults anno) {} @Reference(service = LogService.class) void setLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void unsetLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void updatedLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } @Override public void run() { // TODO Auto-generated method stub } } /** * Check that a DS 1.3 bind method causes a DS 1.3 namespace */ @Component() public static class DS13_ref_bind_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference(service = LogService.class) void setLogService(@SuppressWarnings("unused") Map<String,Object> map) { } void unsetLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void updatedLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } @Override public void run() { // TODO Auto-generated method stub } } /** * Check that a DS 1.3 unbind method causes a DS 1.3 namespace */ @Component() public static class DS13_ref_unbind_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference(service = LogService.class) void setLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void unsetLogService(@SuppressWarnings("unused") Map<String,Object> map) { } void updatedLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } @Override public void run() { // TODO Auto-generated method stub } } /** * Check that a DS 1.3 updated method causes a DS 1.3 namespace */ @Component() public static class DS13_ref_updated_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference(service = LogService.class) void setLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void unsetLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void updatedLogService(@SuppressWarnings("unused") Map<String,Object> map) { } @Override public void run() { // TODO Auto-generated method stub } } /** * Check that a DS 1.3 prototype scope causes a DS 1.3 namespace */ @Component(scope = ServiceScope.PROTOTYPE) public static class DS13_scope_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference(service = LogService.class) void setLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void unsetLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void updatedLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } @Override public void run() { // TODO Auto-generated method stub } } /** * Check that multiple configuration pids causes a DS 1.3 namespace */ @Component(configurationPid = { "pid1", "pid2" }) public static class DS13_pids_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference(service = LogService.class) void setLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void unsetLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void updatedLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } @Override public void run() { // TODO Auto-generated method stub } } /** * Check that '$' placeholder is translated to component name and causes a * DS 1.3 namespace */ @Component(configurationPid = { "$", "pid2" }) public static class DS13_dollar_pids_basic implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Reference(service = LogService.class) void setLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void unsetLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } void updatedLogService(@SuppressWarnings("unused") ServiceReference<LogService> sr) { } @Override public void run() { // TODO Auto-generated method stub } } public void testBasic13() throws Exception { Jar jar = setupBasic13(null, LogService.class.getName(), SERIALIZABLE_RUNNABLE); // Test 1.3 signature methods give 1.3 namespace checkDS13(jar, "test.component.DSAnnotationTest$DS13_activate_basic", "", ""); checkDS13(jar, "test.component.DSAnnotationTest$DS13_deactivate_basic", "", ""); checkDS13(jar, "test.component.DSAnnotationTest$DS13_modified_basic", "", ""); checkDS13(jar, "test.component.DSAnnotationTest$DS13_ref_bind_basic", "", ""); checkDS13(jar, "test.component.DSAnnotationTest$DS13_ref_unbind_basic", "", ""); checkDS13(jar, "test.component.DSAnnotationTest$DS13_ref_updated_basic", "", ""); checkDS13(jar, "test.component.DSAnnotationTest$DS13_scope_basic", "", "prototype"); checkDS13(jar, "test.component.DSAnnotationTest$DS13_pids_basic", "pid1 pid2", ""); checkDS13(jar, "test.component.DSAnnotationTest$DS13_dollar_pids_basic", "test.component.DSAnnotationTest$DS13_dollar_pids_basic pid2", ""); // suppress cap/req setupBasic13("nocapabilities", LogService.class.getName()); setupBasic13("norequirements", null, SERIALIZABLE_RUNNABLE); setupBasic13("nocapabilities,norequirements", null); } private Jar setupBasic13(String options, String requires, String... provides) throws IOException, Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$DS13_*"); if (options != null) { b.setProperty(Constants.DSANNOTATIONS_OPTIONS, options); } b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); if (provides == null || provides.length == 0) { checkProvides(a); } else { checkProvides(a, provides); } if (requires == null) { checkRequires(a, "1.3.0"); } else { checkRequires(a, "1.3.0", requires); } return jar; } private void checkDS13(Jar jar, String name, String pids, String scope) throws Exception, XPathExpressionException { Resource r = jar.getResource("OSGI-INF/" + name + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); // Test the defaults xt.assertAttribute(name, "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute(name, "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute(scope, "scr:component/service/@scope"); xt.assertAttribute(pids, "scr:component/@configuration-pid"); xt.assertAttribute("activate", "scr:component/@activate"); xt.assertAttribute("deactivate", "scr:component/@deactivate"); xt.assertAttribute("modified", "scr:component/@modified"); xt.assertAttribute("java.io.Serializable", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "scr:component/service/provide[2]/@interface"); xt.assertAttribute("0", "count(scr:component/properties)"); xt.assertAttribute("0", "count(scr:component/property)"); xt.assertAttribute("LogService", "scr:component/reference[1]/@name"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("setLogService", "scr:component/reference[1]/@bind"); xt.assertAttribute("unsetLogService", "scr:component/reference[1]/@unbind"); xt.assertAttribute("updatedLogService", "scr:component/reference[1]/@updated"); xt.assertAttribute("", "scr:component/reference[1]/@cardinality"); xt.assertAttribute("", "scr:component/reference[1]/@policy"); xt.assertAttribute("", "scr:component/reference[1]/@target"); xt.assertAttribute("", "scr:component/reference[1]/@policy-option"); } public void testNoHeaderDups() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$DS13_*"); b.setProperty("Private-Package", "test.component"); b.setProperty("Provide-Capability", "osgi.service;objectClass:List<String>=\"java.io.Serializable,java.lang.Runnable\""); b.setProperty("Require-Capability", "osgi.service;filter:=\"(objectClass=org.osgi.service.log.LogService)\";effective:=active"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a, SERIALIZABLE_RUNNABLE); checkRequires(a, "1.3.0", LogService.class.getName()); } public enum Foo { A, B } public @interface ConfigTypes { String myString() default "foo"; String[] myStringArray() default { "foo", "bar" }; String[] mySingleStringArray() default "baz"; int myInt() default 1; int[] myIntArray() default { 2, 3 }; int[] mySingleIntArray() default 4; Class< ? > myClass() default ConfigTypes.class; Class< ? >[] myClassArray() default { ConfigTypes.class, ConfigTypes.class }; Class< ? >[] mySingleClassArray() default ConfigTypes.class; Foo myEnum() default Foo.A; Foo[] myEnumArray() default { Foo.A, Foo.B }; Foo[] mySingleEnumArray() default Foo.B; float myFloat() default 1.0f; char myChar() default 'a'; byte myByte() default 2; short myShort() default 298; double myDouble() default 2.1D; long myLong() default 9876543210L; } @Component() public static class DS13anno_configTypes_activate implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigTypes config1) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Override public void run() { // TODO Auto-generated method stub } } @Component() public static class DS13anno_configTypes_modified implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigTypes config1) {} @Override public void run() { // TODO Auto-generated method stub } } @Component() public static class DS13anno_configTypes_deactivate implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigTypes config1) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Override public void run() { // TODO Auto-generated method stub } } public void testAnnoConfig13() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$DS13anno_*"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a, SERIALIZABLE_RUNNABLE); checkRequires(a, "1.3.0"); // // Test 1.3 signature methods give 1.3 namespace checkDS13Anno(jar, DS13anno_configTypes_activate.class.getName(), ""); checkDS13Anno(jar, DS13anno_configTypes_deactivate.class.getName(), ""); checkDS13Anno(jar, DS13anno_configTypes_modified.class.getName(), ""); } private void checkDS13Anno(Jar jar, String name, String pids) throws Exception, XPathExpressionException { Resource r = jar.getResource("OSGI-INF/" + name + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); // Test the defaults xt.assertAttribute(name, "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute(name, "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute("", "scr:component/service/@scope"); xt.assertAttribute(pids, "scr:component/@configuration-pid"); xt.assertAttribute("activate", "scr:component/@activate"); xt.assertAttribute("deactivate", "scr:component/@deactivate"); xt.assertAttribute("modified", "scr:component/@modified"); xt.assertAttribute("java.io.Serializable", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "scr:component/service/provide[2]/@interface"); xt.assertAttribute("0", "count(scr:component/properties)"); xt.assertAttribute("18", "count(scr:component/property)"); xt.assertAttribute("foo", "scr:component/property[@name='myString']/@value"); xt.assertAttribute("String", "scr:component/property[@name='myString']/@type"); xt.assertTrimmedAttribute("foo\\nbar", "scr:component/property[@name='myStringArray']"); xt.assertAttribute("String", "scr:component/property[@name='myStringArray']/@type"); xt.assertTrimmedAttribute("baz", "scr:component/property[@name='mySingleStringArray']"); xt.assertAttribute("String", "scr:component/property[@name='mySingleStringArray']/@type"); xt.assertAttribute("1", "scr:component/property[@name='myInt']/@value"); xt.assertAttribute("Integer", "scr:component/property[@name='myInt']/@type"); xt.assertTrimmedAttribute("2\\n3", "scr:component/property[@name='myIntArray']"); xt.assertAttribute("Integer", "scr:component/property[@name='myIntArray']/@type"); xt.assertTrimmedAttribute("4", "scr:component/property[@name='mySingleIntArray']"); xt.assertAttribute("Integer", "scr:component/property[@name='mySingleIntArray']/@type"); xt.assertAttribute("test.component.DSAnnotationTest$ConfigTypes", "scr:component/property[@name='myClass']/@value"); xt.assertAttribute("String", "scr:component/property[@name='myClass']/@type"); xt.assertTrimmedAttribute( "test.component.DSAnnotationTest$ConfigTypes\\ntest.component.DSAnnotationTest$ConfigTypes", "scr:component/property[@name='myClassArray']"); xt.assertAttribute("String", "scr:component/property[@name='myClassArray']/@type"); xt.assertTrimmedAttribute("test.component.DSAnnotationTest$ConfigTypes", "scr:component/property[@name='mySingleClassArray']"); xt.assertAttribute("String", "scr:component/property[@name='mySingleClassArray']/@type"); xt.assertAttribute("A", "scr:component/property[@name='myEnum']/@value"); xt.assertAttribute("String", "scr:component/property[@name='myEnum']/@type"); xt.assertTrimmedAttribute("A\\nB", "scr:component/property[@name='myEnumArray']"); xt.assertAttribute("String", "scr:component/property[@name='myEnumArray']/@type"); xt.assertTrimmedAttribute("B", "scr:component/property[@name='mySingleEnumArray']"); xt.assertAttribute("String", "scr:component/property[@name='mySingleEnumArray']/@type"); xt.assertAttribute("1.0", "scr:component/property[@name='myFloat']/@value"); xt.assertAttribute("Float", "scr:component/property[@name='myFloat']/@type"); xt.assertAttribute("97", "scr:component/property[@name='myChar']/@value"); xt.assertAttribute("Character", "scr:component/property[@name='myChar']/@type"); xt.assertAttribute("2", "scr:component/property[@name='myByte']/@value"); xt.assertAttribute("Byte", "scr:component/property[@name='myByte']/@type"); xt.assertAttribute("298", "scr:component/property[@name='myShort']/@value"); xt.assertAttribute("Short", "scr:component/property[@name='myShort']/@type"); xt.assertAttribute("9876543210", "scr:component/property[@name='myLong']/@value"); xt.assertAttribute("Long", "scr:component/property[@name='myLong']/@type"); xt.assertAttribute("2.1", "scr:component/property[@name='myDouble']/@value"); xt.assertAttribute("Double", "scr:component/property[@name='myDouble']/@type"); } public @interface ConfigNames { String myString1() default "foo"; String my$String2() default "foo"; String my$$String3() default "foo"; String my_String4() default "foo"; String my__String5() default "foo"; String my$$__String6() default "foo"; } @Component() public static class DS13annoNames_config implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigNames configNames) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Override public void run() {} } public void testAnnoConfigNames13() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$DS13annoNames_config*"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a, SERIALIZABLE_RUNNABLE); checkRequires(a, "1.3.0"); checkDS13AnnoConfigNames(jar, DS13annoNames_config.class.getName()); } private void checkDS13AnnoConfigNames(Jar jar, String name) throws Exception, XPathExpressionException { Resource r = jar.getResource("OSGI-INF/" + name + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); // Test the defaults xt.assertAttribute(name, "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute(name, "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute("", "scr:component/service/@scope"); xt.assertAttribute("", "scr:component/@configuration-pid"); xt.assertAttribute("activate", "scr:component/@activate"); xt.assertAttribute("deactivate", "scr:component/@deactivate"); xt.assertAttribute("modified", "scr:component/@modified"); xt.assertAttribute("java.io.Serializable", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "scr:component/service/provide[2]/@interface"); xt.assertAttribute("6", "count(scr:component/property)"); xt.assertAttribute("foo", "scr:component/property[@name='myString1']/@value"); xt.assertAttribute("String", "scr:component/property[@name='myString1']/@type"); xt.assertAttribute("foo", "scr:component/property[@name='myString2']/@value"); xt.assertAttribute("String", "scr:component/property[@name='myString2']/@type"); xt.assertAttribute("foo", "scr:component/property[@name='my$String3']/@value"); xt.assertAttribute("String", "scr:component/property[@name='my$String3']/@type"); xt.assertAttribute("foo", "scr:component/property[@name='my.String4']/@value"); xt.assertAttribute("String", "scr:component/property[@name='my.String4']/@type"); xt.assertAttribute("foo", "scr:component/property[@name='my_String5']/@value"); xt.assertAttribute("String", "scr:component/property[@name='my_String5']/@type"); xt.assertAttribute("foo", "scr:component/property[@name='my$_String6']/@value"); xt.assertAttribute("String", "scr:component/property[@name='my$_String6']/@type"); } public @interface ConfigNames14 { String PREFIX_ = "test."; String my$_$String7() default "foo"; String value() default "foo"; } @Component() public static class DS14annoNames_config implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigNames14 configNames) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Override public void run() {} } public void testAnnoConfigNames14() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$DS14annoNames_config*"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a, SERIALIZABLE_RUNNABLE); checkRequires(a, "1.4.0"); checkDS14AnnoConfigNames(jar, DS14annoNames_config.class.getName()); } private void checkDS14AnnoConfigNames(Jar jar, String name) throws Exception, XPathExpressionException { Resource r = jar.getResource("OSGI-INF/" + name + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.4.0"); // Test the defaults xt.assertAttribute(name, "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute(name, "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute("", "scr:component/service/@scope"); xt.assertAttribute("", "scr:component/@configuration-pid"); xt.assertAttribute("activate", "scr:component/@activate"); xt.assertAttribute("deactivate", "scr:component/@deactivate"); xt.assertAttribute("modified", "scr:component/@modified"); xt.assertAttribute("java.io.Serializable", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "scr:component/service/provide[2]/@interface"); xt.assertAttribute("2", "count(scr:component/property)"); xt.assertAttribute("foo", "scr:component/property[@name='test.my-String7']/@value"); xt.assertAttribute("String", "scr:component/property[@name='test.my-String7']/@type"); xt.assertAttribute("foo", "scr:component/property[@name='test.config.names14']/@value"); xt.assertAttribute("String", "scr:component/property[@name='test.config.names14']/@type"); } public @interface ConfigA { String a() default "a"; String one() default "a"; String two() default "a"; } public @interface ConfigB { String b() default "b"; String one() default "b"; } @Component(property = { "two:String=c" }) public static class DS13annoOverride_a_a implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigA a, @SuppressWarnings("unused") ConfigB b) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Override public void run() {} } @Component(property = { "two:String=c" }) public static class DS13annoOverride_a_d implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigA a) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigB b) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Override public void run() {} } @Component(property = { "two:String=c" }) public static class DS13annoOverride_a_m implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigA a) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigB b) {} @Override public void run() {} } @Component(property = { "two:String=c" }) public static class DS13annoOverride_d_m implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc) {} @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigA a) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigB b) {} @Override public void run() {} } public void testAnnoConfigOverrides13() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$DS13annoOverride_*"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a, SERIALIZABLE_RUNNABLE); checkRequires(a, "1.3.0"); checkDS13AnnoOverride(jar, DS13annoOverride_a_a.class.getName()); checkDS13AnnoOverride(jar, DS13annoOverride_a_d.class.getName()); checkDS13AnnoOverride(jar, DS13annoOverride_a_m.class.getName()); checkDS13AnnoOverride(jar, DS13annoOverride_d_m.class.getName()); } private void checkDS13AnnoOverride(Jar jar, String name) throws Exception, XPathExpressionException { Resource r = jar.getResource("OSGI-INF/" + name + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); // Test the defaults xt.assertAttribute(name, "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute(name, "scr:component/@name"); xt.assertAttribute("", "scr:component/@configuration-policy"); xt.assertAttribute("", "scr:component/@immediate"); xt.assertAttribute("", "scr:component/@enabled"); xt.assertAttribute("", "scr:component/@factory"); xt.assertAttribute("", "scr:component/service/@scope"); xt.assertAttribute("", "scr:component/@configuration-pid"); xt.assertAttribute("activate", "scr:component/@activate"); xt.assertAttribute("deactivate", "scr:component/@deactivate"); xt.assertAttribute("modified", "scr:component/@modified"); xt.assertAttribute("java.io.Serializable", "scr:component/service/provide[1]/@interface"); xt.assertAttribute("java.lang.Runnable", "scr:component/service/provide[2]/@interface"); xt.assertAttribute("4", "count(scr:component/property)"); xt.assertAttribute("a", "scr:component/property[@name='a']/@value"); xt.assertAttribute("String", "scr:component/property[@name='a']/@type"); xt.assertAttribute("b", "scr:component/property[@name='b']/@value"); xt.assertAttribute("String", "scr:component/property[@name='b']/@type"); xt.assertAttribute("b", "scr:component/property[@name='one']/@value"); xt.assertAttribute("String", "scr:component/property[@name='one']/@type"); xt.assertAttribute("c", "scr:component/property[@name='two']/@value"); xt.assertAttribute("String", "scr:component/property[@name='two']/@type"); } @Component public static class TestFieldInjection { @Reference private LogService serviceField; @Reference private ServiceReference<LogService> srField; @Reference private ComponentServiceObjects<LogService> soField; @Reference(service = LogService.class) private Map<String,Object> propsField; @Reference private Map.Entry<Map<String,Object>,LogService> tupleField; @Reference private Map.Entry<Map<String, ? >,LogService> tupleField2; @Reference private Map.Entry<Map<String, ? extends Object>,LogService> tupleField3; } public void testFieldInjection() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*TestFieldInjection"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a); checkRequires(a, "1.3.0", LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/" + TestFieldInjection.class.getName() + ".xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); xt.assertNamespace("http://www.osgi.org/xmlns/scr/v1.3.0"); xt.assertAttribute("propsField", "scr:component/reference[1]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[1]/@interface"); xt.assertAttribute("propsField", "scr:component/reference[1]/@field"); xt.assertAttribute("serviceField", "scr:component/reference[2]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[2]/@interface"); xt.assertAttribute("serviceField", "scr:component/reference[2]/@field"); xt.assertAttribute("soField", "scr:component/reference[3]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[3]/@interface"); xt.assertAttribute("soField", "scr:component/reference[3]/@field"); xt.assertAttribute("srField", "scr:component/reference[4]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[4]/@interface"); xt.assertAttribute("srField", "scr:component/reference[4]/@field"); xt.assertAttribute("tupleField", "scr:component/reference[5]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[5]/@interface"); xt.assertAttribute("tupleField", "scr:component/reference[5]/@field"); xt.assertAttribute("tupleField2", "scr:component/reference[6]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[6]/@interface"); xt.assertAttribute("tupleField2", "scr:component/reference[6]/@field"); xt.assertAttribute("tupleField3", "scr:component/reference[7]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[7]/@interface"); xt.assertAttribute("tupleField3", "scr:component/reference[7]/@field"); } @Component public static class TestFieldCollectionType implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Reference // (service = LogService.class) private Collection<ServiceReference<LogService>> srField; @Reference // (service=LogService.class) private Collection<ComponentServiceObjects<LogService>> soField; @Reference(service = LogService.class) private Collection<Map<String,Object>> propsField; @Reference // (service=LogService.class) private Collection<LogService> serviceField; @Reference // (service = LogService.class) private Collection<Map.Entry<Map<String,Object>,LogService>> tupleField; public void run() {} } public void testFieldCollectionType() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest*TestFieldCollectionType"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkProvides(a, SERIALIZABLE_RUNNABLE); checkRequires(a, "1.3.0", LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/" + TestFieldCollectionType.class.getName() + ".xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); xt.assertNamespace("http://www.osgi.org/xmlns/scr/v1.3.0"); xt.assertAttribute("propsField", "scr:component/reference[1]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[1]/@interface"); xt.assertAttribute("propsField", "scr:component/reference[1]/@field"); xt.assertAttribute("properties", "scr:component/reference[1]/@field-collection-type"); xt.assertAttribute("serviceField", "scr:component/reference[2]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[2]/@interface"); xt.assertAttribute("serviceField", "scr:component/reference[2]/@field"); xt.assertAttribute("service", "scr:component/reference[2]/@field-collection-type"); xt.assertAttribute("soField", "scr:component/reference[3]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[3]/@interface"); xt.assertAttribute("soField", "scr:component/reference[3]/@field"); xt.assertAttribute("serviceobjects", "scr:component/reference[3]/@field-collection-type"); xt.assertAttribute("srField", "scr:component/reference[4]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[4]/@interface"); xt.assertAttribute("srField", "scr:component/reference[4]/@field"); xt.assertAttribute("reference", "scr:component/reference[4]/@field-collection-type"); xt.assertAttribute("tupleField", "scr:component/reference[5]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[5]/@interface"); xt.assertAttribute("tupleField", "scr:component/reference[5]/@field"); xt.assertAttribute("tuple", "scr:component/reference[5]/@field-collection-type"); } private void checkProvides(Attributes a, String[]... objectClass) { String p = a.getValue(Constants.PROVIDE_CAPABILITY); System.err.println(Constants.PROVIDE_CAPABILITY + ":" + p); Parameters header = new Parameters(p); List<Attrs> attrs = getAll(header, "osgi.service"); assertEquals(objectClass.length, attrs.size()); for (String[] o : objectClass) { boolean found = false; for (Attrs at : attrs) { if (Arrays.asList(o).equals(at.getTyped("objectClass"))) { assertEquals(1, at.size()); found = true; } } assertTrue("objectClass not found: " + o, found); } } private void checkRequires(Attributes a, String extender, String... objectClass) { String p = a.getValue(Constants.REQUIRE_CAPABILITY); System.err.println(Constants.REQUIRE_CAPABILITY + ":" + p); Parameters header = new Parameters(p); List<Attrs> attrs = getAll(header, "osgi.service"); assertEquals("osgi.service attributes: " + attrs, objectClass.length, attrs.size()); for (String o : objectClass) { boolean found = false; for (Attrs at : attrs) { if (("(objectClass=" + o + ")").equals(at.get("filter:"))) { assertEquals("no effective:=\"active\"", "active", at.get("effective:")); found = true; } } assertTrue("objectClass not found: " + o, found); } if (extender != null) { Attrs attr = header.get("osgi.extender"); assertNotNull(attr); assertEquals("(&(osgi.extender=osgi.component)(version>=" + extender + ")(!(version>=2.0.0)))", attr.get("filter:")); } } private Attributes getAttr(Jar jar) throws Exception { Manifest m = jar.getManifest(); return m.getMainAttributes(); } private List<Attrs> getAll(Parameters p, String key) { List<Attrs> l = new ArrayList<Attrs>(); for (; p.containsKey(key); key += aQute.bnd.osgi.Constants.DUPLICATE_MARKER) { l.add(p.get(key)); } return l; } @Component public static class DesignateNone { @Activate void activate(Map<String,Object> props) {} } @ObjectClassDefinition @interface config {} @Component @Designate(ocd = config.class) public static class DesignateSingleton { @Activate void activate(Map<String,Object> props) {} } @Component @Designate(ocd = config.class, factory = true) public static class DesignateFactory { @Activate void activate(Map<String,Object> props) {} } @Component(configurationPolicy = ConfigurationPolicy.REQUIRE) public static class DesignateNoneRequire { @Activate void activate(Map<String,Object> props) {} } @Component(configurationPolicy = ConfigurationPolicy.REQUIRE) @Designate(ocd = config.class) public static class DesignateSingletonRequire { @Activate void activate(Map<String,Object> props) {} } @Component(configurationPolicy = ConfigurationPolicy.OPTIONAL) @Designate(ocd = config.class, factory = true) public static class DesignateFactoryOptional { @Activate void activate(Map<String,Object> props) {} } public void testDesignate() throws Exception { Builder b = new Builder(); b.setProperty("-dsannotations", "test.component.DSAnnotationTest*Designate*"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "version;minimum=1.0.0"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); checkConfigurationPolicy(jar, DesignateNone.class, ""); checkConfigurationPolicy(jar, DesignateSingleton.class, ""); checkConfigurationPolicy(jar, DesignateFactory.class, "require"); checkConfigurationPolicy(jar, DesignateNoneRequire.class, "require"); checkConfigurationPolicy(jar, DesignateSingletonRequire.class, "require"); checkConfigurationPolicy(jar, DesignateFactoryOptional.class, "optional"); } void checkConfigurationPolicy(Jar jar, Class< ? > clazz, String option) throws Exception, XPathExpressionException { Resource r = jar.getResource("OSGI-INF/" + clazz.getName() + ".xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.1.0"); xt.assertNamespace("http://www.osgi.org/xmlns/scr/v1.1.0"); xt.assertAttribute(option, "scr:component/@configuration-policy"); } @XMLAttribute(namespace = "org.foo.extensions.v1", prefix = "foo", embedIn = "*") @Retention(RetentionPolicy.CLASS) @Target({ ElementType.TYPE }) @interface TestExtensions { boolean booleanAttr() default true; String stringAttr(); Foo fooAttr(); } @XMLAttribute(namespace = "org.foo.extensions.v1", prefix = "foo", embedIn = "http://www.osgi.org/xmlns/scr/*") @Retention(RetentionPolicy.CLASS) @Target({ ElementType.FIELD, ElementType.METHOD }) @interface TestRefExtensions { boolean booleanAttr2() default true; String stringAttr2(); Foo fooAttr2(); } @TestExtensions(stringAttr = "bar", fooAttr = Foo.A) @Component public static class ExtraAttributes implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigA a, @SuppressWarnings("unused") ConfigB b) {} @TestRefExtensions(stringAttr2 = "ignore", fooAttr2 = Foo.A) @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @TestRefExtensions(stringAttr2 = "baz", fooAttr2 = Foo.B, booleanAttr2 = false) @Reference protected LogService lsa; @TestRefExtensions(stringAttr2 = "bax", fooAttr2 = Foo.A) @Reference protected void setLogServiceB(LogService ls) {}; @Reference protected void setLogServicec(LogService ls) {}; @TestRefExtensions(stringAttr2 = "ignore", fooAttr2 = Foo.A) @Override public void run() {} } public void testExtraAttributes() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$ExtraAttributes*"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); String name = ExtraAttributes.class.getName(); Resource r = jar.getResource("OSGI-INF/" + name + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0", "foo", "org.foo.extensions.v1"); // Test the defaults xt.assertAttribute(name, "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute(name, "scr:component/@name"); xt.assertCount(7, "scr:component/@*"); xt.assertAttribute("bar", "scr:component/@foo:stringAttr"); xt.assertAttribute("A", "scr:component/@foo:fooAttr"); xt.assertAttribute("true", "scr:component/@foo:booleanAttr"); xt.assertCount(3, "scr:component/reference"); xt.assertCount(6, "scr:component/reference[1]/@*"); xt.assertAttribute("bax", "scr:component/reference[1]/@foo:stringAttr2"); xt.assertAttribute("A", "scr:component/reference[1]/@foo:fooAttr2"); xt.assertAttribute("true", "scr:component/reference[1]/@foo:booleanAttr2"); xt.assertCount(3, "scr:component/reference[2]/@*"); xt.assertCount(6, "scr:component/reference[3]/@*"); xt.assertAttribute("baz", "scr:component/reference[3]/@foo:stringAttr2"); xt.assertAttribute("B", "scr:component/reference[3]/@foo:fooAttr2"); xt.assertAttribute("false", "scr:component/reference[3]/@foo:booleanAttr2"); } @TestExtensions(stringAttr = "bar", fooAttr = Foo.A) @Component public static class ExtraAttributes10 { @Activate protected void activate(@SuppressWarnings("unused") ComponentContext cc) {} @TestRefExtensions(stringAttr2 = "ignore", fooAttr2 = Foo.A) @Deactivate protected void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} } /** * test that an extension attribute will ensure at least a 1.1 namespace, so * the extension namespace is meaningful * * @throws Exception */ public void testExtraAttributes10() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$ExtraAttributes*"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "version;minimum=1.0.0"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); String name = ExtraAttributes10.class.getName(); Resource r = jar.getResource("OSGI-INF/" + name + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.1.0", "foo", "org.foo.extensions.v1"); // This wll check that the spec namespace is 1.1 xt.assertAttribute(name, "scr:component/implementation/@class"); } @XMLAttribute(namespace = "org.foo.extensions.v2", prefix = "foo") @Retention(RetentionPolicy.CLASS) @Target({ ElementType.TYPE }) @interface TestExtensions3 { boolean booleanAttr3() default false; String stringAttr3(); Foo fooAttr3(); } @TestExtensions(stringAttr = "bar", fooAttr = Foo.A) @TestExtensions3(stringAttr3 = "bar3", fooAttr3 = Foo.B) @Component public static class PrefixCollisionExtraAttributes implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigA a, @SuppressWarnings("unused") ConfigB b) {} @TestRefExtensions(stringAttr2 = "ignore", fooAttr2 = Foo.A) @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @TestRefExtensions(stringAttr2 = "baz", fooAttr2 = Foo.B, booleanAttr2 = false) @Reference protected LogService lsa; @TestRefExtensions(stringAttr2 = "bax", fooAttr2 = Foo.A) @Reference protected void setLogServiceB(LogService ls) {}; @Reference protected void setLogServicec(LogService ls) {}; @TestRefExtensions(stringAttr2 = "ignore", fooAttr2 = Foo.A) @Override public void run() {} } public void testPrefixCollisionExtraAttributes() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$PrefixCollisionExtraAttributes*"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); String name = PrefixCollisionExtraAttributes.class.getName(); Resource r = jar.getResource("OSGI-INF/" + name + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0", "foo", "org.foo.extensions.v1", "foo1", "org.foo.extensions.v2"); // Test the defaults xt.assertAttribute(name, "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute(name, "scr:component/@name"); xt.assertCount(10, "scr:component/@*"); xt.assertAttribute("bar", "scr:component/@foo:stringAttr"); xt.assertAttribute("A", "scr:component/@foo:fooAttr"); xt.assertAttribute("true", "scr:component/@foo:booleanAttr"); xt.assertAttribute("bar3", "scr:component/@foo1:stringAttr3"); xt.assertAttribute("B", "scr:component/@foo1:fooAttr3"); xt.assertAttribute("false", "scr:component/@foo1:booleanAttr3"); xt.assertCount(3, "scr:component/reference"); xt.assertCount(6, "scr:component/reference[1]/@*"); xt.assertAttribute("bax", "scr:component/reference[1]/@foo:stringAttr2"); xt.assertAttribute("A", "scr:component/reference[1]/@foo:fooAttr2"); xt.assertAttribute("true", "scr:component/reference[1]/@foo:booleanAttr2"); xt.assertCount(3, "scr:component/reference[2]/@*"); xt.assertCount(6, "scr:component/reference[3]/@*"); xt.assertAttribute("baz", "scr:component/reference[3]/@foo:stringAttr2"); xt.assertAttribute("B", "scr:component/reference[3]/@foo:fooAttr2"); xt.assertAttribute("false", "scr:component/reference[3]/@foo:booleanAttr2"); } @XMLAttribute(namespace = "org.foo.extensions.v4") @Retention(RetentionPolicy.CLASS) @Target({ ElementType.TYPE }) @interface TestExtensions4 { boolean booleanAttr4() default true; String stringAttr4(); Foo fooAttr4(); } @XMLAttribute(namespace = "org.foo.extensions.v5") @Retention(RetentionPolicy.CLASS) @Target({ ElementType.TYPE }) @interface TestExtensions5 { boolean booleanAttr5() default true; String stringAttr5(); Foo fooAttr5(); } @TestExtensions4(stringAttr4 = "bar", fooAttr4 = Foo.A) @TestExtensions5(stringAttr5 = "bar3", fooAttr5 = Foo.B) @Component public static class DefaultPrefixCollisionExtraAttributes implements Serializable, Runnable { private static final long serialVersionUID = 1L; @Activate void activate(@SuppressWarnings("unused") ComponentContext cc, @SuppressWarnings("unused") ConfigA a, @SuppressWarnings("unused") ConfigB b) {} @TestRefExtensions(stringAttr2 = "ignore", fooAttr2 = Foo.A) @Deactivate void deactivate(@SuppressWarnings("unused") ComponentContext cc) {} @Modified void modified(@SuppressWarnings("unused") ComponentContext cc) {} @Override public void run() {} } public void testPrefixCollisionExtraAttributesDefaultPrefix() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$DefaultPrefixCollisionExtraAttributes*"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); String name = DefaultPrefixCollisionExtraAttributes.class.getName(); Resource r = jar.getResource("OSGI-INF/" + name + ".xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0", "ns", "org.foo.extensions.v4", "ns1", "org.foo.extensions.v5"); // Test the defaults xt.assertAttribute(name, "scr:component/implementation/@class"); // Default must be the implementation class xt.assertAttribute(name, "scr:component/@name"); xt.assertCount(10, "scr:component/@*"); xt.assertAttribute("bar", "scr:component/@ns:stringAttr4"); xt.assertAttribute("A", "scr:component/@ns:fooAttr4"); xt.assertAttribute("true", "scr:component/@ns:booleanAttr4"); xt.assertAttribute("bar3", "scr:component/@ns1:stringAttr5"); xt.assertAttribute("B", "scr:component/@ns1:fooAttr5"); xt.assertAttribute("true", "scr:component/@ns1:booleanAttr5"); } @Component(name = "mixed-std-bnd") static class MixedStdBnd { @aQute.bnd.annotation.component.Reference protected void setLog(@SuppressWarnings("unused") LogService log) {} @aQute.bnd.annotation.component.Activate void start() {} @aQute.bnd.annotation.component.Modified void update(Map<String,Object> map) {} @aQute.bnd.annotation.component.Deactivate void stop() {} } public void testMixedStandardBnd() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.DSAnnotationTest$MixedStdBnd"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar build = b.build(); System.err.println(b.getErrors()); System.err.println(b.getWarnings()); assertEquals(4, b.getErrors().size()); List<String> errors = new ArrayList<String>(b.getErrors()); Collections.sort(errors); assertEquals( "The DS component mixed-std-bnd uses standard annotations to declare it as a component, but also uses the bnd DS annotation: aQute.bnd.annotation.component.Activate on method start with signature ()V. It is an error to mix these two types of annotations", errors.get(0)); assertEquals( "The DS component mixed-std-bnd uses standard annotations to declare it as a component, but also uses the bnd DS annotation: aQute.bnd.annotation.component.Deactivate on method stop with signature ()V. It is an error to mix these two types of annotations", errors.get(1)); assertEquals( "The DS component mixed-std-bnd uses standard annotations to declare it as a component, but also uses the bnd DS annotation: aQute.bnd.annotation.component.Modified on method update with signature (Ljava/util/Map;)V. It is an error to mix these two types of annotations", errors.get(2)); assertEquals( "The DS component mixed-std-bnd uses standard annotations to declare it as a component, but also uses the bnd DS annotation: aQute.bnd.annotation.component.Reference on method setLog with signature (Lorg/osgi/service/log/LogService;)V. It is an error to mix these two types of annotations", errors.get(3)); assertEquals(0, b.getWarnings().size()); } @Component static class VolatileField { @Reference private volatile LogService log1; @Reference private LogService log2; } public void testVolatileFieldDynamic() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*VolatileField"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkRequires(a, "1.3.0", LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$VolatileField.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$VolatileField", "scr:component/implementation/@class"); xt.assertAttribute("log1", "scr:component/reference[1]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[1]/@interface"); xt.assertAttribute("dynamic", "scr:component/reference[1]/@policy"); xt.assertAttribute("log2", "scr:component/reference[2]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[2]/@interface"); xt.assertNoAttribute("scr:component/reference[2]/@policy"); } @Component static class FinalDynamicCollectionField { @Reference(policy = ReferencePolicy.DYNAMIC) private final List<LogService> logs1 = new CopyOnWriteArrayList<LogService>(); @Reference private final List<LogService> logs2 = new CopyOnWriteArrayList<LogService>(); } public void testFinalDynamicCollectionField() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*FinalDynamicCollectionField"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkRequires(a, "1.3.0", LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$FinalDynamicCollectionField.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$FinalDynamicCollectionField", "scr:component/implementation/@class"); xt.assertAttribute("logs1", "scr:component/reference[1]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[1]/@interface"); xt.assertAttribute("dynamic", "scr:component/reference[1]/@policy"); xt.assertAttribute("update", "scr:component/reference[1]/@field-option"); xt.assertAttribute("logs2", "scr:component/reference[2]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[2]/@interface"); xt.assertNoAttribute("scr:component/reference[2]/@policy"); xt.assertNoAttribute("scr:component/reference[2]/@field-option"); } @Component static class FieldCardinality { @Reference private List<LogService> log1; @Reference private volatile Collection<LogService> log2; @Reference private LogService log3; @Reference private volatile LogService log4; @Reference(policy = ReferencePolicy.DYNAMIC) private final List<LogService> log5 = new CopyOnWriteArrayList<>(); } public void testFieldCardinality() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*FieldCardinality"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b); Attributes a = getAttr(jar); checkRequires(a, "1.3.0", LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$FieldCardinality.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); // Test the defaults xt.assertAttribute("test.component.DSAnnotationTest$FieldCardinality", "scr:component/implementation/@class"); xt.assertAttribute("log1", "scr:component/reference[1]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[1]/@interface"); xt.assertAttribute("0..n", "scr:component/reference[1]/@cardinality"); xt.assertNoAttribute("scr:component/reference[1]/@policy"); xt.assertNoAttribute("scr:component/reference[1]/@field-option"); xt.assertAttribute("log2", "scr:component/reference[2]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[2]/@interface"); xt.assertAttribute("0..n", "scr:component/reference[2]/@cardinality"); xt.assertAttribute("dynamic", "scr:component/reference[2]/@policy"); xt.assertNoAttribute("scr:component/reference[2]/@field-option"); xt.assertAttribute("log3", "scr:component/reference[3]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[3]/@interface"); xt.assertNoAttribute("scr:component/reference[3]/@cardinality"); xt.assertNoAttribute("scr:component/reference[3]/@policy"); xt.assertNoAttribute("scr:component/reference[3]/@field-option"); xt.assertAttribute("log4", "scr:component/reference[4]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[4]/@interface"); xt.assertNoAttribute("scr:component/reference[4]/@cardinality"); xt.assertAttribute("dynamic", "scr:component/reference[4]/@policy"); xt.assertNoAttribute("scr:component/reference[4]/@field-option"); xt.assertAttribute("log5", "scr:component/reference[5]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[5]/@interface"); xt.assertAttribute("0..n", "scr:component/reference[5]/@cardinality"); xt.assertAttribute("dynamic", "scr:component/reference[5]/@policy"); xt.assertAttribute("update", "scr:component/reference[5]/@field-option"); } @Component static class MismatchedUnbind { @Reference void setLogService10(LogService ls) {} void updatedLogService10(FinalDynamicCollectionField notLs) {} void unsetLogService10(FinalDynamicCollectionField notLs) {} @Reference void setLogService11(LogService ls, Map<String,Object> props) {} void unsetLogService11(FinalDynamicCollectionField notLs, Map<String,Object> props) {} @Reference void setLogService13(Map<String,Object> props, LogService ls) {} void unsetLogService13(Map<String,Object> props, FinalDynamicCollectionField notLs) {} } public void testMismatchedUnbind() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*MismatchedUnbind"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b, 0, 8); Attributes a = getAttr(jar); checkRequires(a, null, LogService.class.getName()); Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$MismatchedUnbind.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); xt.assertAttribute("LogService10", "scr:component/reference[1]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[1]/@interface"); xt.assertAttribute("setLogService10", "scr:component/reference[1]/@bind"); xt.assertNoAttribute("scr:component/reference[1]/@unbind"); xt.assertNoAttribute("scr:component/reference[1]/@updated"); xt.assertAttribute("LogService11", "scr:component/reference[2]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[2]/@interface"); xt.assertAttribute("setLogService11", "scr:component/reference[2]/@bind"); xt.assertNoAttribute("scr:component/reference[2]/@unbind"); xt.assertAttribute("LogService13", "scr:component/reference[3]/@name"); xt.assertAttribute(LogService.class.getName(), "scr:component/reference[3]/@interface"); xt.assertAttribute("setLogService13", "scr:component/reference[3]/@bind"); xt.assertNoAttribute("scr:component/reference[3]/@unbind"); } @Component(service = Map.class) static class NotAMap1 {} @Component(service = HashMap.class) static class NotAMap2 {} @SuppressWarnings("serial") @Component(service = HashMap.class) static class NotAMap3 extends TreeMap<String,String> {} public void testNotImplementedService() throws Exception { checkClass(NotAMap1.class, 1); checkClass(NotAMap2.class, 1); checkClass(NotAMap3.class, 1); } @SuppressWarnings("serial") @Component(service = Map.class) static class IsAMap1 extends HashMap<String,String> {} @SuppressWarnings("serial") static class MyHashMap1<K, V> extends HashMap<K,V> {} @SuppressWarnings("serial") @Component(service = HashMap.class) static class IsAMap2 extends MyHashMap1<String,String> {} static interface MyMap<K, V> extends Map<K,V> {}; @SuppressWarnings("serial") static class MyHashMap2<K, V> extends HashMap<K,V> implements MyMap<K,V> {} @SuppressWarnings("serial") @Component(service = Map.class) static class IsAMap3 extends MyHashMap2<String,String> {} static interface Marker {} @SuppressWarnings("serial") @Component(service = Map.class) static class IsAMap3a extends MyHashMap2<String,String> implements Marker {} @Component(service = Map.class) static class IsAMap4 implements MyMap<String,String> { @Override public int size() { return 0; } @Override public boolean isEmpty() { return false; } @Override public boolean containsKey(Object key) { return false; } @Override public boolean containsValue(Object value) { return false; } @Override public String get(Object key) { return null; } @Override public String put(String key, String value) { return null; } @Override public String remove(Object key) { return null; } @Override public void putAll(Map< ? extends String, ? extends String> m) {} @Override public void clear() {} @Override public Set<String> keySet() { return null; } @Override public Collection<String> values() { return null; } @Override public Set<java.util.Map.Entry<String,String>> entrySet() { return null; } } public void testIndirectlyImplementedService() throws Exception { checkClass(IsAMap1.class, 0); checkClass(IsAMap2.class, 0); checkClass(IsAMap3.class, 0); checkClass(IsAMap3a.class, 0); checkClass(IsAMap4.class, 0); } private void checkClass(Class< ? > c, int i) throws IOException, Exception, AssertionFailedError { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, c.getName()); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b, i, 0); } public static interface GenericMarker<K> extends Marker {} @Component public static class RefType { @Reference(service = Marker.class) void setMarker1(ServiceReference< ? > ref) {} @Reference(service = Marker.class) void setMarker2(ComponentServiceObjects< ? > ref) {} @Reference void setMarker3(ServiceReference<Marker> ref) {} @Reference void setMarker4(ComponentServiceObjects<Marker> ref) {} @Reference(service = GenericMarker.class) void setMarker5(ServiceReference<Marker> ref) {} @Reference(service = GenericMarker.class) void setMarker6(ComponentServiceObjects<Marker> ref) {} @Reference void setMarker7(ServiceReference<GenericMarker< ? >> ref) {} @Reference void setMarker8(ComponentServiceObjects<GenericMarker< ? >> ref) {} @Reference void setMarker9(ServiceReference<GenericMarker<Marker>> ref) {} @Reference void setMarker10(ComponentServiceObjects<GenericMarker<Marker>> ref) {} @Reference void setMarker11(ServiceReference<GenericMarker< ? extends Marker>> ref) {} @Reference void setMarker12(ComponentServiceObjects<GenericMarker< ? super Marker>> ref) {} @Reference void setMarker13(ServiceReference< ? extends GenericMarker< ? extends Marker>> ref) {} @Reference void setMarker14(ComponentServiceObjects< ? super GenericMarker< ? super Marker>> ref) {} @Reference(service = Marker.class) void setMarker15(ComponentServiceObjects< ? super GenericMarker< ? super Marker>> ref) {} } private List<String> indices = new ArrayList<String>(); public void testReferenceType() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*RefType"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b, 0, 0); Attributes a = getAttr(jar); checkRequires(a, null, Marker.class.getName(), GenericMarker.class.getName(), Object.class.getName()); Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$RefType.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); Collection<String> indices = new TreeSet<String>(); for (int i = 1; i < 16; i++) indices.add(Integer.toString(i)); this.indices.addAll(indices); checkMarkerReference(xt, 1, Marker.class); checkMarkerReference(xt, 2, Marker.class); checkMarkerReference(xt, 3, Marker.class); checkMarkerReference(xt, 4, Marker.class); checkMarkerReference(xt, 5, GenericMarker.class); checkMarkerReference(xt, 6, GenericMarker.class); checkMarkerReference(xt, 7, GenericMarker.class); checkMarkerReference(xt, 8, GenericMarker.class); checkMarkerReference(xt, 9, GenericMarker.class); checkMarkerReference(xt, 10, GenericMarker.class); checkMarkerReference(xt, 11, GenericMarker.class); checkMarkerReference(xt, 12, GenericMarker.class); checkMarkerReference(xt, 13, GenericMarker.class); checkMarkerReference(xt, 14, Object.class); checkMarkerReference(xt, 15, Marker.class); } private void checkMarkerReference(XmlTester xt, int count, Class< ? > cl) throws XPathExpressionException { String index = Integer.toString(indices.indexOf(Integer.toString(count)) + 1); xt.assertAttribute("Marker" + count, "scr:component/reference[" + index + "]/@name"); xt.assertAttribute(cl.getName(), "scr:component/reference[" + index + "]/@interface"); xt.assertAttribute("setMarker" + count, "scr:component/reference[" + index + "]/@bind"); xt.assertNoAttribute("scr:component/reference[" + index + "]/@unbind"); xt.assertNoAttribute("scr:component/reference[" + index + "]/@updated"); } @Component(reference = @Reference(name = "LogService", service = LogService.class) ) public static class ComponentReferenceGood {} @Component(reference = @Reference(service = LogService.class) ) public static class ComponentReferenceBad {} public void testComponentReference() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*ComponentReference*"); b.setProperty(Constants.DSANNOTATIONS_OPTIONS, "version;minimum=1.0.0"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b, 1, 0); { Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$ComponentReferenceGood.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream()); xt.assertAttribute(LogService.class.getName(), "component/reference[1]/@interface"); } { Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$ComponentReferenceBad.xml"); System.err.println(Processor.join(jar.getResources().keySet(), "\n")); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream()); xt.assertCount(0, "component/reference"); } } public interface Activatable<T extends Annotation> { void activator(T config); } @Component(service = {}) public static class ActivatableComponent implements Activatable<ConfigA> { @Activate public void activator(ConfigA config) { String a = config.a(); } } /* * See https://github.com/bndtools/bnd/issues/1546. If a component class has * an annotated method for which the compiler generates a bridge method, * javac will copy the annotations onto the bridge method. Bnd must ignore * bridge methods. */ public void testBridgeMethod() throws Exception { Builder b = new Builder(); b.setProperty(Constants.DSANNOTATIONS, "test.component.*ActivatableComponent"); b.setProperty("Private-Package", "test.component"); b.addClasspath(new File("bin")); Jar jar = b.build(); assertOk(b, 0, 0); Resource r = jar.getResource("OSGI-INF/test.component.DSAnnotationTest$ActivatableComponent.xml"); assertNotNull(r); r.write(System.err); XmlTester xt = new XmlTester(r.openInputStream(), "scr", "http://www.osgi.org/xmlns/scr/v1.3.0"); xt.assertAttribute("activator", "scr:component/@activate"); } }