1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package org.metricshub.wbem.sblim.slp;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 import java.io.ByteArrayOutputStream;
57 import java.io.Serializable;
58 import java.util.Arrays;
59 import java.util.StringTokenizer;
60 import java.util.Vector;
61 import org.metricshub.wbem.sblim.cimclient.GenericExts;
62 import org.metricshub.wbem.sblim.slp.internal.AttributeHandler;
63 import org.metricshub.wbem.sblim.slp.internal.Convert;
64 import org.metricshub.wbem.sblim.slp.internal.SLPString;
65
66
67
68
69 public class ServiceLocationAttribute implements Serializable {
70 private static final long serialVersionUID = -6753246108754657715L;
71
72 private Vector<Object> iValues;
73
74 private String iId;
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 public ServiceLocationAttribute(String pId, Vector<Object> pValues) {
91 this.iId = pId;
92 if (pValues != null && pValues.size() > 0) {
93 this.iValues = GenericExts.cloneVector(pValues);
94 }
95 }
96
97
98
99
100
101
102
103
104
105 public ServiceLocationAttribute(String pString) throws ServiceLocationException {
106 if (pString == null || pString.length() == 0) throw new ServiceLocationException(
107 ServiceLocationException.PARSE_ERROR,
108 "Empty or null String is not good for this constructor!"
109 );
110
111 if (pString.startsWith("(") && pString.endsWith(")")) {
112 int equalPos = pString.indexOf('=');
113 if (equalPos < 0) throw new ServiceLocationException(
114 ServiceLocationException.PARSE_ERROR,
115 "Missing '=' from attribute string: " + pString
116 );
117 this.iId = Convert.unescape(pString.substring(1, equalPos));
118 if (this.iId.length() == 0) throw new ServiceLocationException(
119 ServiceLocationException.PARSE_ERROR,
120 "Empty attribute ID in attribute string: " + pString
121 );
122 String valueString = pString.substring(equalPos + 1, pString.length() - 1);
123
124 parseValueString(valueString);
125 } else {
126 if (pString.indexOf('(') >= 0 || pString.indexOf(')') >= 0) throw new ServiceLocationException(
127 ServiceLocationException.PARSE_ERROR
128 );
129 this.iId = Convert.unescape(pString);
130 this.iValues = null;
131 }
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145 public static String escapeId(String pId) {
146 return Convert.escape(pId, Convert.ATTR_RESERVED);
147 }
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164 public static String escapeValue(Object pValue) {
165 return AttributeHandler.escapeValue(pValue);
166 }
167
168
169
170
171
172
173
174
175
176 public Vector<Object> getValues() {
177 if (this.iValues != null) return GenericExts.cloneVector(this.iValues);
178 return this.iValues;
179 }
180
181
182
183
184
185
186 public String getId() {
187 return this.iId;
188 }
189
190
191
192
193
194
195
196
197
198
199
200
201
202 @Override
203 public boolean equals(Object obj) {
204 if (obj == this) return true;
205 if (!(obj instanceof ServiceLocationAttribute)) return false;
206
207 ServiceLocationAttribute that = (ServiceLocationAttribute) obj;
208 if (!that.getId().equalsIgnoreCase(this.iId)) return false;
209
210 Vector<Object> thatValues = that.iValues;
211 if (this.iValues == null) return thatValues == null;
212 if (thatValues == null) return false;
213 if (this.iValues.size() != thatValues.size()) return false;
214
215 ValueEntry[] thisEntries = getSortedValueEntries();
216 ValueEntry[] thatEntries = that.getSortedValueEntries();
217
218 return Arrays.equals(thisEntries, thatEntries);
219 }
220
221
222
223
224
225
226
227
228
229
230
231 @Override
232 public String toString() {
233 StringBuffer stringbuffer = new StringBuffer("(");
234 stringbuffer.append(this.iId);
235 if (this.iValues != null) {
236 stringbuffer.append("=");
237 int size = this.iValues.size();
238 for (int i = 0; i < size; i++) {
239 Object obj = this.iValues.elementAt(i);
240 if (i > 0) {
241 stringbuffer.append(",");
242 }
243 if (obj instanceof byte[]) obj = AttributeHandler.mkOpaqueStr((byte[]) obj);
244 stringbuffer.append(obj.toString());
245 }
246 }
247 stringbuffer.append(")");
248 return stringbuffer.toString();
249 }
250
251 private int iHashCode = 0;
252
253 private void incHashCode(int pHashCode) {
254 this.iHashCode *= 31;
255 this.iHashCode += pHashCode;
256 }
257
258
259
260
261
262
263
264
265 @Override
266 public int hashCode() {
267 if (this.iHashCode == 0) {
268 this.iHashCode = this.iId.hashCode();
269 if (this.iValues != null) {
270 ValueEntry[] valueEntries = getSortedValueEntries();
271 for (int i = 0; i < valueEntries.length; i++) incHashCode(valueEntries[i].hashCode());
272 }
273 }
274 return this.iHashCode;
275 }
276
277 private void parseValueString(String pStr) throws ServiceLocationException {
278 StringTokenizer tokenizer = new StringTokenizer(pStr, ",");
279 this.iValues = new Vector<Object>();
280 while (tokenizer.hasMoreElements()) {
281 String valueStr = tokenizer.nextToken();
282 Object value;
283 try {
284 int intVal = Integer.parseInt(valueStr);
285 value = Integer.valueOf(intVal);
286 } catch (NumberFormatException e) {
287 if ("TRUE".equalsIgnoreCase(valueStr)) {
288 value = Boolean.TRUE;
289 } else if ("FALSE".equalsIgnoreCase(valueStr)) {
290 value = Boolean.FALSE;
291 } else if (valueStr.startsWith("\\FF")) {
292 value = parseOpaqueStr(valueStr);
293 } else {
294 value = Convert.unescape(valueStr);
295 }
296 }
297 this.iValues.add(value);
298 }
299 }
300
301 private static byte[] parseOpaqueStr(String pStr) throws ServiceLocationException {
302 if (pStr.length() == 3) throw new ServiceLocationException(
303 ServiceLocationException.PARSE_ERROR,
304 "There must be at least three characters after \\FF in opaque string!" + " pStr=" + pStr
305 );
306
307 ByteArrayOutputStream oStr = new ByteArrayOutputStream();
308 int pos = 3;
309 int left;
310 while ((left = pStr.length() - pos) > 0) {
311 if (left < 3) throw new ServiceLocationException(
312 ServiceLocationException.PARSE_ERROR,
313 "Number of characters must be multiple of three after \\FF in opaque string!" + " pStr=" + pStr
314 );
315 if (pStr.charAt(pos) != '\\') throw new ServiceLocationException(
316 ServiceLocationException.PARSE_ERROR,
317 "Hex value must be preceded by \\ in opaque string!" + " pStr=" + pStr
318 );
319 String hexStr = pStr.substring(pos + 1, pos + 3);
320 pos += 3;
321 try {
322 oStr.write(Integer.parseInt(hexStr, 16));
323 } catch (NumberFormatException e) {
324 throw new ServiceLocationException(
325 ServiceLocationException.PARSE_ERROR,
326 "Failed to parse hex value: " + hexStr + " in opaque string: " + pStr + " !"
327 );
328 }
329 }
330 return oStr.toByteArray();
331 }
332
333 static class ValueEntry implements Comparable<ValueEntry> {
334
335
336
337 public String iStr;
338
339
340
341
342 public Object iValue;
343
344 public int compareTo(ValueEntry o) {
345 ValueEntry that = o;
346 return this.iStr.compareTo(that.iStr);
347 }
348
349 @Override
350 public boolean equals(Object pObj) {
351 if (this == pObj) return true;
352 if (!(pObj instanceof ValueEntry)) return false;
353 ValueEntry that = (ValueEntry) pObj;
354 if (this.iValue == null) return that.iValue == null;
355 if (that.iValue == null) return false;
356 if (!this.iValue.getClass().equals(that.iValue.getClass())) return false;
357 if (this.iValue instanceof byte[]) return Arrays.equals((byte[]) this.iValue, (byte[]) that.iValue);
358 if (this.iValue instanceof String) return this.iStr.equals(that.iStr);
359 return this.iValue.equals(that.iValue);
360 }
361
362 @Override
363 public int hashCode() {
364 return this.iStr == null ? 1 : this.iStr.hashCode();
365 }
366 }
367
368 private transient ValueEntry[] iSortedValueEntries;
369
370
371
372
373
374
375
376
377 private ValueEntry[] getSortedValueEntries() {
378 if (this.iValues == null) return null;
379 if (this.iSortedValueEntries != null) return this.iSortedValueEntries;
380 this.iSortedValueEntries = new ValueEntry[this.iValues.size()];
381 for (int i = 0; i < this.iValues.size(); i++) {
382 ValueEntry entry = new ValueEntry();
383 this.iSortedValueEntries[i] = entry;
384 Object value = this.iValues.get(i);
385 entry.iValue = value;
386 if (value == null) {
387 entry.iStr = "";
388 } else {
389 if (value instanceof String) {
390 entry.iStr = SLPString.unify((String) value);
391 } else if (value instanceof byte[]) {
392 entry.iStr = AttributeHandler.mkOpaqueStr((byte[]) value);
393 } else {
394 entry.iStr = value.toString();
395 }
396 }
397 }
398 Arrays.sort(this.iSortedValueEntries);
399 return this.iSortedValueEntries;
400 }
401 }