View Javadoc
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