blob: 0124ff1f5d1b1790805eb0a4f6f30fff86ee7c19 [file] [log] [blame]
Stuart McCulloch42151ee2012-07-16 13:43:38 +00001package aQute.bnd.header;
Stuart McCullochf3173222012-06-07 21:57:32 +00002
3import java.util.*;
4import java.util.regex.*;
5
Stuart McCulloch42151ee2012-07-16 13:43:38 +00006import aQute.bnd.osgi.*;
Stuart McCullochcd1ddd72012-07-19 13:11:20 +00007import aQute.bnd.version.*;
Stuart McCullochf3173222012-06-07 21:57:32 +00008import aQute.lib.collections.*;
Stuart McCullochf3173222012-06-07 21:57:32 +00009
Stuart McCulloch4482c702012-06-15 13:27:53 +000010public class Attrs implements Map<String,String> {
Stuart McCullochf3173222012-06-07 21:57:32 +000011 public enum Type {
Stuart McCulloch4482c702012-06-15 13:27:53 +000012 STRING(null), LONG(null), VERSION(null), DOUBLE(null), STRINGS(STRING), LONGS(LONG), VERSIONS(VERSION), DOUBLES(
13 DOUBLE);
Stuart McCullochf3173222012-06-07 21:57:32 +000014
15 Type sub;
16
17 Type(Type sub) {
18 this.sub = sub;
19 }
20
21 }
22
23 /**
24 * <pre>
25 * Provide-Capability ::= capability ::=
26 * name-space ::= typed-attr ::= type ::= scalar ::=
27 * capability ( ',' capability )*
28 * name-space
29 * ( ’;’ directive | typed-attr )*
30 * symbolic-name
31 * extended ( ’:’ type ) ’=’ argument
32 * scalar | list
33 * ’String’ | ’Version’ | ’Long’
34 * list ::=
35 * ’List<’ scalar ’>’
36 * </pre>
37 */
Stuart McCulloch4482c702012-06-15 13:27:53 +000038 static String EXTENDED = "[\\-0-9a-zA-Z\\._]+";
39 static String SCALAR = "String|Version|Long|Double";
40 static String LIST = "List\\s*<\\s*(" + SCALAR + ")\\s*>";
41 public static final Pattern TYPED = Pattern.compile("\\s*(" + EXTENDED + ")\\s*:\\s*(" + SCALAR
42 + "|" + LIST + ")\\s*");
Stuart McCullochf3173222012-06-07 21:57:32 +000043
Stuart McCulloch4482c702012-06-15 13:27:53 +000044 private LinkedHashMap<String,String> map;
45 private Map<String,Type> types;
46 static Map<String,String> EMPTY = Collections.emptyMap();
Stuart McCullochf3173222012-06-07 21:57:32 +000047
48 public Attrs(Attrs... attrs) {
49 for (Attrs a : attrs) {
50 if (a != null) {
51 putAll(a);
52 }
53 }
54 }
55
56 public void clear() {
57 map.clear();
58 }
59
60 public boolean containsKey(String name) {
61 if (map == null)
62 return false;
63
64 return map.containsKey(name);
65 }
66
67 @SuppressWarnings("cast")
Stuart McCulloch4482c702012-06-15 13:27:53 +000068 @Deprecated
69 public boolean containsKey(Object name) {
Stuart McCullochf3173222012-06-07 21:57:32 +000070 assert name instanceof String;
71 if (map == null)
72 return false;
73
74 return map.containsKey((String) name);
75 }
76
77 public boolean containsValue(String value) {
78 if (map == null)
79 return false;
80
81 return map.containsValue(value);
82 }
83
84 @SuppressWarnings("cast")
Stuart McCulloch4482c702012-06-15 13:27:53 +000085 @Deprecated
86 public boolean containsValue(Object value) {
Stuart McCullochf3173222012-06-07 21:57:32 +000087 assert value instanceof String;
88 if (map == null)
89 return false;
90
91 return map.containsValue((String) value);
92 }
93
Stuart McCulloch4482c702012-06-15 13:27:53 +000094 public Set<java.util.Map.Entry<String,String>> entrySet() {
Stuart McCullochf3173222012-06-07 21:57:32 +000095 if (map == null)
96 return EMPTY.entrySet();
97
98 return map.entrySet();
99 }
100
101 @SuppressWarnings("cast")
Stuart McCulloch4482c702012-06-15 13:27:53 +0000102 @Deprecated
103 public String get(Object key) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000104 assert key instanceof String;
105 if (map == null)
106 return null;
107
108 return map.get((String) key);
109 }
110
111 public String get(String key) {
112 if (map == null)
113 return null;
114
115 return map.get(key);
116 }
117
118 public String get(String key, String deflt) {
119 String s = get(key);
120 if (s == null)
121 return deflt;
122 return s;
123 }
124
125 public boolean isEmpty() {
126 return map == null || map.isEmpty();
127 }
128
129 public Set<String> keySet() {
130 if (map == null)
131 return EMPTY.keySet();
132
133 return map.keySet();
134 }
135
136 public String put(String key, String value) {
137 if (map == null)
Stuart McCulloch4482c702012-06-15 13:27:53 +0000138 map = new LinkedHashMap<String,String>();
Stuart McCullochf3173222012-06-07 21:57:32 +0000139
140 Matcher m = TYPED.matcher(key);
141 if (m.matches()) {
142 key = m.group(1);
143 String type = m.group(2);
144 Type t = Type.STRING;
145
Stuart McCulloch4482c702012-06-15 13:27:53 +0000146 if (type.startsWith("List")) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000147 type = m.group(3);
Stuart McCulloch4482c702012-06-15 13:27:53 +0000148 if ("String".equals(type))
Stuart McCullochf3173222012-06-07 21:57:32 +0000149 t = Type.STRINGS;
Stuart McCulloch4482c702012-06-15 13:27:53 +0000150 else if ("Long".equals(type))
Stuart McCullochf3173222012-06-07 21:57:32 +0000151 t = Type.LONGS;
Stuart McCulloch4482c702012-06-15 13:27:53 +0000152 else if ("Double".equals(type))
Stuart McCullochf3173222012-06-07 21:57:32 +0000153 t = Type.DOUBLES;
Stuart McCulloch4482c702012-06-15 13:27:53 +0000154 else if ("Version".equals(type))
155 t = Type.VERSIONS;
Stuart McCullochf3173222012-06-07 21:57:32 +0000156 } else {
Stuart McCulloch4482c702012-06-15 13:27:53 +0000157 if ("String".equals(type))
Stuart McCullochf3173222012-06-07 21:57:32 +0000158 t = Type.STRING;
Stuart McCulloch4482c702012-06-15 13:27:53 +0000159 else if ("Long".equals(type))
Stuart McCullochf3173222012-06-07 21:57:32 +0000160 t = Type.LONG;
Stuart McCulloch4482c702012-06-15 13:27:53 +0000161 else if ("Double".equals(type))
Stuart McCullochf3173222012-06-07 21:57:32 +0000162 t = Type.DOUBLE;
Stuart McCulloch4482c702012-06-15 13:27:53 +0000163 else if ("Version".equals(type))
Stuart McCullochf3173222012-06-07 21:57:32 +0000164 t = Type.VERSION;
165 }
166 if (types == null)
Stuart McCulloch4482c702012-06-15 13:27:53 +0000167 types = new LinkedHashMap<String,Type>();
Stuart McCullochf3173222012-06-07 21:57:32 +0000168 types.put(key, t);
169
170 // TODO verify value?
171 }
172
173 return map.put(key, value);
174 }
175
176 public Type getType(String key) {
177 if (types == null)
178 return Type.STRING;
179 Type t = types.get(key);
180 if (t == null)
181 return Type.STRING;
182 return t;
183 }
184
Stuart McCulloch4482c702012-06-15 13:27:53 +0000185 public void putAll(Map< ? extends String, ? extends String> map) {
186 for (Map.Entry< ? extends String, ? extends String> e : map.entrySet())
Stuart McCullochf3173222012-06-07 21:57:32 +0000187 put(e.getKey(), e.getValue());
188 }
189
190 @SuppressWarnings("cast")
Stuart McCulloch4482c702012-06-15 13:27:53 +0000191 @Deprecated
192 public String remove(Object var0) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000193 assert var0 instanceof String;
194 if (map == null)
195 return null;
196
197 return map.remove((String) var0);
198 }
199
200 public String remove(String var0) {
201 if (map == null)
202 return null;
203 return map.remove(var0);
204 }
205
206 public int size() {
207 if (map == null)
208 return 0;
209 return map.size();
210 }
211
212 public Collection<String> values() {
213 if (map == null)
214 return EMPTY.values();
215
216 return map.values();
217 }
218
219 public String getVersion() {
220 return get("version");
221 }
222
223 public String toString() {
224 StringBuilder sb = new StringBuilder();
225 append(sb);
226 return sb.toString();
227 }
228
229 public void append(StringBuilder sb) {
230 String del = "";
Stuart McCulloch4482c702012-06-15 13:27:53 +0000231 for (Map.Entry<String,String> e : entrySet()) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000232 sb.append(del);
233 sb.append(e.getKey());
234 sb.append("=");
235 sb.append(e.getValue());
236 del = ";";
237 }
238 }
239
Stuart McCulloch4482c702012-06-15 13:27:53 +0000240 @Deprecated
241 public boolean equals(Object other) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000242 return super.equals(other);
243 }
244
Stuart McCulloch4482c702012-06-15 13:27:53 +0000245 @Deprecated
246 public int hashCode() {
Stuart McCullochf3173222012-06-07 21:57:32 +0000247 return super.hashCode();
248 }
249
250 public boolean isEqual(Attrs o) {
251 if (this == o)
252 return true;
253
254 Attrs other = o;
255
256 if (size() != other.size())
257 return false;
258
259 if (isEmpty())
260 return true;
261
262 SortedList<String> l = new SortedList<String>(keySet());
263 SortedList<String> lo = new SortedList<String>(other.keySet());
264 if (!l.isEqual(lo))
265 return false;
266
267 for (String key : keySet()) {
268 if (!get(key).equals(other.get(key)))
269 return false;
270 }
271 return true;
272
273 }
274
275 public Object getTyped(String adname) {
276 String s = get(adname);
277 if (s == null)
278 return null;
279
280 Type t = getType(adname);
281 return convert(t, s);
282 }
283
284 private Object convert(Type t, String s) {
285 if (t.sub == null) {
286 switch (t) {
Stuart McCulloch4482c702012-06-15 13:27:53 +0000287 case STRING :
288 return s;
289 case LONG :
290 return Long.parseLong(s.trim());
291 case VERSION :
292 return Version.parseVersion(s);
Stuart McCulloch2b3253e2012-06-17 20:38:35 +0000293 case DOUBLE :
294 return Double.parseDouble(s.trim());
295
296 case DOUBLES :
297 case LONGS :
298 case STRINGS :
299 case VERSIONS :
300 // Cannot happen since the sub is null
301 return null;
Stuart McCullochf3173222012-06-07 21:57:32 +0000302 }
303 return null;
304 }
305 List<Object> list = new ArrayList<Object>();
306 String split[] = s.split("\\s*\\(\\?!\\),\\s*");
307 for (String p : split) {
308 p = p.replaceAll("\\\\", "");
309 list.add(convert(t.sub, p));
310 }
311 return list;
312 }
313}