1 /*
2 */
3 package net.sf.panoptes.model.component.registry;
4
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.Enumeration;
8 import java.util.Hashtable;
9 import java.util.Iterator;
10
11 /***
12 * Represents the IComponent reference. Original code from JBoss.
13 *
14 * @see net.sf.panoptes.model.component.registry.ComponentRegistry
15 *
16 * @author dag@liodden.no
17 * @version 0.1
18 *
19 */
20 public class ComponentName implements java.io.Serializable {
21
22 public static final String DOMAIN_COMPONENT_QUERY = "query";
23 public static final String DOMAIN_MBEAN_DOMAIN = "jmx.domain";
24 public static final String DOMAIN_MBEAN_SERVER = "jmx.server";
25 public static final String DOMAIN_MBEAN = "jmx.mbean";
26 public static final String DOMAIN_LOGGER = "logger";
27
28 // Attributes ----------------------------------------------------
29 private transient boolean hasPattern = false;
30 private transient boolean hasPropertyPattern = false;
31 private transient boolean hasDomainPattern = false;
32 private transient Hashtable propertiesHash = null;
33
34 private transient String domain = null;
35 private transient String kProps = null;
36 private transient String ckProps = null;
37
38 private transient int hash;
39
40 // Static --------------------------------------------------------
41
42 // Constructors --------------------------------------------------
43 public ComponentName(String name) throws MalformedComponentNameException {
44 init(name);
45 }
46
47 public ComponentName(String domain, String name) throws MalformedComponentNameException {
48 init(domain + ":" + name);
49 }
50
51 public ComponentName(String domain, Hashtable table) throws MalformedComponentNameException {
52 if (table == null)
53 throw new NullPointerException("null table");
54
55 initDomain(domain, null);
56
57 if (table.size() < 1)
58 throw new MalformedComponentNameException("empty table");
59
60 initProperties((Hashtable) table.clone(), null);
61
62 this.kProps = ckProps;
63 }
64
65 // Public ------------------------------------------------------
66 /***
67 * Quotes the passed string suitable for use as a value in an
68 * ObjectName.
69 *
70 * @param value the string to quote
71 * @return the quoted string
72 * @exception NullPointerException for a null string
73 */
74 public static String quote(String value) {
75 if (value == null)
76 throw new NullPointerException("null value");
77
78 StringBuffer buffer = new StringBuffer(value.length() + 10);
79 buffer.append('"');
80 char[] chars = value.toCharArray();
81 for (int i = 0; i < chars.length; i++) {
82 switch (chars[i]) {
83 case '"' :
84 case '*' :
85 case '?' :
86 case '//' :
87 buffer.append('//').append(chars[i]);
88 break;
89 case '\n' :
90 buffer.append('//').append('n');
91 break;
92 default :
93 buffer.append(chars[i]);
94 }
95 }
96 buffer.append('"');
97
98 return buffer.toString();
99 }
100
101 /***
102 * Unquotes a string, unquote(quote(s)).equals(s) is always true.
103 *
104 * @param value the string to unquote
105 * @return the unquoted string
106 * @exception IllegalArgumentException when the string is
107 * not of a form that can be unquoted.
108 * @exception NullPointerException for a null string
109 */
110 public static String unquote(String value) {
111 if (value == null)
112 throw new NullPointerException("null value");
113 if (value.length() == 0)
114 throw new IllegalArgumentException("Empty value");
115
116 StringBuffer buffer = new StringBuffer(value.length());
117
118 char[] chars = value.toCharArray();
119
120 boolean inQuote = false;
121 boolean escape = false;
122
123 for (int i = 0; i < chars.length; ++i) {
124 // Valid escape character?
125 char c = chars[i];
126 if (escape) {
127 switch (c) {
128 case '//' :
129 case '"' :
130 case '*' :
131 case '?' :
132 escape = false;
133 buffer.append(c);
134 break;
135 case 'n' :
136 escape = false;
137 buffer.append('\n');
138 break;
139
140 // Invalid escape character
141 default :
142 throw new IllegalArgumentException(
143 "The value " + value + " contains an invalid escape sequence backslash " + c);
144 }
145 }
146
147 // Starting a quote
148 else if (inQuote == false && c == '"')
149 inQuote = true;
150
151 // Ending a quote
152 else if (inQuote && c == '"')
153 inQuote = false;
154
155 // Escaping
156 else if (inQuote && c == '//')
157 escape = true;
158
159 // Inside a quote
160 else if (inQuote) {
161 switch (c) {
162 case '"' :
163 throw new IllegalArgumentException(
164 "The value " + value + " cannot contain quote inside a quote pair, use backslash quote");
165 case '*' :
166 case '?' :
167 throw new IllegalArgumentException(
168 "The value " + value + " cannot contain " + c + " inside a quote pair, use backslash " + c);
169 case '\n' :
170 throw new IllegalArgumentException(
171 "The value " + value + " cannot contain a new line inside a quote pair, use backslash n");
172 }
173 buffer.append(c);
174 }
175
176 // Plain text
177 else
178 throw new IllegalArgumentException("The value " + value + " is not enclosed in quotes");
179 }
180
181 if (inQuote)
182 throw new IllegalArgumentException("Unterminated quote pair, missing quote");
183 if (escape)
184 throw new IllegalArgumentException("Unterminated escape, missing one of backslash quote asterisk question mark or n");
185
186 return buffer.toString();
187 }
188
189 public boolean equals(Object object) {
190 if (object == this) {
191 return true;
192 }
193
194 if (object instanceof ComponentName) {
195 ComponentName oname = (ComponentName) object;
196 return (oname.hash == hash && domain.equals(oname.domain) && ckProps.equals(oname.ckProps));
197 }
198
199 return false;
200 }
201
202 public int hashCode() {
203 return hash;
204 }
205
206 public String toString() {
207 return this.domain + ":" + ckProps;
208 }
209
210 public boolean isPattern() {
211 return hasPattern;
212 }
213
214 public String getCanonicalName() {
215 return this.domain + ":" + ckProps;
216 }
217
218 public String getDomain() {
219 return domain;
220 }
221
222 public String getKeyProperty(String property) {
223 return (String) propertiesHash.get(property);
224 }
225
226 public Hashtable getKeyPropertyList() {
227 return (Hashtable) propertiesHash.clone();
228 }
229
230 public String getKeyPropertyListString() {
231 return kProps;
232 }
233
234 public String getCanonicalKeyPropertyListString() {
235 return ckProps;
236 }
237
238 public boolean isPropertyPattern() {
239 return hasPropertyPattern;
240 }
241
242 // Private -----------------------------------------------------
243
244 /***
245 * constructs an object name from a string
246 */
247 private void init(String name) throws MalformedComponentNameException {
248 if (name == null)
249 throw new NullPointerException("null name");
250
251 if (name.length() == 0)
252 name = "*:*";
253
254 int domainSep = name.indexOf(':');
255
256 if (-1 == domainSep)
257 throw new MalformedComponentNameException("missing domain");
258
259 initDomain(name.substring(0, domainSep), name);
260 initProperties(name.substring(domainSep + 1), name);
261 }
262
263 /***
264 * checks for domain patterns and illegal characters
265 */
266 private void initDomain(String dstring, String name) throws MalformedComponentNameException
267 {
268 if (null == dstring)
269 throw new NullPointerException("null domain");
270
271 checkIllegalDomain(dstring, name);
272
273 if (dstring.indexOf('*') > -1 || dstring.indexOf('?') > -1)
274 {
275 this.hasPattern = true;
276 this.hasDomainPattern = true;
277 }
278
279 this.domain = dstring;
280 }
281 /***
282 * takes the properties string and breaks it up into key/value pairs for
283 * insertion into a newly created hashtable.
284 *
285 * minimal validation is performed so that it doesn't blow up when
286 * constructing the kvp strings.
287 *
288 * checks for duplicate keys
289 *
290 * detects property patterns
291 *
292 */
293 private void initProperties(String properties, String name) throws MalformedComponentNameException {
294 if (null == properties || properties.length() < 1)
295 throw new MalformedComponentNameException(addDebugObjectName(name) + "null or empty properties");
296
297 Hashtable ptable = new Hashtable();
298
299 char[] chars = properties.toCharArray();
300
301 String key = null;
302 String value = null;
303 int start = 0;
304 boolean inKey = true;
305 boolean inQuote = false;
306 boolean escape = false;
307
308 for (int current = 0; current < chars.length; ++current) {
309 char c = chars[current];
310
311 // Previous character was the backslash escape
312 if (escape)
313 escape = false;
314
315 // In a quote
316 else if (inQuote) {
317 // End the quote
318 if (c == '"')
319 inQuote = false;
320
321 // Start escaping
322 else if (c == '//')
323 escape = true;
324 }
325
326 // Processing the key
327 else if (inKey) {
328 // Found the terminator
329 if (c == '=' || c == ',') {
330 if (current == start)
331 throw new MalformedComponentNameException(addDebugObjectName(name) + "Empty key");
332 key = properties.substring(start, current);
333
334 // Didn't get an equals so the only thing valid is asterisk
335 if (c == ',') {
336 if (key.equals("*")) {
337 if (hasPropertyPattern)
338 throw new MalformedComponentNameException(
339 addDebugObjectName(name) + "A property pattern may only contain one * property");
340 this.hasPropertyPattern = true;
341 this.hasPattern = true;
342 } else
343 throw new MalformedComponentNameException(
344 addDebugObjectName(name) + "Invalid key/value data " + key);
345 } else {
346 // Check for a duplicate key and process the value
347 if (ptable.containsKey(key))
348 throw new MalformedComponentNameException(addDebugObjectName(name) + "Duplicate key " + key);
349 inKey = false;
350 }
351 start = current + 1;
352 }
353 }
354
355 // Processing a value
356 else {
357 // Starting a quote
358 if (c == '"')
359 inQuote = true;
360
361 // Found the terminator
362 else if (c == ',') {
363 // Add the key, value pair and process the next pair
364 if (current == start)
365 ptable.put(key, "");
366 else
367 ptable.put(key, properties.substring(start, current));
368
369 inKey = true;
370 start = current + 1;
371 }
372 }
373 }
374
375 // Fell off the end while processing a key
376 if (inKey) {
377 if (start == chars.length)
378 throw new MalformedComponentNameException(
379 addDebugObjectName(name) + "An ObjectName cannot end with a comma");
380
381 // Might be ok if the remainder is an asterisk
382 key = properties.substring(start, chars.length);
383 if (key.equals("*")) {
384 if (hasPropertyPattern)
385 throw new MalformedComponentNameException(
386 addDebugObjectName(name) + "A property pattern may only contain one * property");
387
388 this.hasPropertyPattern = true;
389 this.hasPattern = true;
390 } else
391 throw new MalformedComponentNameException(addDebugObjectName(name) + "Invalid key/value data " + key);
392 }
393
394 // Fell off the end while processing a value
395 if (inKey == false) {
396 // No value
397 if (start == chars.length)
398 ptable.put(key, "");
399 else
400 ptable.put(key, properties.substring(start, chars.length));
401 }
402
403 initProperties(ptable, name);
404 this.kProps = properties;
405 }
406
407 /***
408 * validates incoming properties hashtable
409 *
410 * builds canonical string
411 *
412 * precomputes the hashcode
413 */
414 private void initProperties(Hashtable properties, String name) throws MalformedComponentNameException {
415 if (null == properties || (!this.hasPropertyPattern && properties.size() < 1))
416 throw new MalformedComponentNameException(addDebugObjectName(name) + "null or empty properties");
417
418 Iterator it = properties.keySet().iterator();
419 ArrayList list = new ArrayList();
420
421 while (it.hasNext()) {
422 String key = null;
423 try {
424 key = (String) it.next();
425 } catch (ClassCastException e) {
426 throw new MalformedComponentNameException(addDebugObjectName(name) + "key is not a string " + key);
427 }
428
429 String val = null;
430 try {
431 val = (String) properties.get(key);
432 } catch (ClassCastException e) {
433 throw new MalformedComponentNameException(addDebugObjectName(name) + "value is not a string " + val);
434 }
435
436 if (key.equals("*") && val.equals("*")) {
437 it.remove();
438 this.hasPropertyPattern = true;
439 this.hasPattern = true;
440 continue;
441 }
442
443 if (key.length() == 0)
444 throw new MalformedComponentNameException(addDebugObjectName(name) + "key has no length =" + val);
445
446 checkIllegalKey(key, name);
447 checkIllegalValue(val, name);
448
449 list.add(new String(key + "=" + val));
450 }
451
452 Collections.sort(list);
453 StringBuffer strBuffer = new StringBuffer();
454
455 it = list.iterator();
456 while (it.hasNext()) {
457 strBuffer.append(it.next());
458 if (it.hasNext()) {
459 strBuffer.append(',');
460 }
461 }
462
463 if (this.hasPropertyPattern) {
464 if (properties.size() > 0) {
465 strBuffer.append(",*");
466 } else {
467 strBuffer.append("*");
468 }
469 }
470
471 this.propertiesHash = properties;
472 this.ckProps = strBuffer.toString();
473 this.hash = getCanonicalName().hashCode();
474 }
475
476 private void checkIllegalKey(String key, String name) throws MalformedComponentNameException {
477 char[] chars = key.toCharArray();
478
479 for (int i = 0; i < chars.length; ++i) {
480 switch (chars[i]) {
481 case ':' :
482 case ',' :
483 case '=' :
484 case '*' :
485 case '?' :
486 throw new MalformedComponentNameException(
487 addDebugObjectName(name) + "The key " + key + " cannot contain a " + chars[i] + " character");
488 case '\n' :
489 throw new MalformedComponentNameException(
490 addDebugObjectName(name) + "The key " + key + " cannot contain a new line character");
491 }
492 }
493 }
494
495 private void checkIllegalValue(String value, String name) throws MalformedComponentNameException {
496 char[] chars = value.toCharArray();
497
498 boolean inQuote = false;
499 boolean escape = false;
500
501 for (int i = 0; i < chars.length; ++i) {
502 // Valid escape character?
503 char c = chars[i];
504 if (escape) {
505 switch (c) {
506 case '//' :
507 case 'n' :
508 case '"' :
509 case '*' :
510 case '?' :
511 escape = false;
512 break;
513
514 // Invalid escape character
515 default :
516 throw new MalformedComponentNameException(
517 addDebugObjectName(name)
518 + "The value "
519 + value
520 + " contains an invalid escape sequence backslash "
521 + c);
522 }
523 }
524
525 // Starting a quote
526 else if (inQuote == false && c == '"')
527 inQuote = true;
528
529 // Ending a quote
530 else if (inQuote && c == '"')
531 inQuote = false;
532
533 // Escaping
534 else if (inQuote && c == '//')
535 escape = true;
536
537 // Inside a quote
538 else if (inQuote) {
539 switch (c) {
540 case '"' :
541 throw new MalformedComponentNameException(
542 addDebugObjectName(name)
543 + "The value "
544 + value
545 + " cannot contain quote inside a quote pair, use backslash quote");
546 case '*' :
547 case '?' :
548 throw new MalformedComponentNameException(
549 addDebugObjectName(name)
550 + "The value "
551 + value
552 + " cannot contain "
553 + c
554 + " inside a quote pair, use backslash "
555 + c);
556 case '\n' :
557 throw new MalformedComponentNameException(
558 addDebugObjectName(name)
559 + "The value "
560 + value
561 + " cannot contain a new line inside a quote pair, use backslash n");
562 }
563 }
564
565 // Plain text
566 else {
567 switch (c) {
568 case ':' :
569 case ',' :
570 case '=' :
571 case '*' :
572 case '?' :
573 throw new MalformedComponentNameException(
574 addDebugObjectName(name)
575 + "The value "
576 + value
577 + " cannot contain "
578 + c
579 + " use quote backslash "
580 + c
581 + " quote or ObjectName.quote(String)");
582 case '\n' :
583 throw new MalformedComponentNameException(
584 addDebugObjectName(name)
585 + "The value "
586 + value
587 + " cannot contain a new line use quote backslash n quote or ObjectName.quote(String)");
588 }
589 }
590 }
591
592 if (inQuote)
593 throw new MalformedComponentNameException(
594 addDebugObjectName(name) + "Unterminated quote pair, missing quote");
595 if (escape)
596 throw new MalformedComponentNameException(
597 addDebugObjectName(name)
598 + "Unterminated escape, missing one of backslash quote asterisk question mark or n");
599 }
600
601 /***
602 * returns true if the domain contains illegal characters
603 */
604 private void checkIllegalDomain(String dom, String name) throws MalformedComponentNameException {
605 char[] chars = dom.toCharArray();
606
607 for (int i = 0; i < chars.length; i++) {
608 switch (chars[i]) {
609 case ':' :
610 throw new MalformedComponentNameException(
611 addDebugObjectName(name) + "The domain " + dom + " cannot contain a : character");
612 case '\n' :
613 throw new MalformedComponentNameException(
614 addDebugObjectName(name) + "The domain " + dom + " cannot contain a new line character");
615 }
616 }
617 }
618
619 private String addDebugObjectName(String name) {
620 if (name == null)
621 return "";
622 else
623 return name + " is not a valid ObjectName. ";
624 }
625
626 /***
627 * @param string
628 */
629 public void setDomain(String domain) throws MalformedComponentNameException {
630 initDomain(domain, null);
631 }
632
633 /***
634 * Checks if this instance matches a pattern.
635 *
636 * @param pattern the pattern
637 * @return true if it matches
638 */
639 public boolean matches(ComponentName pattern) {
640 // We do casts here without any checking since the keys and values have been
641 // checked in the ComponentName constructor.
642
643 // Check if the domain matches
644 if ((!pattern.getDomain().equals("*") && !pattern.getDomain().equals(getDomain())))
645 return false;
646
647 // Check the keys in pattern and see if there is a match;
648 Hashtable props = pattern.getKeyPropertyList();
649 for (Enumeration e = props.keys(); e.hasMoreElements();) {
650 String key = (String) e.nextElement();
651 String value = (String) propertiesHash.get(key);
652 if ((value == null) || !(value.equals(props.get(key))))
653 return false;
654 }
655 return true;
656 }
657 }
This page was automatically generated by Maven