aQute.bnd.header.Attrs Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of biz.aQute.bndlib Show documentation
Show all versions of biz.aQute.bndlib Show documentation
bndlib: A Swiss Army Knife for OSGi
package aQute.bnd.header;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import aQute.bnd.version.Version;
public class Attrs implements Map {
public interface DataType {
Type type();
}
public static DataType STRING = new DataType() {
public Type type() {
return Type.STRING;
}
};
public static DataType LONG = new DataType() {
public Type type() {
return Type.LONG;
}
};;
public static DataType DOUBLE = new DataType() {
public Type type() {
return Type.DOUBLE;
}
};;
public static DataType VERSION = new DataType() {
public Type type() {
return Type.VERSION;
}
};;
public static DataType> LIST_STRING = new DataType>() {
public Type type() {
return Type.STRINGS;
}
};;
public static DataType> LIST_LONG = new DataType>() {
public Type type() {
return Type.LONGS;
}
};;
public static DataType> LIST_DOUBLE = new DataType>() {
public Type type() {
return Type.DOUBLES;
}
};;
public static DataType> LIST_VERSION = new DataType>() {
public Type type() {
return Type.VERSIONS;
}
};;
public enum Type {
STRING(null, "String"), LONG(null, "Long"), VERSION(null, "Version"), DOUBLE(null, "Double"), STRINGS(STRING,
"List"), LONGS(LONG, "List"), VERSIONS(VERSION, "List"), DOUBLES(DOUBLE,
"List");
Type sub;
String toString;
Type(Type sub, String toString) {
this.sub = sub;
this.toString = toString;
}
public String toString() {
return toString;
}
public Type plural() {
switch (this) {
case DOUBLE :
return DOUBLES;
case LONG :
return LONGS;
case STRING :
return STRINGS;
case VERSION :
return VERSIONS;
default :
return null;
}
}
}
/**
*
* 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 ’>’
*
*/
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 Map map;
private Map types = new LinkedHashMap();
static Map EMPTY = Collections.emptyMap();
public static Attrs EMPTY_ATTRS = new Attrs();
static {
EMPTY_ATTRS.map = Collections.emptyMap();
}
public Attrs() {}
public Attrs(Attrs... attrs) {
for (Attrs a : attrs) {
if (a != null) {
putAll(a);
if (a.types != null)
types.putAll(a.types);
}
}
}
public void putAllTyped(Map attrs) {
for (Map.Entry entry : attrs.entrySet()) {
Object value = entry.getValue();
String key = entry.getKey();
putTyped(key, value);
}
}
public void putTyped(String key, Object value) {
if (value == null) {
put(key, null);
return;
}
if (!(value instanceof String)) {
Type type;
if (value instanceof Collection)
value = ((Collection< ? >) value).toArray();
if (value.getClass().isArray()) {
type = Type.STRINGS;
int l = Array.getLength(value);
StringBuilder sb = new StringBuilder();
String del = "";
boolean first = true;
for (int i = 0; i < l; i++) {
Object member = Array.get(value, i);
if (member == null) {
// TODO What do we do with null members?
continue;
} else if (first) {
type = getObjectType(member).plural();
first = true;
}
sb.append(del);
int n = sb.length();
sb.append(member);
while (n < sb.length()) {
char c = sb.charAt(n);
if (c == '\\' || c == ',') {
sb.insert(n, '\\');
n++;
}
n++;
}
del = ",";
}
value = sb;
} else {
type = getObjectType(value);
}
key += ":" + type.toString();
}
put(key, value.toString());
}
private Type getObjectType(Object member) {
if (member instanceof Double || member instanceof Float)
return Type.DOUBLE;
if (member instanceof Number)
return Type.LONG;
if (member instanceof Version)
return Type.VERSION;
return Type.STRING;
}
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(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(value);
}
public Set> 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(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 keySet() {
if (map == null)
return EMPTY.keySet();
return map.keySet();
}
public String put(String key, String value) {
if (key == null)
return null;
if (map == null)
map = new LinkedHashMap();
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;
}
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(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 values() {
if (map == null)
return EMPTY.values();
return map.values();
}
public String getVersion() {
return get("version");
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
append(sb);
return sb.toString();
}
public void append(StringBuilder sb) {
try {
String del = "";
for (Map.Entry e : entrySet()) {
sb.append(del);
append(sb, e);
del = ";";
}
} catch (Exception e) {
// Cannot happen
e.printStackTrace();
}
}
public void append(StringBuilder sb, Map.Entry e) throws IOException {
sb.append(e.getKey());
if (types != null) {
Type type = types.get(e.getKey());
if (type != null) {
sb.append(":").append(type);
}
}
sb.append("=");
OSGiHeader.quote(sb, e.getValue());
}
@Override
@Deprecated
public boolean equals(Object other) {
return super.equals(other);
}
@Override
@Deprecated
public int hashCode() {
return super.hashCode();
}
public boolean isEqual(Attrs other) {
if (this == other)
return true;
if (other == null || size() != other.size())
return false;
if (isEmpty())
return true;
TreeSet l = new TreeSet(keySet());
TreeSet lo = new TreeSet(other.keySet());
if (!l.equals(lo))
return false;
for (String key : keySet()) {
String value = get(key);
String valueo = other.get(key);
if (!(value == valueo || (value != null && value.equals(valueo))))
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);
}
@SuppressWarnings("unchecked")
public T getTyped(DataType type, String adname) {
String s = get(adname);
if (s == null)
return null;
Type t = getType(adname);
if (t != type.type())
throw new IllegalArgumentException(
"For key " + adname + ", expected " + type.type() + " but had a " + t + ". Value is " + s);
return (T) convert(t, s);
}
public static Type toType(String type) {
for (Type t : Type.values()) {
if (t.toString.equals(type))
return t;
}
return null;
}
public static Object convert(String t, String s) {
if (s == null)
return null;
Type type = toType(t);
if (type == null)
return s;
return convert(type, s);
}
public static 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);
case DOUBLE :
return Double.parseDouble(s.trim());
case DOUBLES :
case LONGS :
case STRINGS :
case VERSIONS :
// Cannot happen since the sub is null
return null;
}
return null;
}
List