Use local copy of latest bndlib code for pre-release testing purposes
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1347815 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundleplugin/src/main/java/aQute/libg/header/Attrs.java b/bundleplugin/src/main/java/aQute/libg/header/Attrs.java
new file mode 100644
index 0000000..d11b6d1
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/header/Attrs.java
@@ -0,0 +1,295 @@
+package aQute.libg.header;
+
+import java.util.*;
+import java.util.regex.*;
+
+import aQute.lib.collections.*;
+import aQute.libg.version.*;
+
+public class Attrs implements Map<String, String> {
+ public enum Type {
+ STRING(null), LONG(null), VERSION(null), DOUBLE(null), STRINGS(STRING), LONGS(LONG), VERSIONS(VERSION), DOUBLES(DOUBLE);
+
+ Type sub;
+
+ Type(Type sub) {
+ this.sub = sub;
+ }
+
+ }
+
+ /**
+ * <pre>
+ * Provide-Capability ::= capability ::=
+ * name-space ::= typed-attr ::= type ::= scalar ::=
+ * capability ( ',' capability )*
+ * name-space
+ * ( ’;’ directive | typed-attr )*
+ * symbolic-name
+ * extended ( ’:’ type ) ’=’ argument
+ * scalar | list
+ * ’String’ | ’Version’ | ’Long’
+ * list ::=
+ * ’List<’ scalar ’>’
+ * </pre>
+ */
+ static String EXTENDED = "[\\-0-9a-zA-Z\\._]+";
+ static String SCALAR = "String|Version|Long|Double";
+ static String LIST = "List\\s*<\\s*(" + SCALAR + ")\\s*>";
+ public static final Pattern TYPED = Pattern.compile("\\s*(" + EXTENDED + ")\\s*:\\s*("+ SCALAR + "|" + LIST + ")\\s*");
+
+ private LinkedHashMap<String, String> map;
+ private Map<String, Type> types;
+ static Map<String, String> EMPTY = Collections.emptyMap();
+
+ public Attrs(Attrs... attrs) {
+ for (Attrs a : attrs) {
+ if (a != null) {
+ putAll(a);
+ }
+ }
+ }
+
+ public void clear() {
+ map.clear();
+ }
+
+ public boolean containsKey(String name) {
+ if (map == null)
+ return false;
+
+ return map.containsKey(name);
+ }
+
+ @SuppressWarnings("cast")
+ @Deprecated public boolean containsKey(Object name) {
+ assert name instanceof String;
+ if (map == null)
+ return false;
+
+ return map.containsKey((String) name);
+ }
+
+ public boolean containsValue(String value) {
+ if (map == null)
+ return false;
+
+ return map.containsValue(value);
+ }
+
+ @SuppressWarnings("cast")
+ @Deprecated public boolean containsValue(Object value) {
+ assert value instanceof String;
+ if (map == null)
+ return false;
+
+ return map.containsValue((String) value);
+ }
+
+ public Set<java.util.Map.Entry<String, String>> entrySet() {
+ if (map == null)
+ return EMPTY.entrySet();
+
+ return map.entrySet();
+ }
+
+ @SuppressWarnings("cast")
+ @Deprecated public String get(Object key) {
+ assert key instanceof String;
+ if (map == null)
+ return null;
+
+ return map.get((String) key);
+ }
+
+ public String get(String key) {
+ if (map == null)
+ return null;
+
+ return map.get(key);
+ }
+
+ public String get(String key, String deflt) {
+ String s = get(key);
+ if (s == null)
+ return deflt;
+ return s;
+ }
+
+ public boolean isEmpty() {
+ return map == null || map.isEmpty();
+ }
+
+ public Set<String> keySet() {
+ if (map == null)
+ return EMPTY.keySet();
+
+ return map.keySet();
+ }
+
+ public String put(String key, String value) {
+ if (map == null)
+ map = new LinkedHashMap<String, String>();
+
+ Matcher m = TYPED.matcher(key);
+ if (m.matches()) {
+ key = m.group(1);
+ String type = m.group(2);
+ Type t = Type.STRING;
+
+ if ( type.startsWith("List")) {
+ type = m.group(3);
+ if ( "String".equals(type))
+ t = Type.STRINGS;
+ else if ( "Long".equals(type))
+ t = Type.LONGS;
+ else if ( "Double".equals(type))
+ t = Type.DOUBLES;
+ else if ( "Version".equals(type))
+ t = Type.VERSIONS;
+ } else {
+ if ( "String".equals(type))
+ t = Type.STRING;
+ else if ( "Long".equals(type))
+ t = Type.LONG;
+ else if ( "Double".equals(type))
+ t = Type.DOUBLE;
+ else if ( "Version".equals(type))
+ t = Type.VERSION;
+ }
+ if (types == null)
+ types = new LinkedHashMap<String, Type>();
+ types.put(key, t);
+
+ // TODO verify value?
+ }
+
+ return map.put(key, value);
+ }
+
+ public Type getType(String key) {
+ if (types == null)
+ return Type.STRING;
+ Type t = types.get(key);
+ if (t == null)
+ return Type.STRING;
+ return t;
+ }
+
+ public void putAll(Map<? extends String, ? extends String> map) {
+ for (Map.Entry<? extends String, ? extends String> e : map.entrySet())
+ put(e.getKey(), e.getValue());
+ }
+
+ @SuppressWarnings("cast")
+ @Deprecated public String remove(Object var0) {
+ assert var0 instanceof String;
+ if (map == null)
+ return null;
+
+ return map.remove((String) var0);
+ }
+
+ public String remove(String var0) {
+ if (map == null)
+ return null;
+ return map.remove(var0);
+ }
+
+ public int size() {
+ if (map == null)
+ return 0;
+ return map.size();
+ }
+
+ public Collection<String> values() {
+ if (map == null)
+ return EMPTY.values();
+
+ return map.values();
+ }
+
+ public String getVersion() {
+ return get("version");
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ append(sb);
+ return sb.toString();
+ }
+
+ public void append(StringBuilder sb) {
+ String del = "";
+ for (Map.Entry<String, String> e : entrySet()) {
+ sb.append(del);
+ sb.append(e.getKey());
+ sb.append("=");
+ sb.append(e.getValue());
+ del = ";";
+ }
+ }
+
+ @Deprecated public boolean equals(Object other) {
+ return super.equals(other);
+ }
+
+ @Deprecated public int hashCode() {
+ return super.hashCode();
+ }
+
+ public boolean isEqual(Attrs o) {
+ if (this == o)
+ return true;
+
+ Attrs other = o;
+
+ if (size() != other.size())
+ return false;
+
+ if (isEmpty())
+ return true;
+
+ SortedList<String> l = new SortedList<String>(keySet());
+ SortedList<String> lo = new SortedList<String>(other.keySet());
+ if (!l.isEqual(lo))
+ return false;
+
+ for (String key : keySet()) {
+ if (!get(key).equals(other.get(key)))
+ return false;
+ }
+ return true;
+
+ }
+
+ public Object getTyped(String adname) {
+ String s = get(adname);
+ if (s == null)
+ return null;
+
+ Type t = getType(adname);
+ return convert(t, s);
+ }
+
+ private Object convert(Type t, String s) {
+ if (t.sub == null) {
+ switch (t) {
+ case STRING:
+ return s;
+ case LONG:
+ return Long.parseLong(s.trim());
+ case VERSION:
+ return Version.parseVersion(s);
+ }
+ return null;
+ }
+ List<Object> list = new ArrayList<Object>();
+ String split[] = s.split("\\s*\\(\\?!\\),\\s*");
+ for (String p : split) {
+ p = p.replaceAll("\\\\", "");
+ list.add(convert(t.sub, p));
+ }
+ return list;
+ }
+}
diff --git a/bundleplugin/src/main/java/aQute/libg/header/OSGiHeader.java b/bundleplugin/src/main/java/aQute/libg/header/OSGiHeader.java
new file mode 100755
index 0000000..7b26f6f
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/header/OSGiHeader.java
@@ -0,0 +1,138 @@
+package aQute.libg.header;
+
+import java.util.*;
+
+import aQute.libg.generics.*;
+import aQute.libg.qtokens.*;
+import aQute.libg.reporter.*;
+
+public class OSGiHeader {
+
+ static public Parameters parseHeader(String value) {
+ return parseHeader(value, null);
+ }
+
+ /**
+ * Standard OSGi header parser. This parser can handle the format clauses
+ * ::= clause ( ',' clause ) + clause ::= name ( ';' name ) (';' key '='
+ * value )
+ *
+ * This is mapped to a Map { name => Map { attr|directive => value } }
+ *
+ * @param value
+ * A string
+ * @return a Map<String,Map<String,String>>
+ */
+ static public Parameters parseHeader(String value, Reporter logger) {
+ return parseHeader(value, logger, new Parameters());
+ }
+
+ static public Parameters parseHeader(String value, Reporter logger, Parameters result) {
+ if (value == null || value.trim().length() == 0)
+ return result;
+
+ QuotedTokenizer qt = new QuotedTokenizer(value, ";=,");
+ char del = 0;
+ do {
+ boolean hadAttribute = false;
+ Attrs clause = new Attrs();
+ List<String> aliases = Create.list();
+ String name = qt.nextToken(",;");
+
+ del = qt.getSeparator();
+ if (name == null || name.length() == 0) {
+ if (logger != null && logger.isPedantic()) {
+ logger.warning("Empty clause, usually caused by repeating a comma without any name field or by having spaces after the backslash of a property file: "
+ + value);
+ }
+ if (name == null)
+ break;
+ } else {
+ name = name.trim();
+
+ aliases.add(name);
+ while (del == ';') {
+ String adname = qt.nextToken();
+ if ((del = qt.getSeparator()) != '=') {
+ if (hadAttribute)
+ if (logger != null) {
+ logger.error("Header contains name field after attribute or directive: "
+ + adname
+ + " from "
+ + value
+ + ". Name fields must be consecutive, separated by a ';' like a;b;c;x=3;y=4");
+ }
+ if (adname != null && adname.length() > 0)
+ aliases.add(adname.trim());
+ } else {
+ String advalue = qt.nextToken();
+ if (clause.containsKey(adname)) {
+ if (logger != null && logger.isPedantic())
+ logger.warning("Duplicate attribute/directive name " + adname
+ + " in " + value
+ + ". This attribute/directive will be ignored");
+ }
+ if (advalue == null) {
+ if (logger != null)
+ logger.error("No value after '=' sign for attribute " + adname);
+ advalue = "";
+ }
+ clause.put(adname.trim(), advalue.trim());
+ del = qt.getSeparator();
+ hadAttribute = true;
+ }
+ }
+
+ // Check for duplicate names. The aliases list contains
+ // the list of nams, for each check if it exists. If so,
+ // add a number of "~" to make it unique.
+ for (String clauseName : aliases) {
+ if (result.containsKey(clauseName)) {
+ if (logger != null && logger.isPedantic())
+ logger.warning("Duplicate name "
+ + clauseName
+ + " used in header: '"
+ + clauseName
+ + "'. Duplicate names are specially marked in Bnd with a ~ at the end (which is stripped at printing time).");
+ while (result.containsKey(clauseName))
+ clauseName += "~";
+ }
+ result.put(clauseName, clause);
+ }
+ }
+ } while (del == ',');
+ return result;
+ }
+
+ public static Attrs parseProperties(String input) {
+ return parseProperties(input, null);
+ }
+
+ public static Attrs parseProperties(String input, Reporter logger) {
+ if (input == null || input.trim().length() == 0)
+ return new Attrs();
+
+ Attrs result = new Attrs();
+ QuotedTokenizer qt = new QuotedTokenizer(input, "=,");
+ char del = ',';
+
+ while (del == ',') {
+ String key = qt.nextToken(",=");
+ String value = "";
+ del = qt.getSeparator();
+ if (del == '=') {
+ value = qt.nextToken(",=");
+ del = qt.getSeparator();
+ }
+ result.put(key, value);
+ }
+ if (del != 0) {
+ if (logger == null)
+ throw new IllegalArgumentException("Invalid syntax for properties: " + input);
+ logger.error("Invalid syntax for properties: " + input);
+ }
+
+ return result;
+ }
+
+}
diff --git a/bundleplugin/src/main/java/aQute/libg/header/Parameters.java b/bundleplugin/src/main/java/aQute/libg/header/Parameters.java
new file mode 100644
index 0000000..96f0d08
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/header/Parameters.java
@@ -0,0 +1,203 @@
+package aQute.libg.header;
+
+import java.util.*;
+
+import aQute.lib.collections.*;
+import aQute.libg.reporter.*;
+
+public class Parameters implements Map<String, Attrs> {
+ private LinkedHashMap<String, Attrs> map;
+ static Map<String, Attrs> EMPTY = Collections.emptyMap();
+ String error;
+
+ public Parameters() {
+ }
+
+ public Parameters(String header) {
+ OSGiHeader.parseHeader(header, null, this);
+ }
+
+ public Parameters(String header, Reporter reporter) {
+ OSGiHeader.parseHeader(header, reporter, this);
+ }
+
+ public void clear() {
+ map.clear();
+ }
+
+ public boolean containsKey(final String name) {
+ if (map == null)
+ return false;
+
+ return map.containsKey(name);
+ }
+
+ @SuppressWarnings("cast")
+ @Deprecated public boolean containsKey(Object name) {
+ assert name instanceof String;
+ if (map == null)
+ return false;
+
+ return map.containsKey((String) name);
+ }
+
+ public boolean containsValue(Attrs value) {
+ if (map == null)
+ return false;
+
+ return map.containsValue(value);
+ }
+
+ @SuppressWarnings("cast")
+ @Deprecated public boolean containsValue(Object value) {
+ assert value instanceof Attrs;
+ if (map == null)
+ return false;
+
+ return map.containsValue((Attrs) value);
+ }
+
+ public Set<java.util.Map.Entry<String, Attrs>> entrySet() {
+ if (map == null)
+ return EMPTY.entrySet();
+
+ return map.entrySet();
+ }
+
+ @SuppressWarnings("cast")
+ @Deprecated public Attrs get(Object key) {
+ assert key instanceof String;
+ if (map == null)
+ return null;
+
+ return map.get((String) key);
+ }
+
+ public Attrs get(String key) {
+ if (map == null)
+ return null;
+
+ return map.get(key);
+ }
+
+ public boolean isEmpty() {
+ return map == null || map.isEmpty();
+ }
+
+ public Set<String> keySet() {
+ if (map == null)
+ return EMPTY.keySet();
+
+ return map.keySet();
+ }
+
+ public Attrs put(String key, Attrs value) {
+ assert key != null;
+ assert value != null;
+
+ if (map == null)
+ map = new LinkedHashMap<String, Attrs>();
+
+ return map.put(key, value);
+ }
+
+ public void putAll(Map<? extends String, ? extends Attrs> map) {
+ if (this.map == null) {
+ if (map.isEmpty())
+ return;
+ this.map = new LinkedHashMap<String, Attrs>();
+ }
+ this.map.putAll(map);
+ }
+ public void putAllIfAbsent(Map<String, ? extends Attrs> map) {
+ for(Map.Entry<String, ? extends Attrs> entry : map.entrySet() ) {
+ if ( !containsKey(entry.getKey()))
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ @SuppressWarnings("cast")
+ @Deprecated public Attrs remove(Object var0) {
+ assert var0 instanceof String;
+ if (map == null)
+ return null;
+
+ return map.remove((String) var0);
+ }
+
+ public Attrs remove(String var0) {
+ if (map == null)
+ return null;
+ return map.remove(var0);
+ }
+
+ public int size() {
+ if (map == null)
+ return 0;
+ return map.size();
+ }
+
+ public Collection<Attrs> values() {
+ if (map == null)
+ return EMPTY.values();
+
+ return map.values();
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ append(sb);
+ return sb.toString();
+ }
+
+ public void append(StringBuilder sb) {
+ String del = "";
+ for (Map.Entry<String, Attrs> s : entrySet()) {
+ sb.append(del);
+ sb.append(s.getKey());
+ if (!s.getValue().isEmpty()) {
+ sb.append(';');
+ s.getValue().append(sb);
+ }
+
+ del = ",";
+ }
+ }
+
+ @Deprecated
+ public boolean equals(Object other) {
+ return super.equals(other);
+ }
+
+ @Deprecated
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+
+ public boolean isEqual(Parameters other) {
+ if (this == other)
+ return true;
+
+ if (size() != other.size())
+ return false;
+
+ if (isEmpty())
+ return true;
+
+ SortedList<String> l = new SortedList<String>(keySet());
+ SortedList<String> lo = new SortedList<String>(other.keySet());
+ if (!l.isEqual(lo))
+ return false;
+
+ for (String key : keySet()) {
+ if (!get(key).isEqual(other.get(key)))
+ return false;
+ }
+ return true;
+ }
+
+ public Map<String,? extends Map<String,String>> asMapMap() {
+ return this;
+ }
+}
diff --git a/bundleplugin/src/main/java/aQute/libg/header/packageinfo b/bundleplugin/src/main/java/aQute/libg/header/packageinfo
new file mode 100644
index 0000000..e39f616
--- /dev/null
+++ b/bundleplugin/src/main/java/aQute/libg/header/packageinfo
@@ -0,0 +1 @@
+version 1.1.0