blob: 8daaee7deb4177f3dbd33615244672fd5bffb6e3 [file] [log] [blame]
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001package aQute.bnd.header;
Stuart McCullochbb014372012-06-07 21:57:32 +00002
3import java.util.*;
4import java.util.regex.*;
5
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00006import aQute.bnd.osgi.*;
Stuart McCullochbb014372012-06-07 21:57:32 +00007import aQute.lib.collections.*;
Stuart McCullochbb014372012-06-07 21:57:32 +00008
Stuart McCulloch2286f232012-06-15 13:27:53 +00009public class Attrs implements Map<String,String> {
Stuart McCullochbb014372012-06-07 21:57:32 +000010 public enum Type {
Stuart McCulloch2286f232012-06-15 13:27:53 +000011 STRING(null), LONG(null), VERSION(null), DOUBLE(null), STRINGS(STRING), LONGS(LONG), VERSIONS(VERSION), DOUBLES(
12 DOUBLE);
Stuart McCullochbb014372012-06-07 21:57:32 +000013
14 Type sub;
15
16 Type(Type sub) {
17 this.sub = sub;
18 }
19
20 }
21
22 /**
23 * <pre>
24 * Provide-Capability ::= capability ::=
25 * name-space ::= typed-attr ::= type ::= scalar ::=
26 * capability ( ',' capability )*
27 * name-space
28 * ( ’;’ directive | typed-attr )*
29 * symbolic-name
30 * extended ( ’:’ type ) ’=’ argument
31 * scalar | list
32 * ’String’ | ’Version’ | ’Long’
33 * list ::=
34 * ’List<’ scalar ’>’
35 * </pre>
36 */
Stuart McCulloch2286f232012-06-15 13:27:53 +000037 static String EXTENDED = "[\\-0-9a-zA-Z\\._]+";
38 static String SCALAR = "String|Version|Long|Double";
39 static String LIST = "List\\s*<\\s*(" + SCALAR + ")\\s*>";
40 public static final Pattern TYPED = Pattern.compile("\\s*(" + EXTENDED + ")\\s*:\\s*(" + SCALAR
41 + "|" + LIST + ")\\s*");
Stuart McCullochbb014372012-06-07 21:57:32 +000042
Stuart McCulloch2286f232012-06-15 13:27:53 +000043 private LinkedHashMap<String,String> map;
44 private Map<String,Type> types;
45 static Map<String,String> EMPTY = Collections.emptyMap();
Stuart McCullochbb014372012-06-07 21:57:32 +000046
47 public Attrs(Attrs... attrs) {
48 for (Attrs a : attrs) {
49 if (a != null) {
50 putAll(a);
51 }
52 }
53 }
54
55 public void clear() {
56 map.clear();
57 }
58
59 public boolean containsKey(String name) {
60 if (map == null)
61 return false;
62
63 return map.containsKey(name);
64 }
65
66 @SuppressWarnings("cast")
Stuart McCulloch2286f232012-06-15 13:27:53 +000067 @Deprecated
68 public boolean containsKey(Object name) {
Stuart McCullochbb014372012-06-07 21:57:32 +000069 assert name instanceof String;
70 if (map == null)
71 return false;
72
73 return map.containsKey((String) name);
74 }
75
76 public boolean containsValue(String value) {
77 if (map == null)
78 return false;
79
80 return map.containsValue(value);
81 }
82
83 @SuppressWarnings("cast")
Stuart McCulloch2286f232012-06-15 13:27:53 +000084 @Deprecated
85 public boolean containsValue(Object value) {
Stuart McCullochbb014372012-06-07 21:57:32 +000086 assert value instanceof String;
87 if (map == null)
88 return false;
89
90 return map.containsValue((String) value);
91 }
92
Stuart McCulloch2286f232012-06-15 13:27:53 +000093 public Set<java.util.Map.Entry<String,String>> entrySet() {
Stuart McCullochbb014372012-06-07 21:57:32 +000094 if (map == null)
95 return EMPTY.entrySet();
96
97 return map.entrySet();
98 }
99
100 @SuppressWarnings("cast")
Stuart McCulloch2286f232012-06-15 13:27:53 +0000101 @Deprecated
102 public String get(Object key) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000103 assert key instanceof String;
104 if (map == null)
105 return null;
106
107 return map.get((String) key);
108 }
109
110 public String get(String key) {
111 if (map == null)
112 return null;
113
114 return map.get(key);
115 }
116
117 public String get(String key, String deflt) {
118 String s = get(key);
119 if (s == null)
120 return deflt;
121 return s;
122 }
123
124 public boolean isEmpty() {
125 return map == null || map.isEmpty();
126 }
127
128 public Set<String> keySet() {
129 if (map == null)
130 return EMPTY.keySet();
131
132 return map.keySet();
133 }
134
135 public String put(String key, String value) {
136 if (map == null)
Stuart McCulloch2286f232012-06-15 13:27:53 +0000137 map = new LinkedHashMap<String,String>();
Stuart McCullochbb014372012-06-07 21:57:32 +0000138
139 Matcher m = TYPED.matcher(key);
140 if (m.matches()) {
141 key = m.group(1);
142 String type = m.group(2);
143 Type t = Type.STRING;
144
Stuart McCulloch2286f232012-06-15 13:27:53 +0000145 if (type.startsWith("List")) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000146 type = m.group(3);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000147 if ("String".equals(type))
Stuart McCullochbb014372012-06-07 21:57:32 +0000148 t = Type.STRINGS;
Stuart McCulloch2286f232012-06-15 13:27:53 +0000149 else if ("Long".equals(type))
Stuart McCullochbb014372012-06-07 21:57:32 +0000150 t = Type.LONGS;
Stuart McCulloch2286f232012-06-15 13:27:53 +0000151 else if ("Double".equals(type))
Stuart McCullochbb014372012-06-07 21:57:32 +0000152 t = Type.DOUBLES;
Stuart McCulloch2286f232012-06-15 13:27:53 +0000153 else if ("Version".equals(type))
154 t = Type.VERSIONS;
Stuart McCullochbb014372012-06-07 21:57:32 +0000155 } else {
Stuart McCulloch2286f232012-06-15 13:27:53 +0000156 if ("String".equals(type))
Stuart McCullochbb014372012-06-07 21:57:32 +0000157 t = Type.STRING;
Stuart McCulloch2286f232012-06-15 13:27:53 +0000158 else if ("Long".equals(type))
Stuart McCullochbb014372012-06-07 21:57:32 +0000159 t = Type.LONG;
Stuart McCulloch2286f232012-06-15 13:27:53 +0000160 else if ("Double".equals(type))
Stuart McCullochbb014372012-06-07 21:57:32 +0000161 t = Type.DOUBLE;
Stuart McCulloch2286f232012-06-15 13:27:53 +0000162 else if ("Version".equals(type))
Stuart McCullochbb014372012-06-07 21:57:32 +0000163 t = Type.VERSION;
164 }
165 if (types == null)
Stuart McCulloch2286f232012-06-15 13:27:53 +0000166 types = new LinkedHashMap<String,Type>();
Stuart McCullochbb014372012-06-07 21:57:32 +0000167 types.put(key, t);
168
169 // TODO verify value?
170 }
171
172 return map.put(key, value);
173 }
174
175 public Type getType(String key) {
176 if (types == null)
177 return Type.STRING;
178 Type t = types.get(key);
179 if (t == null)
180 return Type.STRING;
181 return t;
182 }
183
Stuart McCulloch2286f232012-06-15 13:27:53 +0000184 public void putAll(Map< ? extends String, ? extends String> map) {
185 for (Map.Entry< ? extends String, ? extends String> e : map.entrySet())
Stuart McCullochbb014372012-06-07 21:57:32 +0000186 put(e.getKey(), e.getValue());
187 }
188
189 @SuppressWarnings("cast")
Stuart McCulloch2286f232012-06-15 13:27:53 +0000190 @Deprecated
191 public String remove(Object var0) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000192 assert var0 instanceof String;
193 if (map == null)
194 return null;
195
196 return map.remove((String) var0);
197 }
198
199 public String remove(String var0) {
200 if (map == null)
201 return null;
202 return map.remove(var0);
203 }
204
205 public int size() {
206 if (map == null)
207 return 0;
208 return map.size();
209 }
210
211 public Collection<String> values() {
212 if (map == null)
213 return EMPTY.values();
214
215 return map.values();
216 }
217
218 public String getVersion() {
219 return get("version");
220 }
221
222 public String toString() {
223 StringBuilder sb = new StringBuilder();
224 append(sb);
225 return sb.toString();
226 }
227
228 public void append(StringBuilder sb) {
229 String del = "";
Stuart McCulloch2286f232012-06-15 13:27:53 +0000230 for (Map.Entry<String,String> e : entrySet()) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000231 sb.append(del);
232 sb.append(e.getKey());
233 sb.append("=");
234 sb.append(e.getValue());
235 del = ";";
236 }
237 }
238
Stuart McCulloch2286f232012-06-15 13:27:53 +0000239 @Deprecated
240 public boolean equals(Object other) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000241 return super.equals(other);
242 }
243
Stuart McCulloch2286f232012-06-15 13:27:53 +0000244 @Deprecated
245 public int hashCode() {
Stuart McCullochbb014372012-06-07 21:57:32 +0000246 return super.hashCode();
247 }
248
249 public boolean isEqual(Attrs o) {
250 if (this == o)
251 return true;
252
253 Attrs other = o;
254
255 if (size() != other.size())
256 return false;
257
258 if (isEmpty())
259 return true;
260
261 SortedList<String> l = new SortedList<String>(keySet());
262 SortedList<String> lo = new SortedList<String>(other.keySet());
263 if (!l.isEqual(lo))
264 return false;
265
266 for (String key : keySet()) {
267 if (!get(key).equals(other.get(key)))
268 return false;
269 }
270 return true;
271
272 }
273
274 public Object getTyped(String adname) {
275 String s = get(adname);
276 if (s == null)
277 return null;
278
279 Type t = getType(adname);
280 return convert(t, s);
281 }
282
283 private Object convert(Type t, String s) {
284 if (t.sub == null) {
285 switch (t) {
Stuart McCulloch2286f232012-06-15 13:27:53 +0000286 case STRING :
287 return s;
288 case LONG :
289 return Long.parseLong(s.trim());
290 case VERSION :
291 return Version.parseVersion(s);
Stuart McCullochffa8aaf2012-06-17 20:38:35 +0000292 case DOUBLE :
293 return Double.parseDouble(s.trim());
294
295 case DOUBLES :
296 case LONGS :
297 case STRINGS :
298 case VERSIONS :
299 // Cannot happen since the sub is null
300 return null;
Stuart McCullochbb014372012-06-07 21:57:32 +0000301 }
302 return null;
303 }
304 List<Object> list = new ArrayList<Object>();
305 String split[] = s.split("\\s*\\(\\?!\\),\\s*");
306 for (String p : split) {
307 p = p.replaceAll("\\\\", "");
308 list.add(convert(t.sub, p));
309 }
310 return list;
311 }
312}