You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by mc...@apache.org on 2012/07/22 02:19:14 UTC

svn commit: r1364196 - in /felix/trunk/bundleplugin/src/main/java/aQute/bnd: annotation/ component/ make/component/ osgi/

Author: mcculls
Date: Sun Jul 22 00:19:13 2012
New Revision: 1364196

URL: http://svn.apache.org/viewvc?rev=1364196&view=rev
Log:
Sync bndlib source

Added:
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java   (with props)
Modified:
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/DSAnnotations.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/TagResource.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/component/ComponentAnnotationReader.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/component/ServiceComponent.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Clazz.java
    felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/ConsumerType.java Sun Jul 22 00:19:13 2012
@@ -8,6 +8,7 @@ import java.lang.annotation.*;
  * 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 {

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/Export.java Sun Jul 22 00:19:13 2012
@@ -2,6 +2,7 @@ package aQute.bnd.annotation;
 
 import java.lang.annotation.*;
 
+@Documented
 @Retention(RetentionPolicy.CLASS)
 @Target(ElementType.PACKAGE)
 public @interface Export {

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/ProviderType.java Sun Jul 22 00:19:13 2012
@@ -8,6 +8,7 @@ import java.lang.annotation.*;
  * 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 {

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/annotation/Version.java Sun Jul 22 00:19:13 2012
@@ -2,6 +2,7 @@ package aQute.bnd.annotation;
 
 import java.lang.annotation.*;
 
+@Documented
 @Retention(RetentionPolicy.CLASS)
 @Target({
 	ElementType.PACKAGE

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/AnnotationReader.java Sun Jul 22 00:19:13 2012
@@ -29,6 +29,7 @@ public class AnnotationReader extends Cl
 	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 @@ public class AnnotationReader extends Cl
 		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();

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/ComponentDef.java Sun Jul 22 00:19:13 2012
@@ -22,9 +22,9 @@ class ComponentDef {
 	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 @@ class ComponentDef {
 		} 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 @@ class ComponentDef {
 			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 @@ class ComponentDef {
 	 * @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);
 

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/DSAnnotations.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/DSAnnotations.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/DSAnnotations.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/DSAnnotations.java Sun Jul 22 00:19:13 2012
@@ -23,16 +23,16 @@ public class DSAnnotations implements An
 		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);

Added: felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java?rev=1364196&view=auto
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java (added)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java Sun Jul 22 00:19:13 2012
@@ -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);
+	}
+
+}

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/ReferenceDef.java Sun Jul 22 00:19:13 2012
@@ -11,7 +11,7 @@ import aQute.lib.tag.*;
  */
 
 class ReferenceDef {
-	Version					version	= AnnotationReader.V1_1;
+	Version					version	= AnnotationReader.V1_0;
 	String					name;
 	String					service;
 	ReferenceCardinality	cardinality;

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/TagResource.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/TagResource.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/TagResource.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/component/TagResource.java Sun Jul 22 00:19:13 2012
@@ -5,7 +5,7 @@ import java.io.*;
 import aQute.bnd.osgi.*;
 import aQute.lib.tag.*;
 
-class TagResource extends WriteResource {
+public class TagResource extends WriteResource {
 	final Tag	tag;
 
 	public TagResource(Tag tag) {

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/component/ComponentAnnotationReader.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/component/ComponentAnnotationReader.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/component/ComponentAnnotationReader.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/component/ComponentAnnotationReader.java Sun Jul 22 00:19:13 2012
@@ -12,6 +12,10 @@ import aQute.bnd.osgi.Clazz.MethodDef;
 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 @@ public class ComponentAnnotationReader e
 
 			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)

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/component/ServiceComponent.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/component/ServiceComponent.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/component/ServiceComponent.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/make/component/ServiceComponent.java Sun Jul 22 00:19:13 2012
@@ -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 @@ public class ServiceComponent implements
 				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 @@ public class ServiceComponent implements
 		}
 
 		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 @@ public class ServiceComponent implements
 		 * @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);
-		}
-
-		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("&lt;");
-					break;
-				case '>' :
-					sb.append("&gt;");
-					break;
-				case '&' :
-					sb.append("&amp;");
-					break;
-				case '\'' :
-					sb.append("&quot;");
-					break;
-				default :
-					sb.append(c);
-					break;
-			}
+		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);
 		}
-		return sb.toString();
 	}
 
 }

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java Sun Jul 22 00:19:13 2012
@@ -306,7 +306,9 @@ public class Analyzer extends Processor 
 	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();

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Clazz.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Clazz.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Clazz.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Clazz.java Sun Jul 22 00:19:13 2012
@@ -833,13 +833,13 @@ public class Clazz {
 			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 @@ public class Clazz {
 			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 @@ public class Clazz {
 		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 @@ public class Clazz {
 		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 @@ public class Clazz {
 		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 @@ public class Clazz {
 		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 @@ public class Clazz {
 
 			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 @@ public class Clazz {
 				return false;
 
 			case RUNTIMEANNOTATIONS :
-				return hasClassAnnotations;
+				return hasRuntimeAnnotations;
 			case CLASSANNOTATIONS :
 				return hasClassAnnotations;
 

Modified: felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java?rev=1364196&r1=1364195&r2=1364196&view=diff
==============================================================================
--- felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java (original)
+++ felix/trunk/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java Sun Jul 22 00:19:13 2012
@@ -274,6 +274,7 @@ public interface Constants {
 	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 interface Constants {
 	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 @@ public interface Constants {
 			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 @@ public interface Constants {
 																						COMPONENT_ACTIVATE,
 																						COMPONENT_DEACTIVATE));
 
+	public final static Set<String>		SET_COMPONENT_DIRECTIVES_1_2				= new HashSet<String>(
+																							Arrays.asList(COMPONENT_GREEDY));
 }
+
+
+
+
+