Sync bndlib source
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1364196 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java b/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java
index 14d6822..ae116a1 100644
--- a/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java
@@ -8,6 +8,7 @@
* compatible change to this interface requires a major update of the version of
* this package.
*/
+@Documented
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface ConsumerType {
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java b/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java
index cd48468..4389c77 100644
--- a/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java
@@ -2,6 +2,7 @@
import java.lang.annotation.*;
+@Documented
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.PACKAGE)
public @interface Export {
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java b/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java
index 183ef7b..22edcea 100644
--- a/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java
@@ -8,6 +8,7 @@
* a minor update to the package API version number. This interface is similar
* to the Eclipse @noextend and @noimplement annotations.
*/
+@Documented
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface ProviderType {
diff --git a/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java b/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java
index 4fe1c56..a90c250 100644
--- a/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java
+++ b/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java
@@ -2,6 +2,7 @@
import java.lang.annotation.*;
+@Documented
@Retention(RetentionPolicy.CLASS)
@Target({
ElementType.PACKAGE
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java b/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java
index a3763fa..1ca3af7 100644
--- a/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java
+++ b/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java
@@ -29,6 +29,7 @@
final static Pattern PROPERTY_PATTERN = Pattern
.compile("\\s*([^=\\s:]+)\\s*(?::\\s*(Boolean|Byte|Character|Short|Integer|Long|Float|Double|String)\\s*)?=(.*)");
+ public static final Version V1_0 = new Version("1.0.0"); // "1.1.0"
public static final Version V1_1 = new Version("1.1.0"); // "1.1.0"
public static final Version V1_2 = new Version("1.2.0"); // "1.1.0"
static Pattern BINDNAME = Pattern.compile("(set|add|bind)?(.*)");
@@ -247,7 +248,7 @@
if (component.implementation != null)
return;
- component.version = V1_1;
+ component.version = V1_0;
component.implementation = clazz.getClassName();
component.name = comp.name();
component.factory = comp.factory();
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java b/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java
index 1054896..b58b775 100644
--- a/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java
+++ b/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java
@@ -22,9 +22,9 @@
final static String NAMESPACE_STEM = "http://www.osgi.org/xmlns/scr";
final List<String> properties = new ArrayList<String>();
final MultiMap<String,String> property = new MultiMap<String,String>();
- final Map<String,ReferenceDef> references = new TreeMap<String,ReferenceDef>();
+ final Map<String,ReferenceDef> references = new LinkedHashMap<String,ReferenceDef>();
- Version version = AnnotationReader.V1_1;
+ Version version = AnnotationReader.V1_0;
String name;
String factory;
Boolean immediate;
@@ -72,6 +72,8 @@
} else if (servicefactory != null && servicefactory)
analyzer.warning("The servicefactory:=true directive is set but no service is provided, ignoring it");
+ if (configurationPolicy != null)
+ version = ReferenceDef.max(version, AnnotationReader.V1_1);
if (configurationPid != null)
version = ReferenceDef.max(version, AnnotationReader.V1_2);
@@ -108,6 +110,12 @@
propertyTags.add(property);
}
}
+
+ void sortReferences() {
+ Map<String, ReferenceDef> temp = new TreeMap(references);
+ references.clear();
+ references.putAll(temp);
+ }
/**
* Returns a tag describing the component element.
@@ -115,11 +123,12 @@
* @return a component element
*/
Tag getTag() {
- Tag component = new Tag("scr:component");
+ String xmlns = this.xmlns;
+ if (xmlns == null && version != AnnotationReader.V1_0)
+ xmlns = NAMESPACE_STEM + "/v" + version;
+ Tag component = new Tag(xmlns == null? "component": "scr:component");
if (xmlns != null)
component.addAttribute("xmlns:scr", xmlns);
- else
- component.addAttribute("xmlns:scr", NAMESPACE_STEM + "/v" + version);
component.addAttribute("name", name);
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/DSAnnotations.java b/bundleplugin/src/main/java/aQute/bnd/component/DSAnnotations.java
index 5d16b9a..e66ad0c 100644
--- a/bundleplugin/src/main/java/aQute/bnd/component/DSAnnotations.java
+++ b/bundleplugin/src/main/java/aQute/bnd/component/DSAnnotations.java
@@ -23,16 +23,16 @@
if (sc != null && sc.trim().length() > 0)
names.add(sc);
- for (Iterator<Clazz> i = list.iterator(); i.hasNext();) {
+ for (Clazz c: list) {
for (Instruction instruction : instructions.keySet()) {
- Clazz c = i.next();
if (instruction.matches(c.getFQN())) {
if (instruction.isNegated())
- i.remove();
+ break;
else {
ComponentDef definition = AnnotationReader.getDefinition(c, analyzer);
if (definition != null) {
+ definition.sortReferences();
definition.prepare(analyzer);
String name = "OSGI-INF/" + definition.name + ".xml";
names.add(name);
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java b/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
new file mode 100644
index 0000000..584de6b
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
@@ -0,0 +1,496 @@
+package aQute.bnd.component;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+
+import aQute.bnd.osgi.*;
+import aQute.bnd.osgi.Clazz.MethodDef;
+import aQute.bnd.osgi.Descriptors.TypeRef;
+import aQute.lib.tag.Tag;
+import aQute.bnd.version.Version;
+
+public class HeaderReader extends Processor {
+ final static Pattern PROPERTY_PATTERN = Pattern
+ .compile("([^=]+([:@](Boolean|Byte|Char|Short|Integer|Long|Float|Double|String))?)\\s*=(.*)");
+ private final static Set<String> LIFECYCLE_METHODS = new HashSet<String>(Arrays.asList("activate", "deactivate", "modified"));
+
+ private final Analyzer analyzer;
+
+ private final static String ComponentContextTR = "org.osgi.service.component.ComponentContext";
+ private final static String BundleContextTR = "org.osgi.framework.BundleContext";
+ private final static String MapTR = Map.class.getName();
+ private final static String IntTR = int.class.getName();
+ private final static Set<String> allowed = new HashSet<String>(Arrays.asList(ComponentContextTR, BundleContextTR, MapTR));
+ private final static Set<String> allowedDeactivate = new HashSet<String>(Arrays.asList(ComponentContextTR, BundleContextTR, MapTR, IntTR));
+
+ private final static String ServiceReferenceTR = "org.osgi.framework.ServiceReference";
+
+ public HeaderReader(Analyzer analyzer) {
+ this.analyzer = analyzer;
+ }
+
+ public Tag createComponentTag(String name, String impl, Map<String, String> info)
+ throws Exception {
+ final ComponentDef cd = new ComponentDef();
+ cd.name = name;
+ if (info.get(COMPONENT_ENABLED) != null)
+ cd.enabled = Boolean.valueOf(info.get(COMPONENT_ENABLED));
+ cd.factory = info.get(COMPONENT_FACTORY);
+ if (info.get(COMPONENT_IMMEDIATE) != null)
+ cd.immediate = Boolean.valueOf(info.get(COMPONENT_IMMEDIATE));
+ if (info.get(COMPONENT_CONFIGURATION_POLICY) != null)
+ cd.configurationPolicy = ConfigurationPolicy.valueOf(info.get(COMPONENT_CONFIGURATION_POLICY).toUpperCase());
+ cd.activate = checkIdentifier(COMPONENT_ACTIVATE, info.get(COMPONENT_ACTIVATE));
+ cd.deactivate = checkIdentifier(COMPONENT_DEACTIVATE, info.get(COMPONENT_DEACTIVATE));
+ cd.modified = checkIdentifier(COMPONENT_MODIFIED, info.get(COMPONENT_MODIFIED));
+
+ cd.implementation = analyzer.getTypeRefFromFQN(impl == null? name: impl);
+
+
+ String provides = info.get(COMPONENT_PROVIDE);
+ if (info.get(COMPONENT_SERVICEFACTORY) != null) {
+ if (provides != null)
+ cd.servicefactory = Boolean.valueOf(info.get(COMPONENT_SERVICEFACTORY));
+ else
+ warning("The servicefactory:=true directive is set but no service is provided, ignoring it");
+ }
+
+ if (cd.servicefactory != null && cd.servicefactory && cd.immediate != null && cd.immediate) {
+ // TODO can become error() if it is up to me
+ warning("For a Service Component, the immediate option and the servicefactory option are mutually exclusive for %(%s)",
+ name, impl);
+ }
+
+ //analyze the class for suitable methods.
+ final Map<String, MethodDef> lifecycleMethods = new HashMap<String, MethodDef>();
+ final Map<String, MethodDef> bindmethods = new HashMap<String, MethodDef>();
+ TypeRef typeRef = analyzer.getTypeRefFromFQN(impl);
+ Clazz clazz = analyzer.findClass(typeRef);
+ boolean privateAllowed = true;
+ boolean defaultAllowed = true;
+ String topPackage = typeRef.getPackageRef().getFQN();
+ while (clazz != null) {
+ final boolean pa = privateAllowed;
+ final boolean da = defaultAllowed;
+ final Map<String, MethodDef> classLifecyclemethods = new HashMap<String, MethodDef>();
+ final Map<String, MethodDef> classBindmethods = new HashMap<String, MethodDef>();
+
+ clazz.parseClassFileWithCollector(new ClassDataCollector() {
+
+ public void method(MethodDef md) {
+ Set<String> allowedParams = allowed;
+ String lifecycleName = null;
+
+ boolean isLifecycle = (cd.activate == null? "activate": cd.activate).equals(md.getName()) ||
+ md.getName().equals(cd.modified);
+ if (!isLifecycle && (cd.deactivate == null? "deactivate": cd.deactivate).equals(md.getName())) {
+ isLifecycle = true;
+ allowedParams = allowedDeactivate;
+ }
+ if (isLifecycle && !lifecycleMethods.containsKey(md.getName()) &&
+ (md.isPublic() ||
+ md.isProtected() ||
+ (md.isPrivate() && pa) ||
+ (!md.isPrivate()) && da) &&
+ isBetter(md, classLifecyclemethods.get(md.getName()), allowedParams)) {
+ classLifecyclemethods.put(md.getName(), md);
+ }
+ if (!bindmethods.containsKey(md.getName()) &&
+ (md.isPublic() ||
+ md.isProtected() ||
+ (md.isPrivate() && pa) ||
+ (!md.isPrivate()) && da) &&
+ isBetterBind(md, classBindmethods.get(md.getName()))) {
+ classBindmethods.put(md.getName(), md);
+ }
+ }
+
+ private boolean isBetter(MethodDef test, MethodDef existing, Set<String> allowedParams) {
+ int testRating = rateLifecycle(test, allowedParams);
+ if (existing == null)
+ return testRating < 6;// ignore invalid methods
+ if (testRating < rateLifecycle(existing, allowedParams))
+ return true;
+
+ return false;
+ }
+
+ private boolean isBetterBind(MethodDef test, MethodDef existing) {
+ int testRating = rateBind(test);
+ if (existing == null)
+ return testRating < 6;// ignore invalid methods
+ if (testRating < rateBind(existing))
+ return true;
+
+ return false;
+ }
+
+ });
+ lifecycleMethods.putAll(classLifecyclemethods);
+ bindmethods.putAll(classBindmethods);
+ typeRef = clazz.getSuper();
+ if (typeRef == null)
+ break;
+ clazz = analyzer.findClass(typeRef);
+ privateAllowed = false;
+ defaultAllowed = defaultAllowed && topPackage.equals(typeRef.getPackageRef().getFQN());
+ }
+
+
+ if (cd.activate != null && !lifecycleMethods.containsKey(cd.activate)) {
+ error("in component %s, activate method %s specified but not found", cd.implementation.getFQN(), cd.activate);
+ cd.activate = null;
+ }
+ if (cd.deactivate != null && !lifecycleMethods.containsKey(cd.deactivate)) {
+ error("in component %s, deactivate method %s specified but not found", cd.implementation.getFQN(), cd.deactivate);
+ cd.activate = null;
+ }
+ if (cd.modified != null && !lifecycleMethods.containsKey(cd.modified)) {
+ error("in component %s, modified method %s specified but not found", cd.implementation.getFQN(), cd.modified);
+ cd.activate = null;
+ }
+
+ provide(cd, provides, impl);
+ properties(cd, info, name);
+ reference(info, impl, cd, bindmethods);
+ //compute namespace after references, an updated method means ds 1.2.
+ cd.xmlns = getNamespace(info, cd, lifecycleMethods);
+ cd.prepare(analyzer);
+ return cd.getTag();
+
+ }
+
+ private String checkIdentifier(String name, String value) {
+ if (value != null) {
+ if (!Verifier.isIdentifier(value)) {
+ error("Component attribute %s has value %s but is not a Java identifier",
+ name, value);
+ return null;
+ }
+ }
+ return value;
+ }
+
+ /**
+ * Check if we need to use the v1.1 namespace (or later).
+ *
+ * @param info
+ * @param cd TODO
+ * @param descriptors TODO
+ * @return
+ */
+ private String getNamespace(Map<String, String> info, ComponentDef cd, Map<String,MethodDef> descriptors) {
+ String namespace = info.get(COMPONENT_NAMESPACE);
+ if (namespace != null) {
+ return namespace;
+ }
+ String version = info.get(COMPONENT_VERSION);
+ if (version != null) {
+ try {
+ Version v = new Version(version);
+ return NAMESPACE_STEM + "/v" + v;
+ } catch (Exception e) {
+ error("version: specified on component header but not a valid version: "
+ + version);
+ return null;
+ }
+ }
+ for (String key : info.keySet()) {
+ if (SET_COMPONENT_DIRECTIVES_1_2.contains(key)) {
+ return NAMESPACE_STEM + "/v1.2.0";
+ }
+ }
+ for (ReferenceDef rd: cd.references.values()) {
+ if (rd.updated != null) {
+ return NAMESPACE_STEM + "/v1.2.0";
+ }
+ }
+ //among other things this picks up any specified lifecycle methods
+ for (String key : info.keySet()) {
+ if (SET_COMPONENT_DIRECTIVES_1_1.contains(key)) {
+ return NAMESPACE_STEM + "/v1.1.0";
+ }
+ }
+ for (String lifecycle: LIFECYCLE_METHODS) {
+ //lifecycle methods were not specified.... check for non 1.0 signatures.
+ if (descriptors.containsKey(lifecycle) && rateLifecycle(descriptors.get(lifecycle), "deactivate".equals(lifecycle)? allowedDeactivate: allowed) > 1) {
+ return NAMESPACE_STEM + "/v1.1.0";
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Print the Service-Component properties element
+ *
+ * @param cd
+ * @param info
+ */
+ void properties(ComponentDef cd, Map<String, String> info, String name) {
+ Collection<String> properties = split(info.get(COMPONENT_PROPERTIES));
+ for (String p : properties) {
+ Matcher m = PROPERTY_PATTERN.matcher(p);
+
+ if (m.matches()) {
+ String key = m.group(1).replaceAll("@", ":");
+ String value = m.group(4);
+ String parts[] = value.split("\\s*(\\||\\n)\\s*");
+ for (String part: parts) {
+ cd.property.add(key, part);
+ }
+ } else
+ throw new IllegalArgumentException("Malformed property '" + p
+ + "' on component: " + name);
+ }
+ }
+
+ /**
+ * @param cd
+ * @param provides
+ */
+ void provide(ComponentDef cd, String provides, String impl) {
+ if (provides != null) {
+ StringTokenizer st = new StringTokenizer(provides, ",");
+ List<TypeRef> provide = new ArrayList<TypeRef>();
+ while (st.hasMoreTokens()) {
+ String interfaceName = st.nextToken();
+ TypeRef ref = analyzer.getTypeRefFromFQN(interfaceName);
+ provide.add(ref);
+ analyzer.referTo(ref);
+
+ // TODO verifies the impl. class extends or implements the
+ // interface
+ }
+ cd.service = provide.toArray(new TypeRef[provide.size()]);
+ }
+ }
+
+ public final static Pattern REFERENCE = Pattern.compile("([^(]+)(\\(.+\\))?");
+
+ /**
+ * rates the methods according to the scale in 112.5.8 (compendium 4.3, ds 1.2), also returning "6" for invalid methods
+ * We don't look at return values yet due to proposal to all them for setting service properties.
+ * @param test methodDef to examine for suitability as a DS lifecycle method
+ * @param allowedParams TODO
+ * @return rating; 6 if invalid, lower is better
+ */
+ private int rateLifecycle(MethodDef test, Set<String> allowedParams) {
+ TypeRef[] prototype = test.getDescriptor().getPrototype();
+ if (prototype.length == 1 && ComponentContextTR.equals(prototype[0].getFQN()))
+ return 1;
+ if (prototype.length == 1 && BundleContextTR.equals(prototype[0].getFQN()))
+ return 2;
+ if (prototype.length == 1 && MapTR.equals(prototype[0].getFQN()))
+ return 3;
+ if (prototype.length > 1) {
+ for (TypeRef tr: prototype) {
+ if (!allowedParams.contains(tr.getFQN()))
+ return 6;
+ }
+ return 5;
+ }
+ if (prototype.length == 0)
+ return 5;
+
+ return 6;
+ }
+
+ /**
+ * see 112.3.2. We can't distinguish the bind type, so we just accept anything.
+ * @param test
+ * @return
+ */
+ private int rateBind(MethodDef test) {
+ TypeRef[] prototype = test.getDescriptor().getPrototype();
+ if (prototype.length == 1 && ServiceReferenceTR.equals(prototype[0].getFQN()))
+ return 1;
+ if (prototype.length == 1)
+ return 2;
+ if (prototype.length == 2 && MapTR.equals(prototype[1].getFQN()))
+ return 3;
+ return 6;
+ }
+
+ /**
+ * @param info
+ * @param impl TODO
+ * @param descriptors TODO
+ * @param pw
+ * @throws Exception
+ */
+ void reference(Map<String, String> info, String impl, ComponentDef cd, Map<String,MethodDef> descriptors) throws Exception {
+ Collection<String> dynamic = new ArrayList<String>(split(info.get(COMPONENT_DYNAMIC)));
+ Collection<String> optional = new ArrayList<String>(split(info.get(COMPONENT_OPTIONAL)));
+ Collection<String> multiple = new ArrayList<String>(split(info.get(COMPONENT_MULTIPLE)));
+ Collection<String> greedy = new ArrayList<String>(split(info.get(COMPONENT_GREEDY)));
+
+
+ for (Map.Entry<String, String> entry : info.entrySet()) {
+
+ // Skip directives
+ String referenceName = entry.getKey();
+ if (referenceName.endsWith(":")) {
+ if (!SET_COMPONENT_DIRECTIVES.contains(referenceName))
+ error("Unrecognized directive in Service-Component header: "
+ + referenceName);
+ continue;
+ }
+
+ // Parse the bind/unbind methods from the name
+ // if set. They are separated by '/'
+ String bind = null;
+ String unbind = null;
+ String updated = null;
+
+ boolean bindCalculated = true;
+ boolean unbindCalculated = true;
+ boolean updatedCalculated = true;
+
+ if (referenceName.indexOf('/') >= 0) {
+ String parts[] = referenceName.split("/");
+ referenceName = parts[0];
+ if (parts[1].length() > 0) {
+ bind = parts[1];
+ bindCalculated = false;
+ } else {
+ bind = calculateBind(referenceName);
+ }
+ bind = parts[1].length() == 0? calculateBind(referenceName): parts[1];
+ if (parts.length > 2 && parts[2].length() > 0) {
+ unbind = parts[2] ;
+ unbindCalculated = false;
+ } else {
+ if (bind.startsWith("add"))
+ unbind = bind.replaceAll("add(.+)", "remove$1");
+ else
+ unbind = "un" + bind;
+ }
+ if (parts.length > 3) {
+ updated = parts[3];
+ updatedCalculated = false;
+ }
+ } else if (Character.isLowerCase(referenceName.charAt(0))) {
+ bind = calculateBind(referenceName);
+ unbind = "un" + bind;
+ updated = "updated" + Character.toUpperCase(referenceName.charAt(0))
+ + referenceName.substring(1);
+ }
+
+ String interfaceName = entry.getValue();
+ if (interfaceName == null || interfaceName.length() == 0) {
+ error("Invalid Interface Name for references in Service Component: "
+ + referenceName + "=" + interfaceName);
+ continue;
+ }
+
+ // If we have descriptors, we have analyzed the component.
+ // So why not check the methods
+ if (descriptors.size() > 0) {
+ // Verify that the bind method exists
+ if (!descriptors.containsKey(bind))
+ if (bindCalculated)
+ bind = null;
+ else
+ error("In component %s, the bind method %s for %s not defined", cd.name, bind, referenceName);
+
+ // Check if the unbind method exists
+ if (!descriptors.containsKey(unbind)) {
+ if (unbindCalculated)
+ // remove it
+ unbind = null;
+ else
+ error("In component %s, the unbind method %s for %s not defined", cd.name, unbind, referenceName);
+ }
+ if (!descriptors.containsKey(updated)) {
+ if (updatedCalculated)
+ //remove it
+ updated = null;
+ else
+ error("In component %s, the updated method %s for %s is not defined", cd.name, updated, referenceName);
+ }
+ }
+ // Check the cardinality by looking at the last
+ // character of the value
+ char c = interfaceName.charAt(interfaceName.length() - 1);
+ if ("?+*~".indexOf(c) >= 0) {
+ if (c == '?' || c == '*' || c == '~')
+ optional.add(referenceName);
+ if (c == '+' || c == '*')
+ multiple.add(referenceName);
+ if (c == '+' || c == '*' || c == '?')
+ dynamic.add(referenceName);
+ interfaceName = interfaceName.substring(0, interfaceName.length() - 1);
+ }
+
+ // Parse the target from the interface name
+ // The target is a filter.
+ String target = null;
+ Matcher m = REFERENCE.matcher(interfaceName);
+ if (m.matches()) {
+ interfaceName = m.group(1);
+ target = m.group(2);
+ }
+ TypeRef ref = analyzer.getTypeRefFromFQN(interfaceName);
+ analyzer.referTo(ref);
+ ReferenceDef rd = new ReferenceDef();
+ rd.name = referenceName;
+ rd.service = interfaceName;
+
+ if (optional.contains(referenceName)) {
+ if (multiple.contains(referenceName)) {
+ rd.cardinality = ReferenceCardinality.MULTIPLE;
+ } else {
+ rd.cardinality = ReferenceCardinality.OPTIONAL;
+ }
+ } else {
+ if (multiple.contains(referenceName)) {
+ rd.cardinality = ReferenceCardinality.AT_LEAST_ONE;
+ } else {
+ rd.cardinality = ReferenceCardinality.MANDATORY;
+ }
+ }
+ if (bind != null) {
+ rd.bind = bind;
+ if (unbind != null) {
+ rd.unbind = unbind;
+ }
+ if (updated != null) {
+ rd.updated = updated;
+ }
+ }
+
+ if (dynamic.contains(referenceName)) {
+ rd.policy = ReferencePolicy.DYNAMIC;
+ }
+
+ if (greedy.contains(referenceName)) {
+ rd.policyOption = ReferencePolicyOption.GREEDY;
+ }
+
+ if (target != null) {
+ rd.target = target;
+ }
+ cd.references.put(referenceName, rd);
+ }
+ }
+
+ private String calculateBind(String referenceName) {
+ return "set" + Character.toUpperCase(referenceName.charAt(0))
+ + referenceName.substring(1);
+ }
+
+}
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java b/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java
index 8830084..fc09c52 100644
--- a/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java
+++ b/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java
@@ -11,7 +11,7 @@
*/
class ReferenceDef {
- Version version = AnnotationReader.V1_1;
+ Version version = AnnotationReader.V1_0;
String name;
String service;
ReferenceCardinality cardinality;
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/TagResource.java b/bundleplugin/src/main/java/aQute/bnd/component/TagResource.java
index cdeb93c..1155d99 100644
--- a/bundleplugin/src/main/java/aQute/bnd/component/TagResource.java
+++ b/bundleplugin/src/main/java/aQute/bnd/component/TagResource.java
@@ -5,7 +5,7 @@
import aQute.bnd.osgi.*;
import aQute.lib.tag.*;
-class TagResource extends WriteResource {
+public class TagResource extends WriteResource {
final Tag tag;
public TagResource(Tag tag) {
diff --git a/bundleplugin/src/main/java/aQute/bnd/make/component/ComponentAnnotationReader.java b/bundleplugin/src/main/java/aQute/bnd/make/component/ComponentAnnotationReader.java
index 5143bd8..c9d60b3 100644
--- a/bundleplugin/src/main/java/aQute/bnd/make/component/ComponentAnnotationReader.java
+++ b/bundleplugin/src/main/java/aQute/bnd/make/component/ComponentAnnotationReader.java
@@ -12,6 +12,10 @@
import aQute.bnd.osgi.Descriptors.TypeRef;
import aQute.service.reporter.*;
+/**
+ * This converts bnd style annotations to, roughly, the header format.
+ *
+ */
public class ComponentAnnotationReader extends ClassDataCollector {
String EMPTY[] = new String[0];
private static final String V1_1 = "1.1.0"; // "1.1.0"
@@ -188,6 +192,10 @@
unbind = annotation.get(Reference.UNBIND);
+ //this error reporting currently handled in HeaderReader. If we rewrite this to go directly to ComponentDesc, we'll want this.
+// if (unbind != null && !descriptors.contains(unbind))
+// reporter.error("In component %s, for bind method %s, missing unbind method %s", name, bind, unbind);
+
if (bind != null) {
name = name + "/" + bind;
if (unbind != null)
diff --git a/bundleplugin/src/main/java/aQute/bnd/make/component/ServiceComponent.java b/bundleplugin/src/main/java/aQute/bnd/make/component/ServiceComponent.java
index 06946ab..af863c6 100644
--- a/bundleplugin/src/main/java/aQute/bnd/make/component/ServiceComponent.java
+++ b/bundleplugin/src/main/java/aQute/bnd/make/component/ServiceComponent.java
@@ -1,18 +1,22 @@
package aQute.bnd.make.component;
-import java.io.*;
-import java.util.*;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+import java.util.Map;
import java.util.Map.Entry;
-import java.util.regex.*;
import aQute.bnd.annotation.component.*;
+import aQute.bnd.component.*;
import aQute.bnd.header.*;
import aQute.bnd.make.metatype.*;
import aQute.bnd.osgi.*;
+import aQute.bnd.osgi.Clazz.MethodDef;
import aQute.bnd.osgi.Clazz.QUERY;
import aQute.bnd.osgi.Descriptors.TypeRef;
import aQute.bnd.service.*;
import aQute.bnd.version.*;
+import aQute.lib.tag.Tag;
/**
* This class is an analyzer plugin. It looks at the properties and tries to
@@ -76,6 +80,7 @@
catch (Exception e) {
e.printStackTrace();
error("Invalid Service-Component header: %s %s, throws %s", name, info, e);
+ throw e;
}
}
return serviceComponents;
@@ -208,7 +213,7 @@
}
private void createComponentResource(Map<String,Map<String,String>> components, String name,
- Map<String,String> info) throws IOException {
+ Map<String,String> info) throws Exception {
// We can override the name in the parameters
if (info.containsKey(COMPONENT_NAME))
@@ -275,343 +280,11 @@
* @param info
* @throws UnsupportedEncodingException
*/
- Resource createComponentResource(String name, String impl, Map<String,String> info) throws IOException {
- String namespace = getNamespace(info);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- PrintWriter pw = new PrintWriter(new OutputStreamWriter(out, Constants.DEFAULT_CHARSET));
- pw.println("<?xml version='1.0' encoding='utf-8'?>");
- if (namespace != null)
- pw.print("<scr:component xmlns:scr='" + namespace + "'");
- else
- pw.print("<component");
-
- doAttribute(pw, name, "name");
- doAttribute(pw, info.get(COMPONENT_FACTORY), "factory");
- doAttribute(pw, info.get(COMPONENT_IMMEDIATE), "immediate", "false", "true");
- doAttribute(pw, info.get(COMPONENT_ENABLED), "enabled", "true", "false");
- doAttribute(pw, info.get(COMPONENT_CONFIGURATION_POLICY), "configuration-policy", "optional", "require",
- "ignore");
- doAttribute(pw, info.get(COMPONENT_ACTIVATE), "activate", JIDENTIFIER);
- doAttribute(pw, info.get(COMPONENT_DEACTIVATE), "deactivate", JIDENTIFIER);
- doAttribute(pw, info.get(COMPONENT_MODIFIED), "modified", JIDENTIFIER);
-
- pw.println(">");
-
- // Allow override of the implementation when people
- // want to choose their own name
- pw.println(" <implementation class='" + (impl == null ? name : impl) + "'/>");
-
- String provides = info.get(COMPONENT_PROVIDE);
- boolean servicefactory = Processor.isTrue(info.get(COMPONENT_SERVICEFACTORY));
-
- if (servicefactory && Processor.isTrue(info.get(COMPONENT_IMMEDIATE))) {
- // TODO can become error() if it is up to me
- warning("For a Service Component, the immediate option and the servicefactory option are mutually exclusive for %(%s)",
- name, impl);
- }
- provide(pw, provides, servicefactory, impl);
- properties(pw, info);
- reference(info, pw);
-
- if (namespace != null)
- pw.println("</scr:component>");
- else
- pw.println("</component>");
-
- pw.close();
- byte[] data = out.toByteArray();
- out.close();
- return new EmbeddedResource(data, 0);
+ Resource createComponentResource(String name, String impl, Map<String, String> info)
+ throws Exception {
+ Tag tag = new HeaderReader(analyzer).createComponentTag(name, impl, info);
+ return new TagResource(tag);
}
-
- private void doAttribute(PrintWriter pw, String value, String name, String... matches) {
- if (value != null) {
- if (matches.length != 0) {
- if (matches.length == 1 && matches[0].equals(JIDENTIFIER)) {
- if (!Verifier.isIdentifier(value))
- error("Component attribute %s has value %s but is not a Java identifier", name, value);
- } else {
-
- if (!Verifier.isMember(value, matches))
- error("Component attribute %s has value %s but is not a member of %s", name, value,
- Arrays.toString(matches));
- }
- }
- pw.print(" ");
- pw.print(name);
- pw.print("='");
- pw.print(value);
- pw.print("'");
- }
- }
-
- /**
- * Check if we need to use the v1.1 namespace (or later).
- *
- * @param info
- * @return
- */
- private String getNamespace(Map<String,String> info) {
- String version = info.get(COMPONENT_VERSION);
- if (version != null) {
- try {
- Version v = new Version(version);
- return NAMESPACE_STEM + "/v" + v;
- }
- catch (Exception e) {
- error("version: specified on component header but not a valid version: " + version);
- return null;
- }
- }
- for (String key : info.keySet()) {
- if (SET_COMPONENT_DIRECTIVES_1_1.contains(key)) {
- return NAMESPACE_STEM + "/v1.1.0";
- }
- }
- return null;
- }
-
- /**
- * Print the Service-Component properties element
- *
- * @param pw
- * @param info
- */
- void properties(PrintWriter pw, Map<String,String> info) {
- Collection<String> properties = split(info.get(COMPONENT_PROPERTIES));
- for (Iterator<String> p = properties.iterator(); p.hasNext();) {
- String clause = p.next();
- int n = clause.indexOf('=');
- if (n <= 0) {
- error("Not a valid property in service component: " + clause);
- } else {
- String type = null;
- String name = clause.substring(0, n);
- if (name.indexOf('@') >= 0) {
- String parts[] = name.split("@");
- name = parts[1];
- type = parts[0];
- } else if (name.indexOf(':') >= 0) {
- String parts[] = name.split(":");
- name = parts[0];
- type = parts[1];
- }
- String value = clause.substring(n + 1).trim();
- // TODO verify validity of name and value.
- pw.print(" <property name='");
- pw.print(name);
- pw.print("'");
-
- if (type != null) {
- if (VALID_PROPERTY_TYPES.matcher(type).matches()) {
- pw.print(" type='");
- pw.print(type);
- pw.print("'");
- } else {
- warning("Invalid property type '" + type + "' for property " + name);
- }
- }
-
- String parts[] = value.split("\\s*(\\||\\n)\\s*");
- if (parts.length > 1) {
- pw.println(">");
- for (String part : parts) {
- pw.println(part);
- }
- pw.println("</property>");
- } else {
- pw.print(" value='");
- pw.print(parts[0]);
- pw.println("'/>");
- }
- }
- }
- }
-
- /**
- * @param pw
- * @param provides
- */
- void provide(PrintWriter pw, String provides, boolean servicefactory, @SuppressWarnings("unused") String impl) {
- if (provides != null) {
- if (!servicefactory)
- pw.println(" <service>");
- else
- pw.println(" <service servicefactory='true'>");
-
- StringTokenizer st = new StringTokenizer(provides, ",");
- while (st.hasMoreTokens()) {
- String interfaceName = st.nextToken();
- TypeRef ref = analyzer.getTypeRefFromFQN(interfaceName);
- pw.println(" <provide interface='" + interfaceName + "'/>");
- analyzer.referTo(ref);
-
- // TODO verifies the impl. class extends or implements the
- // interface
- }
- pw.println(" </service>");
- } else if (servicefactory)
- warning("The servicefactory:=true directive is set but no service is provided, ignoring it");
- }
-
- public final static Pattern REFERENCE = Pattern.compile("([^(]+)(\\(.+\\))?");
-
- /**
- * @param info
- * @param pw
- */
-
- void reference(Map<String,String> info, PrintWriter pw) {
- Collection<String> dynamic = new ArrayList<String>(split(info.get(COMPONENT_DYNAMIC)));
- Collection<String> optional = new ArrayList<String>(split(info.get(COMPONENT_OPTIONAL)));
- Collection<String> multiple = new ArrayList<String>(split(info.get(COMPONENT_MULTIPLE)));
-
- Collection<String> descriptors = split(info.get(COMPONENT_DESCRIPTORS));
-
- for (Map.Entry<String,String> entry : info.entrySet()) {
-
- // Skip directives
- String referenceName = entry.getKey();
- if (referenceName.endsWith(":")) {
- if (!SET_COMPONENT_DIRECTIVES.contains(referenceName))
- error("Unrecognized directive in Service-Component header: " + referenceName);
- continue;
- }
-
- // Parse the bind/unbind methods from the name
- // if set. They are separated by '/'
- String bind = null;
- String unbind = null;
-
- boolean unbindCalculated = false;
-
- if (referenceName.indexOf('/') >= 0) {
- String parts[] = referenceName.split("/");
- referenceName = parts[0];
- bind = parts[1];
- if (parts.length > 2) {
- unbind = parts[2];
- } else {
- unbindCalculated = true;
- if (bind.startsWith("add"))
- unbind = bind.replaceAll("add(.+)", "remove$1");
- else
- unbind = "un" + bind;
- }
- } else if (Character.isLowerCase(referenceName.charAt(0))) {
- unbindCalculated = true;
- bind = "set" + Character.toUpperCase(referenceName.charAt(0)) + referenceName.substring(1);
- unbind = "un" + bind;
- }
-
- String interfaceName = entry.getValue();
- if (interfaceName == null || interfaceName.length() == 0) {
- error("Invalid Interface Name for references in Service Component: " + referenceName + "="
- + interfaceName);
- continue;
- }
-
- // If we have descriptors, we have analyzed the component.
- // So why not check the methods
- if (descriptors.size() > 0) {
- // Verify that the bind method exists
- if (!descriptors.contains(bind))
- error("The bind method %s for %s not defined", bind, referenceName);
-
- // Check if the unbind method exists
- if (!descriptors.contains(unbind)) {
- if (unbindCalculated)
- // remove it
- unbind = null;
- else
- error("The unbind method %s for %s not defined", unbind, referenceName);
- }
- }
- // Check tje cardinality by looking at the last
- // character of the value
- char c = interfaceName.charAt(interfaceName.length() - 1);
- if ("?+*~".indexOf(c) >= 0) {
- if (c == '?' || c == '*' || c == '~')
- optional.add(referenceName);
- if (c == '+' || c == '*')
- multiple.add(referenceName);
- if (c == '+' || c == '*' || c == '?')
- dynamic.add(referenceName);
- interfaceName = interfaceName.substring(0, interfaceName.length() - 1);
- }
-
- // Parse the target from the interface name
- // The target is a filter.
- String target = null;
- Matcher m = REFERENCE.matcher(interfaceName);
- if (m.matches()) {
- interfaceName = m.group(1);
- target = m.group(2);
- }
- TypeRef ref = analyzer.getTypeRefFromFQN(interfaceName);
- analyzer.referTo(ref);
-
- pw.printf(" <reference name='%s'", referenceName);
- pw.printf(" interface='%s'", interfaceName);
-
- String cardinality = optional.contains(referenceName) ? "0" : "1";
- cardinality += "..";
- cardinality += multiple.contains(referenceName) ? "n" : "1";
- if (!cardinality.equals("1..1"))
- pw.print(" cardinality='" + cardinality + "'");
-
- if (bind != null) {
- pw.printf(" bind='%s'", bind);
- if (unbind != null) {
- pw.printf(" unbind='%s'", unbind);
- }
- }
-
- if (dynamic.contains(referenceName)) {
- pw.print(" policy='dynamic'");
- }
-
- if (target != null) {
- // Filter filter = new Filter(target);
- // if (filter.verify() == null)
- // pw.print(" target='" + filter.toString() + "'");
- // else
- // error("Target for " + referenceName
- // + " is not a correct filter: " + target + " "
- // + filter.verify());
- pw.print(" target='" + escape(target) + "'");
- }
- pw.println("/>");
- }
- }
- }
-
- /**
- * Escape a string, do entity conversion.
- */
- static String escape(String s) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- switch (c) {
- case '<' :
- sb.append("<");
- break;
- case '>' :
- sb.append(">");
- break;
- case '&' :
- sb.append("&");
- break;
- case '\'' :
- sb.append(""");
- break;
- default :
- sb.append(c);
- break;
- }
- }
- return sb.toString();
}
}
diff --git a/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java b/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
index d4e68ce..5c3e2b7 100755
--- a/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
+++ b/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
@@ -306,7 +306,9 @@
void doPlugins() {
for (AnalyzerPlugin plugin : getPlugins(AnalyzerPlugin.class)) {
try {
+ Processor previous = beginHandleErrors(plugin.toString());
boolean reanalyze = plugin.analyzeJar(this);
+ endHandleErrors(previous);
if (reanalyze) {
classspace.clear();
analyzeBundleClasspath();
diff --git a/bundleplugin/src/main/java/aQute/bnd/osgi/Clazz.java b/bundleplugin/src/main/java/aQute/bnd/osgi/Clazz.java
index 0a72c77..e03865a 100755
--- a/bundleplugin/src/main/java/aQute/bnd/osgi/Clazz.java
+++ b/bundleplugin/src/main/java/aQute/bnd/osgi/Clazz.java
@@ -833,13 +833,13 @@
if (cd != null)
cd.deprecated();
} else if ("RuntimeVisibleAnnotations".equals(attributeName))
- doAnnotations(in, member, RetentionPolicy.RUNTIME);
+ doAnnotations(in, member, RetentionPolicy.RUNTIME, access_flags);
else if ("RuntimeVisibleParameterAnnotations".equals(attributeName))
- doParameterAnnotations(in, member, RetentionPolicy.RUNTIME);
+ doParameterAnnotations(in, member, RetentionPolicy.RUNTIME, access_flags);
else if ("RuntimeInvisibleAnnotations".equals(attributeName))
- doAnnotations(in, member, RetentionPolicy.CLASS);
+ doAnnotations(in, member, RetentionPolicy.CLASS, access_flags);
else if ("RuntimeInvisibleParameterAnnotations".equals(attributeName))
- doParameterAnnotations(in, member, RetentionPolicy.CLASS);
+ doParameterAnnotations(in, member, RetentionPolicy.CLASS, access_flags);
else if ("InnerClasses".equals(attributeName))
doInnerClasses(in);
else if ("EnclosingMethod".equals(attributeName))
@@ -852,7 +852,9 @@
doSignature(in, member, access_flags);
else if ("ConstantValue".equals(attributeName))
doConstantValue(in);
- else {
+ else if ("Exceptions".equals(attributeName))
+ doExceptions(in, access_flags);
+ else {
if (attribute_length > 0x7FFFFFFF) {
throw new IllegalArgumentException("Attribute > 2Gb");
}
@@ -985,6 +987,20 @@
cd.constant(object);
}
+ void doExceptions(DataInputStream in, int access_flags) throws IOException {
+ int exception_count = in.readUnsignedShort();
+ for (int i = 0; i < exception_count; i++) {
+ int index = in.readUnsignedShort();
+ if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags))) {
+ ClassConstant cc = (ClassConstant) pool[index];
+ String descr = (String) pool[cc.cname];
+
+ TypeRef clazz = analyzer.getTypeRef(descr);
+ referTo(clazz, access_flags);
+ }
+ }
+ }
+
/**
* <pre>
* Code_attribute {
@@ -1121,29 +1137,29 @@
this.sourceFile = pool[sourcefile_index].toString();
}
- private void doParameterAnnotations(DataInputStream in, ElementType member, RetentionPolicy policy)
+ private void doParameterAnnotations(DataInputStream in, ElementType member, RetentionPolicy policy, int access_flags)
throws IOException {
int num_parameters = in.readUnsignedByte();
for (int p = 0; p < num_parameters; p++) {
if (cd != null)
cd.parameter(p);
- doAnnotations(in, member, policy);
+ doAnnotations(in, member, policy, access_flags);
}
}
- private void doAnnotations(DataInputStream in, ElementType member, RetentionPolicy policy) throws IOException {
+ private void doAnnotations(DataInputStream in, ElementType member, RetentionPolicy policy, int access_flags) throws IOException {
int num_annotations = in.readUnsignedShort(); // # of annotations
for (int a = 0; a < num_annotations; a++) {
if (cd == null)
- doAnnotation(in, member, policy, false);
+ doAnnotation(in, member, policy, false, access_flags);
else {
- Annotation annotion = doAnnotation(in, member, policy, true);
+ Annotation annotion = doAnnotation(in, member, policy, true, access_flags);
cd.annotation(annotion);
}
}
}
- private Annotation doAnnotation(DataInputStream in, ElementType member, RetentionPolicy policy, boolean collect)
+ private Annotation doAnnotation(DataInputStream in, ElementType member, RetentionPolicy policy, boolean collect, int access_flags)
throws IOException {
int type_index = in.readUnsignedShort();
if (annotations == null)
@@ -1152,19 +1168,21 @@
TypeRef tr = analyzer.getTypeRef(pool[type_index].toString());
annotations.add(tr);
+ TypeRef name = analyzer.getTypeRef((String) pool[type_index]);
if (policy == RetentionPolicy.RUNTIME) {
referTo(type_index, 0);
hasRuntimeAnnotations = true;
+ if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags)))
+ api.add(name.getPackageRef());
} else {
hasClassAnnotations = true;
}
- TypeRef name = analyzer.getTypeRef((String) pool[type_index]);
int num_element_value_pairs = in.readUnsignedShort();
Map<String,Object> elements = null;
for (int v = 0; v < num_element_value_pairs; v++) {
int element_name_index = in.readUnsignedShort();
String element = (String) pool[element_name_index];
- Object value = doElementValue(in, member, policy, collect);
+ Object value = doElementValue(in, member, policy, collect, access_flags);
if (collect) {
if (elements == null)
elements = new LinkedHashMap<String,Object>();
@@ -1176,7 +1194,7 @@
return null;
}
- private Object doElementValue(DataInputStream in, ElementType member, RetentionPolicy policy, boolean collect)
+ private Object doElementValue(DataInputStream in, ElementType member, RetentionPolicy policy, boolean collect, int access_flags)
throws IOException {
char tag = (char) in.readUnsignedByte();
switch (tag) {
@@ -1200,25 +1218,35 @@
case 'e' : // enum constant
int type_name_index = in.readUnsignedShort();
- if (policy == RetentionPolicy.RUNTIME)
+ if (policy == RetentionPolicy.RUNTIME) {
referTo(type_name_index, 0);
+ if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags))) {
+ TypeRef name = analyzer.getTypeRef((String) pool[type_name_index]);
+ api.add(name.getPackageRef());
+ }
+ }
int const_name_index = in.readUnsignedShort();
return pool[const_name_index];
case 'c' : // Class
int class_info_index = in.readUnsignedShort();
- if (policy == RetentionPolicy.RUNTIME)
+ if (policy == RetentionPolicy.RUNTIME) {
referTo(class_info_index, 0);
+ if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags))) {
+ TypeRef name = analyzer.getTypeRef((String) pool[class_info_index]);
+ api.add(name.getPackageRef());
+ }
+ }
return pool[class_info_index];
case '@' : // Annotation type
- return doAnnotation(in, member, policy, collect);
+ return doAnnotation(in, member, policy, collect, access_flags);
case '[' : // Array
int num_values = in.readUnsignedShort();
Object[] result = new Object[num_values];
for (int i = 0; i < num_values; i++) {
- result[i] = doElementValue(in, member, policy, collect);
+ result[i] = doElementValue(in, member, policy, collect, access_flags);
}
return result;
@@ -1475,7 +1503,7 @@
return false;
case RUNTIMEANNOTATIONS :
- return hasClassAnnotations;
+ return hasRuntimeAnnotations;
case CLASSANNOTATIONS :
return hasClassAnnotations;
diff --git a/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java b/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java
index 755e9a2..230c717 100644
--- a/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java
+++ b/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java
@@ -274,6 +274,7 @@
public final static String COMPONENT_ENABLED = "enabled:";
public final static String COMPONENT_DYNAMIC = "dynamic:";
public final static String COMPONENT_MULTIPLE = "multiple:";
+ public final static String COMPONENT_GREEDY = "greedy:";
public final static String COMPONENT_PROVIDE = "provide:";
public final static String COMPONENT_OPTIONAL = "optional:";
public final static String COMPONENT_PROPERTIES = "properties:";
@@ -289,6 +290,8 @@
public final static String COMPONENT_ACTIVATE = "activate:";
public final static String COMPONENT_DEACTIVATE = "deactivate:";
+ public final static String COMPONENT_NAMESPACE = "xmlns:";
+
final static Map<String,String> EMPTY = Collections.emptyMap();
public final static String[] componentDirectives = new String[] {
@@ -296,7 +299,7 @@
COMPONENT_PROVIDE, COMPONENT_OPTIONAL, COMPONENT_PROPERTIES, COMPONENT_IMPLEMENTATION,
COMPONENT_SERVICEFACTORY, COMPONENT_VERSION, COMPONENT_CONFIGURATION_POLICY, COMPONENT_MODIFIED,
COMPONENT_ACTIVATE, COMPONENT_DEACTIVATE, COMPONENT_NAME, COMPONENT_DESCRIPTORS, COMPONENT_DESIGNATE,
- COMPONENT_DESIGNATEFACTORY
+ COMPONENT_DESIGNATEFACTORY, COMPONENT_GREEDY, COMPONENT_NAMESPACE
};
public final static Set<String> SET_COMPONENT_DIRECTIVES = new HashSet<String>(
@@ -310,4 +313,11 @@
COMPONENT_ACTIVATE,
COMPONENT_DEACTIVATE));
+ public final static Set<String> SET_COMPONENT_DIRECTIVES_1_2 = new HashSet<String>(
+ Arrays.asList(COMPONENT_GREEDY));
}
+
+
+
+
+