Latest bndlib code (with potential fix for GF)

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1365307 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java b/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
index 584de6b..a794027 100644
--- a/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
+++ b/bundleplugin/src/main/java/aQute/bnd/component/HeaderReader.java
@@ -227,7 +227,9 @@
 		}
 		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) {
+			MethodDef test = descriptors.get(lifecycle);
+			if (descriptors.containsKey(lifecycle) && (!(test.isPublic() || test.isProtected()) || 
+					rateLifecycle(test, "deactivate".equals(lifecycle)? allowedDeactivate: allowed) > 1)) {
 				return NAMESPACE_STEM + "/v1.1.0";
 			}
 		}
@@ -291,7 +293,7 @@
 	private int rateLifecycle(MethodDef test, Set<String> allowedParams) {
 		TypeRef[] prototype = test.getDescriptor().getPrototype();
 		if (prototype.length == 1 && ComponentContextTR.equals(prototype[0].getFQN()))
-			return 1;
+			    return 1;
 		if (prototype.length == 1 && BundleContextTR.equals(prototype[0].getFQN()))
 			return 2;
 		if (prototype.length == 1 && MapTR.equals(prototype[0].getFQN()))
diff --git a/bundleplugin/src/main/java/aQute/bnd/differ/RepositoryElement.java b/bundleplugin/src/main/java/aQute/bnd/differ/RepositoryElement.java
index 0145149..99cdf89 100644
--- a/bundleplugin/src/main/java/aQute/bnd/differ/RepositoryElement.java
+++ b/bundleplugin/src/main/java/aQute/bnd/differ/RepositoryElement.java
@@ -2,7 +2,6 @@
 
 import java.util.*;
 
-import aQute.bnd.osgi.*;
 import aQute.bnd.service.*;
 import aQute.bnd.service.diff.*;
 import aQute.bnd.version.*;
diff --git a/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java b/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
index 5c3e2b7..c490e66 100755
--- a/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
+++ b/bundleplugin/src/main/java/aQute/bnd/osgi/Analyzer.java
@@ -336,127 +336,135 @@
 	 * @throws IOException
 	 */
 	public Manifest calcManifest() throws Exception {
-		analyze();
-		Manifest manifest = new Manifest();
-		Attributes main = manifest.getMainAttributes();
+		try {
+			analyze();
+			Manifest manifest = new Manifest();
+			Attributes main = manifest.getMainAttributes();
 
-		main.put(Attributes.Name.MANIFEST_VERSION, "1.0");
-		main.putValue(BUNDLE_MANIFESTVERSION, "2");
+			main.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+			main.putValue(BUNDLE_MANIFESTVERSION, "2");
 
-		boolean noExtraHeaders = "true".equalsIgnoreCase(getProperty(NOEXTRAHEADERS));
+			boolean noExtraHeaders = "true".equalsIgnoreCase(getProperty(NOEXTRAHEADERS));
 
-		if (!noExtraHeaders) {
-			main.putValue(CREATED_BY, System.getProperty("java.version") + " (" + System.getProperty("java.vendor")
-					+ ")");
-			main.putValue(TOOL, "Bnd-" + getBndVersion());
-			main.putValue(BND_LASTMODIFIED, "" + System.currentTimeMillis());
-		}
-
-		String exportHeader = printClauses(exports, true);
-
-		if (exportHeader.length() > 0)
-			main.putValue(EXPORT_PACKAGE, exportHeader);
-		else
-			main.remove(EXPORT_PACKAGE);
-
-		// Remove all the Java packages from the imports
-		if (!imports.isEmpty()) {
-			main.putValue(IMPORT_PACKAGE, printClauses(imports));
-		} else {
-			main.remove(IMPORT_PACKAGE);
-		}
-
-		Packages temp = new Packages(contained);
-		temp.keySet().removeAll(exports.keySet());
-
-		if (!temp.isEmpty())
-			main.putValue(PRIVATE_PACKAGE, printClauses(temp));
-		else
-			main.remove(PRIVATE_PACKAGE);
-
-		Parameters bcp = getBundleClasspath();
-		if (bcp.isEmpty() || (bcp.containsKey(".") && bcp.size() == 1))
-			main.remove(BUNDLE_CLASSPATH);
-		else
-			main.putValue(BUNDLE_CLASSPATH, printClauses(bcp));
-
-		doNamesection(dot, manifest);
-
-		for (Enumeration< ? > h = getProperties().propertyNames(); h.hasMoreElements();) {
-			String header = (String) h.nextElement();
-			if (header.trim().length() == 0) {
-				warning("Empty property set with value: " + getProperties().getProperty(header));
-				continue;
+			if (!noExtraHeaders) {
+				main.putValue(CREATED_BY, System.getProperty("java.version") + " (" + System.getProperty("java.vendor")
+						+ ")");
+				main.putValue(TOOL, "Bnd-" + getBndVersion());
+				main.putValue(BND_LASTMODIFIED, "" + System.currentTimeMillis());
 			}
 
-			if (isMissingPlugin(header.trim())) {
-				error("Missing plugin for command %s", header);
-			}
-			if (!Character.isUpperCase(header.charAt(0))) {
-				if (header.charAt(0) == '@')
-					doNameSection(manifest, header);
-				continue;
-			}
+			String exportHeader = printClauses(exports, true);
 
-			if (header.equals(BUNDLE_CLASSPATH) || header.equals(EXPORT_PACKAGE) || header.equals(IMPORT_PACKAGE))
-				continue;
+			if (exportHeader.length() > 0)
+				main.putValue(EXPORT_PACKAGE, exportHeader);
+			else
+				main.remove(EXPORT_PACKAGE);
 
-			if (header.equalsIgnoreCase("Name")) {
-				error("Your bnd file contains a header called 'Name'. This interferes with the manifest name section.");
-				continue;
-			}
-
-			if (Verifier.HEADER_PATTERN.matcher(header).matches()) {
-				String value = getProperty(header);
-				if (value != null && main.getValue(header) == null) {
-					if (value.trim().length() == 0)
-						main.remove(header);
-					else if (value.trim().equals(EMPTY_HEADER))
-						main.putValue(header, "");
-					else
-						main.putValue(header, value);
-				}
+			// Remove all the Java packages from the imports
+			if (!imports.isEmpty()) {
+				main.putValue(IMPORT_PACKAGE, printClauses(imports));
 			} else {
-				// TODO should we report?
+				main.remove(IMPORT_PACKAGE);
 			}
+
+			Packages temp = new Packages(contained);
+			temp.keySet().removeAll(exports.keySet());
+
+			if (!temp.isEmpty())
+				main.putValue(PRIVATE_PACKAGE, printClauses(temp));
+			else
+				main.remove(PRIVATE_PACKAGE);
+
+			Parameters bcp = getBundleClasspath();
+			if (bcp.isEmpty() || (bcp.containsKey(".") && bcp.size() == 1))
+				main.remove(BUNDLE_CLASSPATH);
+			else
+				main.putValue(BUNDLE_CLASSPATH, printClauses(bcp));
+
+			doNamesection(dot, manifest);
+
+			for (Enumeration< ? > h = getProperties().propertyNames(); h.hasMoreElements();) {
+				String header = (String) h.nextElement();
+				if (header.trim().length() == 0) {
+					warning("Empty property set with value: " + getProperties().getProperty(header));
+					continue;
+				}
+
+				if (isMissingPlugin(header.trim())) {
+					error("Missing plugin for command %s", header);
+				}
+				if (!Character.isUpperCase(header.charAt(0))) {
+					if (header.charAt(0) == '@')
+						doNameSection(manifest, header);
+					continue;
+				}
+
+				if (header.equals(BUNDLE_CLASSPATH) || header.equals(EXPORT_PACKAGE) || header.equals(IMPORT_PACKAGE))
+					continue;
+
+				if (header.equalsIgnoreCase("Name")) {
+					error("Your bnd file contains a header called 'Name'. This interferes with the manifest name section.");
+					continue;
+				}
+
+				if (Verifier.HEADER_PATTERN.matcher(header).matches()) {
+					String value = getProperty(header);
+					if (value != null && main.getValue(header) == null) {
+						if (value.trim().length() == 0)
+							main.remove(header);
+						else if (value.trim().equals(EMPTY_HEADER))
+							main.putValue(header, "");
+						else
+							main.putValue(header, value);
+					}
+				} else {
+					// TODO should we report?
+				}
+			}
+
+			// Copy old values into new manifest, when they
+			// exist in the old one, but not in the new one
+			merge(manifest, dot.getManifest());
+
+			//
+			// Calculate the bundle symbolic name if it is
+			// not set.
+			// 1. set
+			// 2. name of properties file (must be != bnd.bnd)
+			// 3. name of directory, which is usualy project name
+			//
+			String bsn = getBsn();
+			if (main.getValue(BUNDLE_SYMBOLICNAME) == null) {
+				main.putValue(BUNDLE_SYMBOLICNAME, bsn);
+			}
+
+			//
+			// Use the same name for the bundle name as BSN when
+			// the bundle name is not set
+			//
+			if (main.getValue(BUNDLE_NAME) == null) {
+				main.putValue(BUNDLE_NAME, bsn);
+			}
+
+			if (main.getValue(BUNDLE_VERSION) == null)
+				main.putValue(BUNDLE_VERSION, "0");
+
+			// Remove all the headers mentioned in -removeheaders
+			Instructions instructions = new Instructions(getProperty(REMOVEHEADERS));
+			Collection<Object> result = instructions.select(main.keySet(), false);
+			main.keySet().removeAll(result);
+
+			// We should not set the manifest here, this is in general done
+			// by the caller.
+			// dot.setManifest(manifest);
+			return manifest;
 		}
-
-		// Copy old values into new manifest, when they
-		// exist in the old one, but not in the new one
-		merge(manifest, dot.getManifest());
-
-		//
-		// Calculate the bundle symbolic name if it is
-		// not set.
-		// 1. set
-		// 2. name of properties file (must be != bnd.bnd)
-		// 3. name of directory, which is usualy project name
-		//
-		String bsn = getBsn();
-		if (main.getValue(BUNDLE_SYMBOLICNAME) == null) {
-			main.putValue(BUNDLE_SYMBOLICNAME, bsn);
+		catch (Exception e) {
+			// This should not really happen. The code should never throw
+			// exceptions in normal situations. So if it happens we need more
+			// information. So to help diagnostics. We do a full property dump
+			throw new IllegalStateException("Calc manifest failed, state=\n"+getFlattenedProperties(), e);
 		}
-
-		//
-		// Use the same name for the bundle name as BSN when
-		// the bundle name is not set
-		//
-		if (main.getValue(BUNDLE_NAME) == null) {
-			main.putValue(BUNDLE_NAME, bsn);
-		}
-
-		if (main.getValue(BUNDLE_VERSION) == null)
-			main.putValue(BUNDLE_VERSION, "0");
-
-		// Remove all the headers mentioned in -removeheaders
-		Instructions instructions = new Instructions(getProperty(REMOVEHEADERS));
-		Collection<Object> result = instructions.select(main.keySet(), false);
-		main.keySet().removeAll(result);
-
-		// We should not set the manifest here, this is in general done
-		// by the caller.
-		// dot.setManifest(manifest);
-		return manifest;
 	}
 
 	/**
@@ -1009,6 +1017,13 @@
 			PackageRef next = i.next();
 			Collection<PackageRef> usedByExportedPackage = this.uses.get(next);
 
+			// We had an NPE on usedByExportedPackage in GF.
+			// I guess this can happen with hard coded
+			// imports that do not match reality ...
+			if (usedByExportedPackage == null || usedByExportedPackage.isEmpty()) {
+				continue;
+			}
+
 			for (PackageRef privatePackage : privatePackages) {
 				if (usedByExportedPackage.contains(privatePackage)) {
 					i.remove();
@@ -2509,21 +2524,22 @@
 
 	/**
 	 * Create a cross reference from package source, to packages in dest
+	 * 
 	 * @param source
 	 * @param dest
 	 * @param sourceModifiers
 	 * @return
 	 * @throws Exception
 	 */
-	public Map<Clazz.Def, List<TypeRef>> getXRef(final PackageRef source, final Collection<PackageRef> dest, final int sourceModifiers)
-			throws Exception {
-		final MultiMap<Clazz.Def,TypeRef> xref = new MultiMap<Clazz.Def, TypeRef>(Clazz.Def.class, TypeRef.class, true);
+	public Map<Clazz.Def,List<TypeRef>> getXRef(final PackageRef source, final Collection<PackageRef> dest,
+			final int sourceModifiers) throws Exception {
+		final MultiMap<Clazz.Def,TypeRef> xref = new MultiMap<Clazz.Def,TypeRef>(Clazz.Def.class, TypeRef.class, true);
 
 		for (final Clazz clazz : getClassspace().values()) {
 			if ((clazz.accessx & sourceModifiers) == 0)
 				continue;
 
-			if (source!=null && source != clazz.getClassName().getPackageRef())
+			if (source != null && source != clazz.getClassName().getPackageRef())
 				continue;
 
 			clazz.parseClassFileWithCollector(new ClassDataCollector() {
diff --git a/bundleplugin/src/main/java/aQute/bnd/osgi/Builder.java b/bundleplugin/src/main/java/aQute/bnd/osgi/Builder.java
index d6fa2ba..912bad3 100755
--- a/bundleplugin/src/main/java/aQute/bnd/osgi/Builder.java
+++ b/bundleplugin/src/main/java/aQute/bnd/osgi/Builder.java
@@ -770,8 +770,8 @@
 			extractFromJar(jar, source.substring(1), parts.length == 1 ? "" : destination, absentIsOk);
 		} else if (extra.containsKey("cmd")) {
 			doCommand(jar, source, destination, extra, preprocess, absentIsOk);
-		} else if (extra.containsKey("literal")) {
-			String literal = extra.get("literal");
+		} else if (extra.containsKey(LITERAL_ATTRIBUTE)) {
+			String literal = extra.get(LITERAL_ATTRIBUTE);
 			Resource r = new EmbeddedResource(literal.getBytes("UTF-8"), 0);
 			String x = extra.get("extra");
 			if (x != null)
diff --git a/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java b/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java
index 230c717..34d60c6 100644
--- a/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java
+++ b/bundleplugin/src/main/java/aQute/bnd/osgi/Constants.java
@@ -194,6 +194,7 @@
 	String							PATH_DIRECTIVE								= "path:";
 	String							SIZE_ATTRIBUTE								= "size";
 	String							LINK_ATTRIBUTE								= "link";
+	String							LITERAL_ATTRIBUTE							= "literal";
 	String							NAME_ATTRIBUTE								= "name";
 	String							DESCRIPTION_ATTRIBUTE						= "description";
 	String							OSNAME_ATTRIBUTE							= "osname";
@@ -219,7 +220,7 @@
 			SPLIT_PACKAGE_DIRECTIVE, NO_IMPORT_DIRECTIVE, IMPORT_DIRECTIVE, RESOLUTION_DIRECTIVE, INCLUDE_DIRECTIVE,
 			USES_DIRECTIVE, EXCLUDE_DIRECTIVE, KEYSTORE_LOCATION_DIRECTIVE, KEYSTORE_PROVIDER_DIRECTIVE,
 			KEYSTORE_PASSWORD_DIRECTIVE, SIGN_PASSWORD_DIRECTIVE, COMMAND_DIRECTIVE, NOANNOTATIONS, LIB_DIRECTIVE,
-			RUNPATH_LAUNCHER_DIRECTIVE, FROM_DIRECTIVE, PRIVATE_DIRECTIVE
+			RUNPATH_LAUNCHER_DIRECTIVE, FROM_DIRECTIVE, PRIVATE_DIRECTIVE, LITERAL_ATTRIBUTE
 
 																				// TODO
 																				};
@@ -290,7 +291,7 @@
 	public final static String		COMPONENT_ACTIVATE							= "activate:";
 	public final static String		COMPONENT_DEACTIVATE						= "deactivate:";
 
-	public final static String			COMPONENT_NAMESPACE				 		= "xmlns:";
+	public final static String		COMPONENT_NAMESPACE							= "xmlns:";
 
 	final static Map<String,String>	EMPTY										= Collections.emptyMap();
 
@@ -313,11 +314,6 @@
 																						COMPONENT_ACTIVATE,
 																						COMPONENT_DEACTIVATE));
 
-	public final static Set<String>		SET_COMPONENT_DIRECTIVES_1_2				= new HashSet<String>(
-																							Arrays.asList(COMPONENT_GREEDY));
+	public final static Set<String>	SET_COMPONENT_DIRECTIVES_1_2				= new HashSet<String>(
+																						Arrays.asList(COMPONENT_GREEDY));
 }
-
-
-
-
-
diff --git a/bundleplugin/src/main/java/aQute/bnd/service/repository/MinimalRepository.java b/bundleplugin/src/main/java/aQute/bnd/service/repository/MinimalRepository.java
new file mode 100644
index 0000000..bbc0593
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/bnd/service/repository/MinimalRepository.java
@@ -0,0 +1,24 @@
+package aQute.bnd.service.repository;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import aQute.bnd.version.*;
+import aQute.service.reporter.*;
+
+public interface MinimalRepository {
+	public enum Gestalt {
+		ADD, REMOTE
+	};
+
+	Report add(File f) throws Exception;
+
+	Iterable<String> list(String globbing);
+
+	List<Version> versions(String bsn);
+
+	Future<File> get(String bsn, Version version, Map<String,String> attrs);
+	
+	boolean is(Gestalt gestalt);
+}
diff --git a/bundleplugin/src/main/java/aQute/lib/collections/ExtList.java b/bundleplugin/src/main/java/aQute/lib/collections/ExtList.java
index 4943d92..48e1732 100644
--- a/bundleplugin/src/main/java/aQute/lib/collections/ExtList.java
+++ b/bundleplugin/src/main/java/aQute/lib/collections/ExtList.java
@@ -16,6 +16,10 @@
 		super(size);
 	}
 
+	public ExtList(Collection<T> _) {
+		super(_);
+	}
+
 	public static ExtList<String> from(String s) {
 		// TODO make sure no \ before comma
 		return from(s, "\\s*,\\s*");
diff --git a/bundleplugin/src/main/java/aQute/libg/reporter/ReporterAdapter.java b/bundleplugin/src/main/java/aQute/libg/reporter/ReporterAdapter.java
index e08c569..d233631 100644
--- a/bundleplugin/src/main/java/aQute/libg/reporter/ReporterAdapter.java
+++ b/bundleplugin/src/main/java/aQute/libg/reporter/ReporterAdapter.java
@@ -113,7 +113,10 @@
 	}
 
 	public SetLocation exception(Throwable t, String s, Object... args) {
-		String e = String.format(s, args);
+		StackTraceElement[] stackTrace = t.getStackTrace();
+		String method = stackTrace[0].getMethodName();
+		String cname = stackTrace[0].getClassName();
+		String e = String.format("["+shorten(cname) +"."+method+"] " +s, args);
 		errors.add(e);
 		trace("ERROR: %s", e);
 		if (isExceptions() || isTrace())
@@ -124,6 +127,14 @@
 		return location(e);
 	}
 
+	private String shorten(String cname) {
+		int index = cname.lastIndexOf('$');
+		if ( index < 0)
+			index = cname.lastIndexOf('.');
+		
+		return cname.substring(index+1);
+	}
+
 	public SetLocation warning(String s, Object... args) {
 		String e = String.format(s, args);
 		warnings.add(e);