1 /* 2 * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.management; 27 28 import com.sun.jmx.mbeanserver.GetPropertyAction; 29 import com.sun.jmx.mbeanserver.Util; 30 import java.io.IOException; 31 import java.io.InvalidObjectException; 32 import java.io.ObjectInputStream; 33 import java.io.ObjectOutputStream; 34 import java.io.ObjectStreamField; 35 import java.security.AccessController; 36 import java.util.Arrays; 37 import java.util.Collections; 38 import java.util.HashMap; 39 import java.util.Hashtable; 40 import java.util.Map; 41 42 /** 43 * <p>Represents the object name of an MBean, or a pattern that can 44 * match the names of several MBeans. Instances of this class are 45 * immutable.</p> 46 * 47 * <p>An instance of this class can be used to represent:</p> 48 * <ul> 49 * <li>An object name</li> 50 * <li>An object name pattern, within the context of a query</li> 51 * </ul> 52 * 53 * <p>An object name consists of two parts, the domain and the key 54 * properties.</p> 55 * 56 * <p>The <em>domain</em> is a string of characters not including 57 * the character colon (<code>:</code>). It is recommended that the domain 58 * should not contain the string "{@code //}", which is reserved for future use. 59 * 60 * <p>If the domain includes at least one occurrence of the wildcard 61 * characters asterisk (<code>*</code>) or question mark 62 * (<code>?</code>), then the object name is a pattern. The asterisk 63 * matches any sequence of zero or more characters, while the question 64 * mark matches any single character.</p> 65 * 66 * <p>If the domain is empty, it will be replaced in certain contexts 67 * by the <em>default domain</em> of the MBean server in which the 68 * ObjectName is used.</p> 69 * 70 * <p>The <em>key properties</em> are an unordered set of keys and 71 * associated values.</p> 72 * 73 * <p>Each <em>key</em> is a nonempty string of characters which may 74 * not contain any of the characters comma (<code>,</code>), equals 75 * (<code>=</code>), colon, asterisk, or question mark. The same key 76 * may not occur twice in a given ObjectName.</p> 77 * 78 * <p>Each <em>value</em> associated with a key is a string of 79 * characters that is either unquoted or quoted.</p> 80 * 81 * <p>An <em>unquoted value</em> is a possibly empty string of 82 * characters which may not contain any of the characters comma, 83 * equals, colon, or quote.</p> 84 * 85 * <p>If the <em>unquoted value</em> contains at least one occurrence 86 * of the wildcard characters asterisk or question mark, then the object 87 * name is a <em>property value pattern</em>. The asterisk matches any 88 * sequence of zero or more characters, while the question mark matches 89 * any single character.</p> 90 * 91 * <p>A <em>quoted value</em> consists of a quote (<code>"</code>), 92 * followed by a possibly empty string of characters, followed by 93 * another quote. Within the string of characters, the backslash 94 * (<code>\</code>) has a special meaning. It must be followed by 95 * one of the following characters:</p> 96 * 97 * <ul> 98 * <li>Another backslash. The second backslash has no special 99 * meaning and the two characters represent a single backslash.</li> 100 * 101 * <li>The character 'n'. The two characters represent a newline 102 * ('\n' in Java).</li> 103 * 104 * <li>A quote. The two characters represent a quote, and that quote 105 * is not considered to terminate the quoted value. An ending closing 106 * quote must be present for the quoted value to be valid.</li> 107 * 108 * <li>A question mark (?) or asterisk (*). The two characters represent 109 * a question mark or asterisk respectively.</li> 110 * </ul> 111 * 112 * <p>A quote may not appear inside a quoted value except immediately 113 * after an odd number of consecutive backslashes.</p> 114 * 115 * <p>The quotes surrounding a quoted value, and any backslashes 116 * within that value, are considered to be part of the value.</p> 117 * 118 * <p>If the <em>quoted value</em> contains at least one occurrence of 119 * the characters asterisk or question mark and they are not preceded 120 * by a backslash, then they are considered as wildcard characters and 121 * the object name is a <em>property value pattern</em>. The asterisk 122 * matches any sequence of zero or more characters, while the question 123 * mark matches any single character.</p> 124 * 125 * <p>An ObjectName may be a <em>property list pattern</em>. In this 126 * case it may have zero or more keys and associated values. It matches 127 * a nonpattern ObjectName whose domain matches and that contains the 128 * same keys and associated values, as well as possibly other keys and 129 * values.</p> 130 * 131 * <p>An ObjectName is a <em>property value pattern</em> when at least 132 * one of its <em>quoted</em> or <em>unquoted</em> key property values 133 * contains the wildcard characters asterisk or question mark as described 134 * above. In this case it has one or more keys and associated values, with 135 * at least one of the values containing wildcard characters. It matches a 136 * nonpattern ObjectName whose domain matches and that contains the same 137 * keys whose values match; if the property value pattern is also a 138 * property list pattern then the nonpattern ObjectName can contain 139 * other keys and values.</p> 140 * 141 * <p>An ObjectName is a <em>property pattern</em> if it is either a 142 * <em>property list pattern</em> or a <em>property value pattern</em> 143 * or both.</p> 144 * 145 * <p>An ObjectName is a pattern if its domain contains a wildcard or 146 * if the ObjectName is a property pattern.</p> 147 * 148 * <p>If an ObjectName is not a pattern, it must contain at least one 149 * key with its associated value.</p> 150 * 151 * <p>Examples of ObjectName patterns are:</p> 152 * 153 * <ul> 154 * <li>{@code *:type=Foo,name=Bar} to match names in any domain whose 155 * exact set of keys is {@code type=Foo,name=Bar}.</li> 156 * <li>{@code d:type=Foo,name=Bar,*} to match names in the domain 157 * {@code d} that have the keys {@code type=Foo,name=Bar} plus 158 * zero or more other keys.</li> 159 * <li>{@code *:type=Foo,name=Bar,*} to match names in any domain 160 * that has the keys {@code type=Foo,name=Bar} plus zero or 161 * more other keys.</li> 162 * <li>{@code d:type=F?o,name=Bar} will match e.g. 163 * {@code d:type=Foo,name=Bar} and {@code d:type=Fro,name=Bar}.</li> 164 * <li>{@code d:type=F*o,name=Bar} will match e.g. 165 * {@code d:type=Fo,name=Bar} and {@code d:type=Frodo,name=Bar}.</li> 166 * <li>{@code d:type=Foo,name="B*"} will match e.g. 167 * {@code d:type=Foo,name="Bling"}. Wildcards are recognized even 168 * inside quotes, and like other special characters can be escaped 169 * with {@code \}.</li> 170 * </ul> 171 * 172 * <p>An ObjectName can be written as a String with the following 173 * elements in order:</p> 174 * 175 * <ul> 176 * <li>The domain. 177 * <li>A colon (<code>:</code>). 178 * <li>A key property list as defined below. 179 * </ul> 180 * 181 * <p>A key property list written as a String is a comma-separated 182 * list of elements. Each element is either an asterisk or a key 183 * property. A key property consists of a key, an equals 184 * (<code>=</code>), and the associated value.</p> 185 * 186 * <p>At most one element of a key property list may be an asterisk. 187 * If the key property list contains an asterisk element, the 188 * ObjectName is a property list pattern.</p> 189 * 190 * <p>Spaces have no special significance in a String representing an 191 * ObjectName. For example, the String: 192 * <pre> 193 * domain: key1 = value1 , key2 = value2 194 * </pre> 195 * represents an ObjectName with two keys. The name of each key 196 * contains six characters, of which the first and last are spaces. 197 * The value associated with the key <code>" key1 "</code> 198 * also begins and ends with a space.</p> 199 * 200 * <p>In addition to the restrictions on characters spelt out above, 201 * no part of an ObjectName may contain a newline character 202 * (<code>'\n'</code>), whether the domain, a key, or a value, whether 203 * quoted or unquoted. The newline character can be represented in a 204 * quoted value with the sequence <code>\n</code>. 205 * 206 * <p>The rules on special characters and quoting apply regardless of 207 * which constructor is used to make an ObjectName.</p> 208 * 209 * <p>To avoid collisions between MBeans supplied by different 210 * vendors, a useful convention is to begin the domain name with the 211 * reverse DNS name of the organization that specifies the MBeans, 212 * followed by a period and a string whose interpretation is 213 * determined by that organization. For example, MBeans specified by 214 * <code>example.com</code> would have 215 * domains such as <code>com.example.MyDomain</code>. This is essentially 216 * the same convention as for Java-language package names.</p> 217 * 218 * <p>The <b>serialVersionUID</b> of this class is <code>1081892073854801359L</code>. 219 * 220 * @since 1.5 221 */ 222 @SuppressWarnings("serial") // don't complain serialVersionUID not constant 223 public class ObjectName implements Comparable<ObjectName>, QueryExp { 224 225 /** 226 * A structure recording property structure and 227 * proposing minimal services 228 */ 229 private static class Property { 230 231 int _key_index; 232 int _key_length; 233 int _value_length; 234 235 /** 236 * Constructor. 237 */ 238 Property(int key_index, int key_length, int value_length) { 239 _key_index = key_index; 240 _key_length = key_length; 241 _value_length = value_length; 242 } 243 244 /** 245 * Assigns the key index of property 246 */ 247 void setKeyIndex(int key_index) { 248 _key_index = key_index; 249 } 250 251 /** 252 * Returns a key string for receiver key 253 */ 254 String getKeyString(String name) { 255 return name.substring(_key_index, _key_index + _key_length); 256 } 257 258 /** 259 * Returns a value string for receiver key 260 */ 261 String getValueString(String name) { 262 int in_begin = _key_index + _key_length + 1; 263 int out_end = in_begin + _value_length; 264 return name.substring(in_begin, out_end); 265 } 266 } 267 268 /** 269 * Marker class for value pattern property. 270 */ 271 private static class PatternProperty extends Property { 272 /** 273 * Constructor. 274 */ 275 PatternProperty(int key_index, int key_length, int value_length) { 276 super(key_index, key_length, value_length); 277 } 278 } 279 280 // Inner classes <======================================== 281 282 283 284 // Private fields ----------------------------------------> 285 286 287 // Serialization compatibility stuff --------------------> 288 289 // Two serial forms are supported in this class. The selected form depends 290 // on system property "jmx.serial.form": 291 // - "1.0" for JMX 1.0 292 // - any other value for JMX 1.1 and higher 293 // 294 // Serial version for old serial form 295 private static final long oldSerialVersionUID = -5467795090068647408L; 296 // 297 // Serial version for new serial form 298 private static final long newSerialVersionUID = 1081892073854801359L; 299 // 300 // Serializable fields in old serial form 301 private static final ObjectStreamField[] oldSerialPersistentFields = 302 { 303 new ObjectStreamField("domain", String.class), 304 new ObjectStreamField("propertyList", Hashtable.class), 305 new ObjectStreamField("propertyListString", String.class), 306 new ObjectStreamField("canonicalName", String.class), 307 new ObjectStreamField("pattern", Boolean.TYPE), 308 new ObjectStreamField("propertyPattern", Boolean.TYPE) 309 }; 310 // 311 // Serializable fields in new serial form 312 private static final ObjectStreamField[] newSerialPersistentFields = { }; 313 // 314 // Actual serial version and serial form 315 private static final long serialVersionUID; 316 private static final ObjectStreamField[] serialPersistentFields; 317 private static boolean compat = false; 318 static { 319 try { 320 GetPropertyAction act = new GetPropertyAction("jmx.serial.form"); 321 String form = AccessController.doPrivileged(act); 322 compat = (form != null && form.equals("1.0")); 323 } catch (Exception e) { 324 // OK: exception means no compat with 1.0, too bad 325 } 326 if (compat) { 327 serialPersistentFields = oldSerialPersistentFields; 328 serialVersionUID = oldSerialVersionUID; 329 } else { 330 serialPersistentFields = newSerialPersistentFields; 331 serialVersionUID = newSerialVersionUID; 332 } 333 } 334 335 // 336 // Serialization compatibility stuff <============================== 337 338 // Class private fields -----------------------------------> 339 340 /** 341 * a shared empty array for empty property lists 342 */ 343 static final private Property[] _Empty_property_array = new Property[0]; 344 345 346 // Class private fields <============================== 347 348 // Instance private fields -----------------------------------> 349 350 /** 351 * a String containing the canonical name 352 */ 353 private transient String _canonicalName; 354 355 356 /** 357 * An array of properties in the same seq order as time creation 358 */ 359 private transient Property[] _kp_array; 360 361 /** 362 * An array of properties in the same seq order as canonical order 363 */ 364 private transient Property[] _ca_array; 365 366 367 /** 368 * The length of the domain part of built objectname 369 */ 370 private transient int _domain_length = 0; 371 372 373 /** 374 * The propertyList of built object name. Initialized lazily. 375 * Table that contains all the pairs (key,value) for this ObjectName. 376 */ 377 private transient Map<String,String> _propertyList; 378 379 /** 380 * boolean that declares if this ObjectName domain part is a pattern 381 */ 382 private transient boolean _domain_pattern = false; 383 384 /** 385 * boolean that declares if this ObjectName contains a pattern on the 386 * key property list 387 */ 388 private transient boolean _property_list_pattern = false; 389 390 /** 391 * boolean that declares if this ObjectName contains a pattern on the 392 * value of at least one key property 393 */ 394 private transient boolean _property_value_pattern = false; 395 396 // Instance private fields <======================================= 397 398 // Private fields <======================================== 399 400 401 // Private methods ----------------------------------------> 402 403 // Category : Instance construction -------------------------> 404 405 /** 406 * Initializes this {@link ObjectName} from the given string 407 * representation. 408 * 409 * @param name A string representation of the {@link ObjectName} 410 * 411 * @exception MalformedObjectNameException The string passed as a 412 * parameter does not have the right format. 413 * @exception NullPointerException The <code>name</code> parameter 414 * is null. 415 */ 416 private void construct(String name) 417 throws MalformedObjectNameException { 418 419 // The name cannot be null 420 if (name == null) 421 throw new NullPointerException("name cannot be null"); 422 423 // Test if the name is empty 424 if (name.length() == 0) { 425 // this is equivalent to the whole word query object name. 426 _canonicalName = "*:*"; 427 _kp_array = _Empty_property_array; 428 _ca_array = _Empty_property_array; 429 _domain_length = 1; 430 _propertyList = null; 431 _domain_pattern = true; 432 _property_list_pattern = true; 433 _property_value_pattern = false; 434 return; 435 } 436 437 // initialize parsing of the string 438 final char[] name_chars = name.toCharArray(); 439 final int len = name_chars.length; 440 final char[] canonical_chars = new char[len]; // canonical form will 441 // be same length at most 442 int cname_index = 0; 443 int index = 0; 444 char c, c1; 445 446 // parses domain part 447 domain_parsing: 448 while (index < len) { 449 switch (name_chars[index]) { 450 case ':' : 451 _domain_length = index++; 452 break domain_parsing; 453 case '=' : 454 // ":" omission check. 455 // 456 // Although "=" is a valid character in the domain part 457 // it is true that it is rarely used in the real world. 458 // So check straight away if the ":" has been omitted 459 // from the ObjectName. This allows us to provide a more 460 // accurate exception message. 461 int i = ++index; 462 while ((i < len) && (name_chars[i++] != ':')) 463 if (i == len) 464 throw new MalformedObjectNameException( 465 "Domain part must be specified"); 466 break; 467 case '\n' : 468 throw new MalformedObjectNameException( 469 "Invalid character '\\n' in domain name"); 470 case '*' : 471 case '?' : 472 _domain_pattern = true; 473 index++; 474 break; 475 default : 476 index++; 477 break; 478 } 479 } 480 481 // check for non-empty properties 482 if (index == len) 483 throw new MalformedObjectNameException( 484 "Key properties cannot be empty"); 485 486 // we have got the domain part, begins building of _canonicalName 487 System.arraycopy(name_chars, 0, canonical_chars, 0, _domain_length); 488 canonical_chars[_domain_length] = ':'; 489 cname_index = _domain_length + 1; 490 491 // parses property list 492 Property prop; 493 Map<String,Property> keys_map = new HashMap<String,Property>(); 494 String[] keys; 495 String key_name; 496 boolean quoted_value; 497 int property_index = 0; 498 int in_index; 499 int key_index, key_length, value_index, value_length; 500 501 keys = new String[10]; 502 _kp_array = new Property[10]; 503 _property_list_pattern = false; 504 _property_value_pattern = false; 505 506 while (index < len) { 507 c = name_chars[index]; 508 509 // case of pattern properties 510 if (c == '*') { 511 if (_property_list_pattern) 512 throw new MalformedObjectNameException( 513 "Cannot have several '*' characters in pattern " + 514 "property list"); 515 else { 516 _property_list_pattern = true; 517 if ((++index < len ) && (name_chars[index] != ',')) 518 throw new MalformedObjectNameException( 519 "Invalid character found after '*': end of " + 520 "name or ',' expected"); 521 else if (index == len) { 522 if (property_index == 0) { 523 // empty properties case 524 _kp_array = _Empty_property_array; 525 _ca_array = _Empty_property_array; 526 _propertyList = Collections.emptyMap(); 527 } 528 break; 529 } else { 530 // correct pattern spec in props, continue 531 index++; 532 continue; 533 } 534 } 535 } 536 537 // standard property case, key part 538 in_index = index; 539 key_index = in_index; 540 if (name_chars[in_index] == '=') 541 throw new MalformedObjectNameException("Invalid key (empty)"); 542 while ((in_index < len) && ((c1 = name_chars[in_index++]) != '=')) 543 switch (c1) { 544 // '=' considered to introduce value part 545 case '*' : 546 case '?' : 547 case ',' : 548 case ':' : 549 case '\n' : 550 final String ichar = ((c1=='\n')?"\\n":""+c1); 551 throw new MalformedObjectNameException( 552 "Invalid character '" + ichar + 553 "' in key part of property"); 554 } 555 if (name_chars[in_index - 1] != '=') 556 throw new MalformedObjectNameException( 557 "Unterminated key property part"); 558 value_index = in_index; // in_index pointing after '=' char 559 key_length = value_index - key_index - 1; // found end of key 560 561 // standard property case, value part 562 boolean value_pattern = false; 563 if (in_index < len && name_chars[in_index] == '\"') { 564 quoted_value = true; 565 // the case of quoted value part 566 quoted_value_parsing: 567 while ((++in_index < len) && 568 ((c1 = name_chars[in_index]) != '\"')) { 569 // the case of an escaped character 570 if (c1 == '\\') { 571 if (++in_index == len) 572 throw new MalformedObjectNameException( 573 "Unterminated quoted value"); 574 switch (c1 = name_chars[in_index]) { 575 case '\\' : 576 case '\"' : 577 case '?' : 578 case '*' : 579 case 'n' : 580 break; // valid character 581 default : 582 throw new MalformedObjectNameException( 583 "Invalid escape sequence '\\" + 584 c1 + "' in quoted value"); 585 } 586 } else if (c1 == '\n') { 587 throw new MalformedObjectNameException( 588 "Newline in quoted value"); 589 } else { 590 switch (c1) { 591 case '?' : 592 case '*' : 593 value_pattern = true; 594 break; 595 } 596 } 597 } 598 if (in_index == len) 599 throw new MalformedObjectNameException( 600 "Unterminated quoted value"); 601 else value_length = ++in_index - value_index; 602 } else { 603 // the case of standard value part 604 quoted_value = false; 605 while ((in_index < len) && ((c1 = name_chars[in_index]) != ',')) 606 switch (c1) { 607 // ',' considered to be the value separator 608 case '*' : 609 case '?' : 610 value_pattern = true; 611 in_index++; 612 break; 613 case '=' : 614 case ':' : 615 case '"' : 616 case '\n' : 617 final String ichar = ((c1=='\n')?"\\n":""+c1); 618 throw new MalformedObjectNameException( 619 "Invalid character '" + ichar + 620 "' in value part of property"); 621 default : 622 in_index++; 623 break; 624 } 625 value_length = in_index - value_index; 626 } 627 628 // Parsed property, checks the end of name 629 if (in_index == len - 1) { 630 if (quoted_value) 631 throw new MalformedObjectNameException( 632 "Invalid ending character `" + 633 name_chars[in_index] + "'"); 634 else throw new MalformedObjectNameException( 635 "Invalid ending comma"); 636 } else in_index++; 637 638 // we got the key and value part, prepare a property for this 639 if (!value_pattern) { 640 prop = new Property(key_index, key_length, value_length); 641 } else { 642 _property_value_pattern = true; 643 prop = new PatternProperty(key_index, key_length, value_length); 644 } 645 key_name = name.substring(key_index, key_index + key_length); 646 647 if (property_index == keys.length) { 648 String[] tmp_string_array = new String[property_index + 10]; 649 System.arraycopy(keys, 0, tmp_string_array, 0, property_index); 650 keys = tmp_string_array; 651 } 652 keys[property_index] = key_name; 653 654 addProperty(prop, property_index, keys_map, key_name); 655 property_index++; 656 index = in_index; 657 } 658 659 // computes and set canonical name 660 setCanonicalName(name_chars, canonical_chars, keys, 661 keys_map, cname_index, property_index); 662 } 663 664 /** 665 * Construct an ObjectName from a domain and a Hashtable. 666 * 667 * @param domain Domain of the ObjectName. 668 * @param props Map containing couples <i>key</i> -> <i>value</i>. 669 * 670 * @exception MalformedObjectNameException The <code>domain</code> 671 * contains an illegal character, or one of the keys or values in 672 * <code>table</code> contains an illegal character, or one of the 673 * values in <code>table</code> does not follow the rules for quoting. 674 * @exception NullPointerException One of the parameters is null. 675 */ 676 private void construct(String domain, Map<String,String> props) 677 throws MalformedObjectNameException { 678 679 // The domain cannot be null 680 if (domain == null) 681 throw new NullPointerException("domain cannot be null"); 682 683 // The key property list cannot be null 684 if (props == null) 685 throw new NullPointerException("key property list cannot be null"); 686 687 // The key property list cannot be empty 688 if (props.isEmpty()) 689 throw new MalformedObjectNameException( 690 "key property list cannot be empty"); 691 692 // checks domain validity 693 if (!isDomain(domain)) 694 throw new MalformedObjectNameException("Invalid domain: " + domain); 695 696 // init canonicalname 697 final StringBuilder sb = new StringBuilder(); 698 sb.append(domain).append(':'); 699 _domain_length = domain.length(); 700 701 // allocates the property array 702 int nb_props = props.size(); 703 _kp_array = new Property[nb_props]; 704 705 String[] keys = new String[nb_props]; 706 final Map<String,Property> keys_map = new HashMap<String,Property>(); 707 Property prop; 708 int key_index; 709 int i = 0; 710 for (Map.Entry<String,String> entry : props.entrySet()) { 711 if (sb.length() > 0) 712 sb.append(","); 713 String key = entry.getKey(); 714 String value; 715 try { 716 value = entry.getValue(); 717 } catch (ClassCastException e) { 718 throw new MalformedObjectNameException(e.getMessage()); 719 } 720 key_index = sb.length(); 721 checkKey(key); 722 sb.append(key); 723 keys[i] = key; 724 sb.append("="); 725 boolean value_pattern = checkValue(value); 726 sb.append(value); 727 if (!value_pattern) { 728 prop = new Property(key_index, 729 key.length(), 730 value.length()); 731 } else { 732 _property_value_pattern = true; 733 prop = new PatternProperty(key_index, 734 key.length(), 735 value.length()); 736 } 737 addProperty(prop, i, keys_map, key); 738 i++; 739 } 740 741 // initialize canonical name and data structure 742 int len = sb.length(); 743 char[] initial_chars = new char[len]; 744 sb.getChars(0, len, initial_chars, 0); 745 char[] canonical_chars = new char[len]; 746 System.arraycopy(initial_chars, 0, canonical_chars, 0, 747 _domain_length + 1); 748 setCanonicalName(initial_chars, canonical_chars, keys, keys_map, 749 _domain_length + 1, _kp_array.length); 750 } 751 // Category : Instance construction <============================== 752 753 // Category : Internal utilities ------------------------------> 754 755 /** 756 * Add passed property to the list at the given index 757 * for the passed key name 758 */ 759 private void addProperty(Property prop, int index, 760 Map<String,Property> keys_map, String key_name) 761 throws MalformedObjectNameException { 762 763 if (keys_map.containsKey(key_name)) throw new 764 MalformedObjectNameException("key `" + 765 key_name +"' already defined"); 766 767 // if no more space for property arrays, have to increase it 768 if (index == _kp_array.length) { 769 Property[] tmp_prop_array = new Property[index + 10]; 770 System.arraycopy(_kp_array, 0, tmp_prop_array, 0, index); 771 _kp_array = tmp_prop_array; 772 } 773 _kp_array[index] = prop; 774 keys_map.put(key_name, prop); 775 } 776 777 /** 778 * Sets the canonical name of receiver from input 'specified_chars' 779 * array, by filling 'canonical_chars' array with found 'nb-props' 780 * properties starting at position 'prop_index'. 781 */ 782 private void setCanonicalName(char[] specified_chars, 783 char[] canonical_chars, 784 String[] keys, Map<String,Property> keys_map, 785 int prop_index, int nb_props) { 786 787 // Sort the list of found properties 788 if (_kp_array != _Empty_property_array) { 789 String[] tmp_keys = new String[nb_props]; 790 Property[] tmp_props = new Property[nb_props]; 791 792 System.arraycopy(keys, 0, tmp_keys, 0, nb_props); 793 Arrays.sort(tmp_keys); 794 keys = tmp_keys; 795 System.arraycopy(_kp_array, 0, tmp_props, 0 , nb_props); 796 _kp_array = tmp_props; 797 _ca_array = new Property[nb_props]; 798 799 // now assigns _ca_array to the sorted list of keys 800 // (there cannot be two identical keys in an objectname. 801 for (int i = 0; i < nb_props; i++) 802 _ca_array[i] = keys_map.get(keys[i]); 803 804 // now we build the canonical name and set begin indexes of 805 // properties to reflect canonical form 806 int last_index = nb_props - 1; 807 int prop_len; 808 Property prop; 809 for (int i = 0; i <= last_index; i++) { 810 prop = _ca_array[i]; 811 // length of prop including '=' char 812 prop_len = prop._key_length + prop._value_length + 1; 813 System.arraycopy(specified_chars, prop._key_index, 814 canonical_chars, prop_index, prop_len); 815 prop.setKeyIndex(prop_index); 816 prop_index += prop_len; 817 if (i != last_index) { 818 canonical_chars[prop_index] = ','; 819 prop_index++; 820 } 821 } 822 } 823 824 // terminate canonicalname with '*' in case of pattern 825 if (_property_list_pattern) { 826 if (_kp_array != _Empty_property_array) 827 canonical_chars[prop_index++] = ','; 828 canonical_chars[prop_index++] = '*'; 829 } 830 831 // we now build the canonicalname string 832 _canonicalName = (new String(canonical_chars, 0, prop_index)).intern(); 833 } 834 835 /** 836 * Parse a key. 837 * <pre>final int endKey=parseKey(s,startKey);</pre> 838 * <p>key starts at startKey (included), and ends at endKey (excluded). 839 * If (startKey == endKey), then the key is empty. 840 * 841 * @param s The char array of the original string. 842 * @param startKey index at which to begin parsing. 843 * @return The index following the last character of the key. 844 **/ 845 private static int parseKey(final char[] s, final int startKey) 846 throws MalformedObjectNameException { 847 int next = startKey; 848 int endKey = startKey; 849 final int len = s.length; 850 while (next < len) { 851 final char k = s[next++]; 852 switch (k) { 853 case '*': 854 case '?': 855 case ',': 856 case ':': 857 case '\n': 858 final String ichar = ((k=='\n')?"\\n":""+k); 859 throw new 860 MalformedObjectNameException("Invalid character in key: `" 861 + ichar + "'"); 862 case '=': 863 // we got the key. 864 endKey = next-1; 865 break; 866 default: 867 if (next < len) continue; 868 else endKey=next; 869 } 870 break; 871 } 872 return endKey; 873 } 874 875 /** 876 * Parse a value. 877 * <pre>final int endVal=parseValue(s,startVal);</pre> 878 * <p>value starts at startVal (included), and ends at endVal (excluded). 879 * If (startVal == endVal), then the key is empty. 880 * 881 * @param s The char array of the original string. 882 * @param startValue index at which to begin parsing. 883 * @return The first element of the int array indicates the index 884 * following the last character of the value. The second 885 * element of the int array indicates that the value is 886 * a pattern when its value equals 1. 887 **/ 888 private static int[] parseValue(final char[] s, final int startValue) 889 throws MalformedObjectNameException { 890 891 boolean value_pattern = false; 892 893 int next = startValue; 894 int endValue = startValue; 895 896 final int len = s.length; 897 final char q=s[startValue]; 898 899 if (q == '"') { 900 // quoted value 901 if (++next == len) throw new 902 MalformedObjectNameException("Invalid quote"); 903 while (next < len) { 904 char last = s[next]; 905 if (last == '\\') { 906 if (++next == len) throw new 907 MalformedObjectNameException( 908 "Invalid unterminated quoted character sequence"); 909 last = s[next]; 910 switch (last) { 911 case '\\' : 912 case '?' : 913 case '*' : 914 case 'n' : 915 break; 916 case '\"' : 917 // We have an escaped quote. If this escaped 918 // quote is the last character, it does not 919 // qualify as a valid termination quote. 920 // 921 if (next+1 == len) throw new 922 MalformedObjectNameException( 923 "Missing termination quote"); 924 break; 925 default: 926 throw new 927 MalformedObjectNameException( 928 "Invalid quoted character sequence '\\" + 929 last + "'"); 930 } 931 } else if (last == '\n') { 932 throw new MalformedObjectNameException( 933 "Newline in quoted value"); 934 } else if (last == '\"') { 935 next++; 936 break; 937 } else { 938 switch (last) { 939 case '?' : 940 case '*' : 941 value_pattern = true; 942 break; 943 } 944 } 945 next++; 946 947 // Check that last character is a termination quote. 948 // We have already handled the case were the last 949 // character is an escaped quote earlier. 950 // 951 if ((next >= len) && (last != '\"')) throw new 952 MalformedObjectNameException("Missing termination quote"); 953 } 954 endValue = next; 955 if (next < len) { 956 if (s[next++] != ',') throw new 957 MalformedObjectNameException("Invalid quote"); 958 } 959 } else { 960 // Non quoted value. 961 while (next < len) { 962 final char v=s[next++]; 963 switch(v) { 964 case '*': 965 case '?': 966 value_pattern = true; 967 if (next < len) continue; 968 else endValue=next; 969 break; 970 case '=': 971 case ':': 972 case '\n' : 973 final String ichar = ((v=='\n')?"\\n":""+v); 974 throw new 975 MalformedObjectNameException("Invalid character `" + 976 ichar + "' in value"); 977 case ',': 978 endValue = next-1; 979 break; 980 default: 981 if (next < len) continue; 982 else endValue=next; 983 } 984 break; 985 } 986 } 987 return new int[] { endValue, value_pattern ? 1 : 0 }; 988 } 989 990 /** 991 * Check if the supplied value is a valid value. 992 * 993 * @return true if the value is a pattern, otherwise false. 994 */ 995 private static boolean checkValue(String val) 996 throws MalformedObjectNameException { 997 998 if (val == null) throw new 999 NullPointerException("Invalid value (null)"); 1000 1001 final int len = val.length(); 1002 if (len == 0) 1003 return false; 1004 1005 final char[] s = val.toCharArray(); 1006 final int[] result = parseValue(s,0); 1007 final int endValue = result[0]; 1008 final boolean value_pattern = result[1] == 1; 1009 if (endValue < len) throw new 1010 MalformedObjectNameException("Invalid character in value: `" + 1011 s[endValue] + "'"); 1012 return value_pattern; 1013 } 1014 1015 /** 1016 * Check if the supplied key is a valid key. 1017 */ 1018 private static void checkKey(String key) 1019 throws MalformedObjectNameException { 1020 1021 if (key == null) throw new 1022 NullPointerException("Invalid key (null)"); 1023 1024 final int len = key.length(); 1025 if (len == 0) throw new 1026 MalformedObjectNameException("Invalid key (empty)"); 1027 final char[] k=key.toCharArray(); 1028 final int endKey = parseKey(k,0); 1029 if (endKey < len) throw new 1030 MalformedObjectNameException("Invalid character in value: `" + 1031 k[endKey] + "'"); 1032 } 1033 1034 1035 // Category : Internal utilities <============================== 1036 1037 // Category : Internal accessors ------------------------------> 1038 1039 /** 1040 * Check if domain is a valid domain. Set _domain_pattern if appropriate. 1041 */ 1042 private boolean isDomain(String domain) { 1043 if (domain == null) return true; 1044 final int len = domain.length(); 1045 int next = 0; 1046 while (next < len) { 1047 final char c = domain.charAt(next++); 1048 switch (c) { 1049 case ':' : 1050 case '\n' : 1051 return false; 1052 case '*' : 1053 case '?' : 1054 _domain_pattern = true; 1055 break; 1056 } 1057 } 1058 return true; 1059 } 1060 1061 // Category : Internal accessors <============================== 1062 1063 // Category : Serialization -----------------------------------> 1064 1065 /** 1066 * Deserializes an {@link ObjectName} from an {@link ObjectInputStream}. 1067 * @serialData <ul> 1068 * <li>In the current serial form (value of property 1069 * <code>jmx.serial.form</code> differs from 1070 * <code>1.0</code>): the string 1071 * "<domain>:<properties><wild>", 1072 * where: <ul> 1073 * <li><domain> represents the domain part 1074 * of the {@link ObjectName}</li> 1075 * <li><properties> represents the list of 1076 * properties, as returned by 1077 * {@link #getKeyPropertyListString} 1078 * <li><wild> is empty if not 1079 * <code>isPropertyPattern</code>, or 1080 * is the character "<code>*</code>" if 1081 * <code>isPropertyPattern</code> 1082 * and <properties> is empty, or 1083 * is "<code>,*</code>" if 1084 * <code>isPropertyPattern</code> and 1085 * <properties> is not empty. 1086 * </li> 1087 * </ul> 1088 * The intent is that this string could be supplied 1089 * to the {@link #ObjectName(String)} constructor to 1090 * produce an equivalent {@link ObjectName}. 1091 * </li> 1092 * <li>In the old serial form (value of property 1093 * <code>jmx.serial.form</code> is 1094 * <code>1.0</code>): <domain> <propertyList> 1095 * <propertyListString> <canonicalName> 1096 * <pattern> <propertyPattern>, 1097 * where: <ul> 1098 * <li><domain> represents the domain part 1099 * of the {@link ObjectName}</li> 1100 * <li><propertyList> is the 1101 * {@link Hashtable} that contains all the 1102 * pairs (key,value) for this 1103 * {@link ObjectName}</li> 1104 * <li><propertyListString> is the 1105 * {@link String} representation of the 1106 * list of properties in any order (not 1107 * mandatorily a canonical representation) 1108 * </li> 1109 * <li><canonicalName> is the 1110 * {@link String} containing this 1111 * {@link ObjectName}'s canonical name</li> 1112 * <li><pattern> is a boolean which is 1113 * <code>true</code> if this 1114 * {@link ObjectName} contains a pattern</li> 1115 * <li><propertyPattern> is a boolean which 1116 * is <code>true</code> if this 1117 * {@link ObjectName} contains a pattern in 1118 * the list of properties</li> 1119 * </ul> 1120 * </li> 1121 * </ul> 1122 */ 1123 private void readObject(ObjectInputStream in) 1124 throws IOException, ClassNotFoundException { 1125 1126 String cn; 1127 if (compat) { 1128 // Read an object serialized in the old serial form 1129 // 1130 //in.defaultReadObject(); 1131 final ObjectInputStream.GetField fields = in.readFields(); 1132 String propListString = 1133 (String)fields.get("propertyListString", ""); 1134 1135 // 6616825: take care of property patterns 1136 final boolean propPattern = 1137 fields.get("propertyPattern" , false); 1138 if (propPattern) { 1139 propListString = 1140 (propListString.length()==0?"*":(propListString+",*")); 1141 } 1142 1143 cn = (String)fields.get("domain", "default")+ 1144 ":"+ propListString; 1145 } else { 1146 // Read an object serialized in the new serial form 1147 // 1148 in.defaultReadObject(); 1149 cn = (String)in.readObject(); 1150 } 1151 1152 try { 1153 construct(cn); 1154 } catch (NullPointerException e) { 1155 throw new InvalidObjectException(e.toString()); 1156 } catch (MalformedObjectNameException e) { 1157 throw new InvalidObjectException(e.toString()); 1158 } 1159 } 1160 1161 1162 /** 1163 * Serializes an {@link ObjectName} to an {@link ObjectOutputStream}. 1164 * @serialData <ul> 1165 * <li>In the current serial form (value of property 1166 * <code>jmx.serial.form</code> differs from 1167 * <code>1.0</code>): the string 1168 * "<domain>:<properties><wild>", 1169 * where: <ul> 1170 * <li><domain> represents the domain part 1171 * of the {@link ObjectName}</li> 1172 * <li><properties> represents the list of 1173 * properties, as returned by 1174 * {@link #getKeyPropertyListString} 1175 * <li><wild> is empty if not 1176 * <code>isPropertyPattern</code>, or 1177 * is the character "<code>*</code>" if 1178 * this <code>isPropertyPattern</code> 1179 * and <properties> is empty, or 1180 * is "<code>,*</code>" if 1181 * <code>isPropertyPattern</code> and 1182 * <properties> is not empty. 1183 * </li> 1184 * </ul> 1185 * The intent is that this string could be supplied 1186 * to the {@link #ObjectName(String)} constructor to 1187 * produce an equivalent {@link ObjectName}. 1188 * </li> 1189 * <li>In the old serial form (value of property 1190 * <code>jmx.serial.form</code> is 1191 * <code>1.0</code>): <domain> <propertyList> 1192 * <propertyListString> <canonicalName> 1193 * <pattern> <propertyPattern>, 1194 * where: <ul> 1195 * <li><domain> represents the domain part 1196 * of the {@link ObjectName}</li> 1197 * <li><propertyList> is the 1198 * {@link Hashtable} that contains all the 1199 * pairs (key,value) for this 1200 * {@link ObjectName}</li> 1201 * <li><propertyListString> is the 1202 * {@link String} representation of the 1203 * list of properties in any order (not 1204 * mandatorily a canonical representation) 1205 * </li> 1206 * <li><canonicalName> is the 1207 * {@link String} containing this 1208 * {@link ObjectName}'s canonical name</li> 1209 * <li><pattern> is a boolean which is 1210 * <code>true</code> if this 1211 * {@link ObjectName} contains a pattern</li> 1212 * <li><propertyPattern> is a boolean which 1213 * is <code>true</code> if this 1214 * {@link ObjectName} contains a pattern in 1215 * the list of properties</li> 1216 * </ul> 1217 * </li> 1218 * </ul> 1219 */ 1220 private void writeObject(ObjectOutputStream out) 1221 throws IOException { 1222 1223 if (compat) 1224 { 1225 // Serializes this instance in the old serial form 1226 // Read CR 6441274 before making any changes to this code 1227 ObjectOutputStream.PutField fields = out.putFields(); 1228 fields.put("domain", _canonicalName.substring(0, _domain_length)); 1229 fields.put("propertyList", getKeyPropertyList()); 1230 fields.put("propertyListString", getKeyPropertyListString()); 1231 fields.put("canonicalName", _canonicalName); 1232 fields.put("pattern", (_domain_pattern || _property_list_pattern)); 1233 fields.put("propertyPattern", _property_list_pattern); 1234 out.writeFields(); 1235 } 1236 else 1237 { 1238 // Serializes this instance in the new serial form 1239 // 1240 out.defaultWriteObject(); 1241 out.writeObject(getSerializedNameString()); 1242 } 1243 } 1244 1245 // Category : Serialization <=================================== 1246 1247 // Private methods <======================================== 1248 1249 // Public methods ----------------------------------------> 1250 1251 // Category : ObjectName Construction ------------------------------> 1252 1253 /** 1254 * <p>Return an instance of ObjectName that can be used anywhere 1255 * an object obtained with {@link #ObjectName(String) new 1256 * ObjectName(name)} can be used. The returned object may be of 1257 * a subclass of ObjectName. Calling this method twice with the 1258 * same parameters may return the same object or two equal but 1259 * not identical objects.</p> 1260 * 1261 * @param name A string representation of the object name. 1262 * 1263 * @return an ObjectName corresponding to the given String. 1264 * 1265 * @exception MalformedObjectNameException The string passed as a 1266 * parameter does not have the right format. 1267 * @exception NullPointerException The <code>name</code> parameter 1268 * is null. 1269 * 1270 */ 1271 public static ObjectName getInstance(String name) 1272 throws MalformedObjectNameException, NullPointerException { 1273 return new ObjectName(name); 1274 } 1275 1276 /** 1277 * <p>Return an instance of ObjectName that can be used anywhere 1278 * an object obtained with {@link #ObjectName(String, String, 1279 * String) new ObjectName(domain, key, value)} can be used. The 1280 * returned object may be of a subclass of ObjectName. Calling 1281 * this method twice with the same parameters may return the same 1282 * object or two equal but not identical objects.</p> 1283 * 1284 * @param domain The domain part of the object name. 1285 * @param key The attribute in the key property of the object name. 1286 * @param value The value in the key property of the object name. 1287 * 1288 * @return an ObjectName corresponding to the given domain, 1289 * key, and value. 1290 * 1291 * @exception MalformedObjectNameException The 1292 * <code>domain</code>, <code>key</code>, or <code>value</code> 1293 * contains an illegal character, or <code>value</code> does not 1294 * follow the rules for quoting. 1295 * @exception NullPointerException One of the parameters is null. 1296 * 1297 */ 1298 public static ObjectName getInstance(String domain, String key, 1299 String value) 1300 throws MalformedObjectNameException { 1301 return new ObjectName(domain, key, value); 1302 } 1303 1304 /** 1305 * <p>Return an instance of ObjectName that can be used anywhere 1306 * an object obtained with {@link #ObjectName(String, Hashtable) 1307 * new ObjectName(domain, table)} can be used. The returned 1308 * object may be of a subclass of ObjectName. Calling this method 1309 * twice with the same parameters may return the same object or 1310 * two equal but not identical objects.</p> 1311 * 1312 * @param domain The domain part of the object name. 1313 * @param table A hash table containing one or more key 1314 * properties. The key of each entry in the table is the key of a 1315 * key property in the object name. The associated value in the 1316 * table is the associated value in the object name. 1317 * 1318 * @return an ObjectName corresponding to the given domain and 1319 * key mappings. 1320 * 1321 * @exception MalformedObjectNameException The <code>domain</code> 1322 * contains an illegal character, or one of the keys or values in 1323 * <code>table</code> contains an illegal character, or one of the 1324 * values in <code>table</code> does not follow the rules for 1325 * quoting. 1326 * @exception NullPointerException One of the parameters is null. 1327 * 1328 */ 1329 public static ObjectName getInstance(String domain, 1330 Hashtable<String,String> table) 1331 throws MalformedObjectNameException { 1332 return new ObjectName(domain, table); 1333 } 1334 1335 /** 1336 * <p>Return an instance of ObjectName that can be used anywhere 1337 * the given object can be used. The returned object may be of a 1338 * subclass of ObjectName. If <code>name</code> is of a subclass 1339 * of ObjectName, it is not guaranteed that the returned object 1340 * will be of the same class.</p> 1341 * 1342 * <p>The returned value may or may not be identical to 1343 * <code>name</code>. Calling this method twice with the same 1344 * parameters may return the same object or two equal but not 1345 * identical objects.</p> 1346 * 1347 * <p>Since ObjectName is immutable, it is not usually useful to 1348 * make a copy of an ObjectName. The principal use of this method 1349 * is to guard against a malicious caller who might pass an 1350 * instance of a subclass with surprising behavior to sensitive 1351 * code. Such code can call this method to obtain an ObjectName 1352 * that is known not to have surprising behavior.</p> 1353 * 1354 * @param name an instance of the ObjectName class or of a subclass 1355 * 1356 * @return an instance of ObjectName or a subclass that is known to 1357 * have the same semantics. If <code>name</code> respects the 1358 * semantics of ObjectName, then the returned object is equal 1359 * (though not necessarily identical) to <code>name</code>. 1360 * 1361 * @exception NullPointerException The <code>name</code> is null. 1362 * 1363 */ 1364 public static ObjectName getInstance(ObjectName name) { 1365 if (name.getClass().equals(ObjectName.class)) 1366 return name; 1367 return Util.newObjectName(name.getSerializedNameString()); 1368 } 1369 1370 /** 1371 * Construct an object name from the given string. 1372 * 1373 * @param name A string representation of the object name. 1374 * 1375 * @exception MalformedObjectNameException The string passed as a 1376 * parameter does not have the right format. 1377 * @exception NullPointerException The <code>name</code> parameter 1378 * is null. 1379 */ 1380 public ObjectName(String name) 1381 throws MalformedObjectNameException { 1382 construct(name); 1383 } 1384 1385 /** 1386 * Construct an object name with exactly one key property. 1387 * 1388 * @param domain The domain part of the object name. 1389 * @param key The attribute in the key property of the object name. 1390 * @param value The value in the key property of the object name. 1391 * 1392 * @exception MalformedObjectNameException The 1393 * <code>domain</code>, <code>key</code>, or <code>value</code> 1394 * contains an illegal character, or <code>value</code> does not 1395 * follow the rules for quoting. 1396 * @exception NullPointerException One of the parameters is null. 1397 */ 1398 public ObjectName(String domain, String key, String value) 1399 throws MalformedObjectNameException { 1400 // If key or value are null a NullPointerException 1401 // will be thrown by the put method in Hashtable. 1402 // 1403 Map<String,String> table = Collections.singletonMap(key, value); 1404 construct(domain, table); 1405 } 1406 1407 /** 1408 * Construct an object name with several key properties from a Hashtable. 1409 * 1410 * @param domain The domain part of the object name. 1411 * @param table A hash table containing one or more key 1412 * properties. The key of each entry in the table is the key of a 1413 * key property in the object name. The associated value in the 1414 * table is the associated value in the object name. 1415 * 1416 * @exception MalformedObjectNameException The <code>domain</code> 1417 * contains an illegal character, or one of the keys or values in 1418 * <code>table</code> contains an illegal character, or one of the 1419 * values in <code>table</code> does not follow the rules for 1420 * quoting. 1421 * @exception NullPointerException One of the parameters is null. 1422 */ 1423 public ObjectName(String domain, Hashtable<String,String> table) 1424 throws MalformedObjectNameException { 1425 construct(domain, table); 1426 /* The exception for when a key or value in the table is not a 1427 String is now ClassCastException rather than 1428 MalformedObjectNameException. This was not previously 1429 specified. */ 1430 } 1431 1432 // Category : ObjectName Construction <============================== 1433 1434 1435 // Category : Getter methods ------------------------------> 1436 1437 /** 1438 * Checks whether the object name is a pattern. 1439 * <p> 1440 * An object name is a pattern if its domain contains a 1441 * wildcard or if the object name is a property pattern. 1442 * 1443 * @return True if the name is a pattern, otherwise false. 1444 */ 1445 public boolean isPattern() { 1446 return (_domain_pattern || 1447 _property_list_pattern || 1448 _property_value_pattern); 1449 } 1450 1451 /** 1452 * Checks whether the object name is a pattern on the domain part. 1453 * 1454 * @return True if the name is a domain pattern, otherwise false. 1455 * 1456 */ 1457 public boolean isDomainPattern() { 1458 return _domain_pattern; 1459 } 1460 1461 /** 1462 * Checks whether the object name is a pattern on the key properties. 1463 * <p> 1464 * An object name is a pattern on the key properties if it is a 1465 * pattern on the key property list (e.g. "d:k=v,*") or on the 1466 * property values (e.g. "d:k=*") or on both (e.g. "d:k=*,*"). 1467 * 1468 * @return True if the name is a property pattern, otherwise false. 1469 */ 1470 public boolean isPropertyPattern() { 1471 return _property_list_pattern || _property_value_pattern; 1472 } 1473 1474 /** 1475 * Checks whether the object name is a pattern on the key property list. 1476 * <p> 1477 * For example, "d:k=v,*" and "d:k=*,*" are key property list patterns 1478 * whereas "d:k=*" is not. 1479 * 1480 * @return True if the name is a property list pattern, otherwise false. 1481 * 1482 * @since 1.6 1483 */ 1484 public boolean isPropertyListPattern() { 1485 return _property_list_pattern; 1486 } 1487 1488 /** 1489 * Checks whether the object name is a pattern on the value part 1490 * of at least one of the key properties. 1491 * <p> 1492 * For example, "d:k=*" and "d:k=*,*" are property value patterns 1493 * whereas "d:k=v,*" is not. 1494 * 1495 * @return True if the name is a property value pattern, otherwise false. 1496 * 1497 * @since 1.6 1498 */ 1499 public boolean isPropertyValuePattern() { 1500 return _property_value_pattern; 1501 } 1502 1503 /** 1504 * Checks whether the value associated with a key in a key 1505 * property is a pattern. 1506 * 1507 * @param property The property whose value is to be checked. 1508 * 1509 * @return True if the value associated with the given key property 1510 * is a pattern, otherwise false. 1511 * 1512 * @exception NullPointerException If <code>property</code> is null. 1513 * @exception IllegalArgumentException If <code>property</code> is not 1514 * a valid key property for this ObjectName. 1515 * 1516 * @since 1.6 1517 */ 1518 public boolean isPropertyValuePattern(String property) { 1519 if (property == null) 1520 throw new NullPointerException("key property can't be null"); 1521 for (int i = 0; i < _ca_array.length; i++) { 1522 Property prop = _ca_array[i]; 1523 String key = prop.getKeyString(_canonicalName); 1524 if (key.equals(property)) 1525 return (prop instanceof PatternProperty); 1526 } 1527 throw new IllegalArgumentException("key property not found"); 1528 } 1529 1530 /** 1531 * <p>Returns the canonical form of the name; that is, a string 1532 * representation where the properties are sorted in lexical 1533 * order.</p> 1534 * 1535 * <p>More precisely, the canonical form of the name is a String 1536 * consisting of the <em>domain part</em>, a colon 1537 * (<code>:</code>), the <em>canonical key property list</em>, and 1538 * a <em>pattern indication</em>.</p> 1539 * 1540 * <p>The <em>canonical key property list</em> is the same string 1541 * as described for {@link #getCanonicalKeyPropertyListString()}.</p> 1542 * 1543 * <p>The <em>pattern indication</em> is: 1544 * <ul> 1545 * <li>empty for an ObjectName 1546 * that is not a property list pattern; 1547 * <li>an asterisk for an ObjectName 1548 * that is a property list pattern with no keys; or 1549 * <li>a comma and an 1550 * asterisk (<code>,*</code>) for an ObjectName that is a property 1551 * list pattern with at least one key. 1552 * </ul></p> 1553 * 1554 * @return The canonical form of the name. 1555 */ 1556 public String getCanonicalName() { 1557 return _canonicalName; 1558 } 1559 1560 /** 1561 * Returns the domain part. 1562 * 1563 * @return The domain. 1564 */ 1565 public String getDomain() { 1566 return _canonicalName.substring(0, _domain_length); 1567 } 1568 1569 /** 1570 * Obtains the value associated with a key in a key property. 1571 * 1572 * @param property The property whose value is to be obtained. 1573 * 1574 * @return The value of the property, or null if there is no such 1575 * property in this ObjectName. 1576 * 1577 * @exception NullPointerException If <code>property</code> is null. 1578 */ 1579 public String getKeyProperty(String property) { 1580 return _getKeyPropertyList().get(property); 1581 } 1582 1583 /** 1584 * <p>Returns the key properties as a Map. The returned 1585 * value is a Map in which each key is a key in the 1586 * ObjectName's key property list and each value is the associated 1587 * value.</p> 1588 * 1589 * <p>The returned value must not be modified.</p> 1590 * 1591 * @return The table of key properties. 1592 */ 1593 private Map<String,String> _getKeyPropertyList() { 1594 synchronized (this) { 1595 if (_propertyList == null) { 1596 // build (lazy eval) the property list from the canonical 1597 // properties array 1598 _propertyList = new HashMap<String,String>(); 1599 int len = _ca_array.length; 1600 Property prop; 1601 for (int i = len - 1; i >= 0; i--) { 1602 prop = _ca_array[i]; 1603 _propertyList.put(prop.getKeyString(_canonicalName), 1604 prop.getValueString(_canonicalName)); 1605 } 1606 } 1607 } 1608 return _propertyList; 1609 } 1610 1611 /** 1612 * <p>Returns the key properties as a Hashtable. The returned 1613 * value is a Hashtable in which each key is a key in the 1614 * ObjectName's key property list and each value is the associated 1615 * value.</p> 1616 * 1617 * <p>The returned value may be unmodifiable. If it is 1618 * modifiable, changing it has no effect on this ObjectName.</p> 1619 * 1620 * @return The table of key properties. 1621 */ 1622 // CR 6441274 depends on the modification property defined above 1623 public Hashtable<String,String> getKeyPropertyList() { 1624 return new Hashtable<String,String>(_getKeyPropertyList()); 1625 } 1626 1627 /** 1628 * <p>Returns a string representation of the list of key 1629 * properties specified at creation time. If this ObjectName was 1630 * constructed with the constructor {@link #ObjectName(String)}, 1631 * the key properties in the returned String will be in the same 1632 * order as in the argument to the constructor.</p> 1633 * 1634 * @return The key property list string. This string is 1635 * independent of whether the ObjectName is a pattern. 1636 */ 1637 public String getKeyPropertyListString() { 1638 // BEWARE : we rebuild the propertyliststring at each call !! 1639 if (_kp_array.length == 0) return ""; 1640 1641 // the size of the string is the canonical one minus domain 1642 // part and pattern part 1643 final int total_size = _canonicalName.length() - _domain_length - 1 1644 - (_property_list_pattern?2:0); 1645 1646 final char[] dest_chars = new char[total_size]; 1647 final char[] value = _canonicalName.toCharArray(); 1648 writeKeyPropertyListString(value,dest_chars,0); 1649 return new String(dest_chars); 1650 } 1651 1652 /** 1653 * <p>Returns the serialized string of the ObjectName. 1654 * properties specified at creation time. If this ObjectName was 1655 * constructed with the constructor {@link #ObjectName(String)}, 1656 * the key properties in the returned String will be in the same 1657 * order as in the argument to the constructor.</p> 1658 * 1659 * @return The key property list string. This string is 1660 * independent of whether the ObjectName is a pattern. 1661 */ 1662 private String getSerializedNameString() { 1663 1664 // the size of the string is the canonical one 1665 final int total_size = _canonicalName.length(); 1666 final char[] dest_chars = new char[total_size]; 1667 final char[] value = _canonicalName.toCharArray(); 1668 final int offset = _domain_length+1; 1669 1670 // copy "domain:" into dest_chars 1671 // 1672 System.arraycopy(value, 0, dest_chars, 0, offset); 1673 1674 // Add property list string 1675 final int end = writeKeyPropertyListString(value,dest_chars,offset); 1676 1677 // Add ",*" if necessary 1678 if (_property_list_pattern) { 1679 if (end == offset) { 1680 // Property list string is empty. 1681 dest_chars[end] = '*'; 1682 } else { 1683 // Property list string is not empty. 1684 dest_chars[end] = ','; 1685 dest_chars[end+1] = '*'; 1686 } 1687 } 1688 1689 return new String(dest_chars); 1690 } 1691 1692 /** 1693 * <p>Write a string representation of the list of key 1694 * properties specified at creation time in the given array, starting 1695 * at the specified offset. If this ObjectName was 1696 * constructed with the constructor {@link #ObjectName(String)}, 1697 * the key properties in the returned String will be in the same 1698 * order as in the argument to the constructor.</p> 1699 * 1700 * @return offset + #of chars written 1701 */ 1702 private int writeKeyPropertyListString(char[] canonicalChars, 1703 char[] data, int offset) { 1704 if (_kp_array.length == 0) return offset; 1705 1706 final char[] dest_chars = data; 1707 final char[] value = canonicalChars; 1708 1709 int index = offset; 1710 final int len = _kp_array.length; 1711 final int last = len - 1; 1712 for (int i = 0; i < len; i++) { 1713 final Property prop = _kp_array[i]; 1714 final int prop_len = prop._key_length + prop._value_length + 1; 1715 System.arraycopy(value, prop._key_index, dest_chars, index, 1716 prop_len); 1717 index += prop_len; 1718 if (i < last ) dest_chars[index++] = ','; 1719 } 1720 return index; 1721 } 1722 1723 1724 1725 /** 1726 * Returns a string representation of the list of key properties, 1727 * in which the key properties are sorted in lexical order. This 1728 * is used in lexicographic comparisons performed in order to 1729 * select MBeans based on their key property list. Lexical order 1730 * is the order implied by {@link String#compareTo(String) 1731 * String.compareTo(String)}. 1732 * 1733 * @return The canonical key property list string. This string is 1734 * independent of whether the ObjectName is a pattern. 1735 */ 1736 public String getCanonicalKeyPropertyListString() { 1737 if (_ca_array.length == 0) return ""; 1738 1739 int len = _canonicalName.length(); 1740 if (_property_list_pattern) len -= 2; 1741 return _canonicalName.substring(_domain_length +1, len); 1742 } 1743 // Category : Getter methods <=================================== 1744 1745 // Category : Utilities ----------------------------------------> 1746 1747 /** 1748 * <p>Returns a string representation of the object name. The 1749 * format of this string is not specified, but users can expect 1750 * that two ObjectNames return the same string if and only if they 1751 * are equal.</p> 1752 * 1753 * @return a string representation of this object name. 1754 */ 1755 @Override 1756 public String toString() { 1757 return getSerializedNameString(); 1758 } 1759 1760 /** 1761 * Compares the current object name with another object name. Two 1762 * ObjectName instances are equal if and only if their canonical 1763 * forms are equal. The canonical form is the string described 1764 * for {@link #getCanonicalName()}. 1765 * 1766 * @param object The object name that the current object name is to be 1767 * compared with. 1768 * 1769 * @return True if <code>object</code> is an ObjectName whose 1770 * canonical form is equal to that of this ObjectName. 1771 */ 1772 @Override 1773 public boolean equals(Object object) { 1774 1775 // same object case 1776 if (this == object) return true; 1777 1778 // object is not an object name case 1779 if (!(object instanceof ObjectName)) return false; 1780 1781 // equality when canonical names are the same 1782 // (because usage of intern()) 1783 ObjectName on = (ObjectName) object; 1784 String on_string = on._canonicalName; 1785 if (_canonicalName == on_string) return true; // ES: OK 1786 1787 // Because we are sharing canonical form between object names, 1788 // we have finished the comparison at this stage ==> unequal 1789 return false; 1790 } 1791 1792 /** 1793 * Returns a hash code for this object name. 1794 * 1795 */ 1796 @Override 1797 public int hashCode() { 1798 return _canonicalName.hashCode(); 1799 } 1800 1801 /** 1802 * <p>Returns a quoted form of the given String, suitable for 1803 * inclusion in an ObjectName. The returned value can be used as 1804 * the value associated with a key in an ObjectName. The String 1805 * <code>s</code> may contain any character. Appropriate quoting 1806 * ensures that the returned value is legal in an ObjectName.</p> 1807 * 1808 * <p>The returned value consists of a quote ('"'), a sequence of 1809 * characters corresponding to the characters of <code>s</code>, 1810 * and another quote. Characters in <code>s</code> appear 1811 * unchanged within the returned value except:</p> 1812 * 1813 * <ul> 1814 * <li>A quote ('"') is replaced by a backslash (\) followed by a quote.</li> 1815 * <li>An asterisk ('*') is replaced by a backslash (\) followed by an 1816 * asterisk.</li> 1817 * <li>A question mark ('?') is replaced by a backslash (\) followed by 1818 * a question mark.</li> 1819 * <li>A backslash ('\') is replaced by two backslashes.</li> 1820 * <li>A newline character (the character '\n' in Java) is replaced 1821 * by a backslash followed by the character '\n'.</li> 1822 * </ul> 1823 * 1824 * @param s the String to be quoted. 1825 * 1826 * @return the quoted String. 1827 * 1828 * @exception NullPointerException if <code>s</code> is null. 1829 * 1830 */ 1831 public static String quote(String s) { 1832 final StringBuilder buf = new StringBuilder("\""); 1833 final int len = s.length(); 1834 for (int i = 0; i < len; i++) { 1835 char c = s.charAt(i); 1836 switch (c) { 1837 case '\n': 1838 c = 'n'; 1839 buf.append('\\'); 1840 break; 1841 case '\\': 1842 case '\"': 1843 case '*': 1844 case '?': 1845 buf.append('\\'); 1846 break; 1847 } 1848 buf.append(c); 1849 } 1850 buf.append('"'); 1851 return buf.toString(); 1852 } 1853 1854 /** 1855 * <p>Returns an unquoted form of the given String. If 1856 * <code>q</code> is a String returned by {@link #quote quote(s)}, 1857 * then <code>unquote(q).equals(s)</code>. If there is no String 1858 * <code>s</code> for which <code>quote(s).equals(q)</code>, then 1859 * unquote(q) throws an IllegalArgumentException.</p> 1860 * 1861 * <p>These rules imply that there is a one-to-one mapping between 1862 * quoted and unquoted forms.</p> 1863 * 1864 * @param q the String to be unquoted. 1865 * 1866 * @return the unquoted String. 1867 * 1868 * @exception IllegalArgumentException if <code>q</code> could not 1869 * have been returned by the {@link #quote} method, for instance 1870 * if it does not begin and end with a quote ("). 1871 * 1872 * @exception NullPointerException if <code>q</code> is null. 1873 * 1874 */ 1875 public static String unquote(String q) { 1876 final StringBuilder buf = new StringBuilder(); 1877 final int len = q.length(); 1878 if (len < 2 || q.charAt(0) != '"' || q.charAt(len - 1) != '"') 1879 throw new IllegalArgumentException("Argument not quoted"); 1880 for (int i = 1; i < len - 1; i++) { 1881 char c = q.charAt(i); 1882 if (c == '\\') { 1883 if (i == len - 2) 1884 throw new IllegalArgumentException("Trailing backslash"); 1885 c = q.charAt(++i); 1886 switch (c) { 1887 case 'n': 1888 c = '\n'; 1889 break; 1890 case '\\': 1891 case '\"': 1892 case '*': 1893 case '?': 1894 break; 1895 default: 1896 throw new IllegalArgumentException( 1897 "Bad character '" + c + "' after backslash"); 1898 } 1899 } else { 1900 switch (c) { 1901 case '*' : 1902 case '?' : 1903 case '\"': 1904 case '\n': 1905 throw new IllegalArgumentException( 1906 "Invalid unescaped character '" + c + 1907 "' in the string to unquote"); 1908 } 1909 } 1910 buf.append(c); 1911 } 1912 return buf.toString(); 1913 } 1914 1915 /** 1916 * Defines the wildcard "*:*" ObjectName. 1917 * 1918 * @since 1.6 1919 */ 1920 public static final ObjectName WILDCARD = Util.newObjectName("*:*"); 1921 1922 // Category : Utilities <=================================== 1923 1924 // Category : QueryExp Interface ----------------------------------------> 1925 1926 /** 1927 * <p>Test whether this ObjectName, which may be a pattern, 1928 * matches another ObjectName. If <code>name</code> is a pattern, 1929 * the result is false. If this ObjectName is a pattern, the 1930 * result is true if and only if <code>name</code> matches the 1931 * pattern. If neither this ObjectName nor <code>name</code> is 1932 * a pattern, the result is true if and only if the two 1933 * ObjectNames are equal as described for the {@link 1934 * #equals(Object)} method.</p> 1935 * 1936 * @param name The name of the MBean to compare to. 1937 * 1938 * @return True if <code>name</code> matches this ObjectName. 1939 * 1940 * @exception NullPointerException if <code>name</code> is null. 1941 * 1942 */ 1943 public boolean apply(ObjectName name) { 1944 1945 if (name == null) throw new NullPointerException(); 1946 1947 if (name._domain_pattern || 1948 name._property_list_pattern || 1949 name._property_value_pattern) 1950 return false; 1951 1952 // No pattern 1953 if (!_domain_pattern && 1954 !_property_list_pattern && 1955 !_property_value_pattern) 1956 return _canonicalName.equals(name._canonicalName); 1957 1958 return matchDomains(name) && matchKeys(name); 1959 } 1960 1961 private final boolean matchDomains(ObjectName name) { 1962 if (_domain_pattern) { 1963 // wildmatch domains 1964 // This ObjectName is the pattern 1965 // The other ObjectName is the string. 1966 return Util.wildmatch(name.getDomain(),getDomain()); 1967 } 1968 return getDomain().equals(name.getDomain()); 1969 } 1970 1971 private final boolean matchKeys(ObjectName name) { 1972 // If key property value pattern but not key property list 1973 // pattern, then the number of key properties must be equal 1974 // 1975 if (_property_value_pattern && 1976 !_property_list_pattern && 1977 (name._ca_array.length != _ca_array.length)) 1978 return false; 1979 1980 // If key property value pattern or key property list pattern, 1981 // then every property inside pattern should exist in name 1982 // 1983 if (_property_value_pattern || _property_list_pattern) { 1984 final Map<String,String> nameProps = name._getKeyPropertyList(); 1985 final Property[] props = _ca_array; 1986 final String cn = _canonicalName; 1987 for (int i = props.length - 1; i >= 0 ; i--) { 1988 // Find value in given object name for key at current 1989 // index in receiver 1990 // 1991 final Property p = props[i]; 1992 final String k = p.getKeyString(cn); 1993 final String v = nameProps.get(k); 1994 // Did we find a value for this key ? 1995 // 1996 if (v == null) return false; 1997 // If this property is ok (same key, same value), go to next 1998 // 1999 if (_property_value_pattern && (p instanceof PatternProperty)) { 2000 // wildmatch key property values 2001 // p is the property pattern, v is the string 2002 if (Util.wildmatch(v,p.getValueString(cn))) 2003 continue; 2004 else 2005 return false; 2006 } 2007 if (v.equals(p.getValueString(cn))) continue; 2008 return false; 2009 } 2010 return true; 2011 } 2012 2013 // If no pattern, then canonical names must be equal 2014 // 2015 final String p1 = name.getCanonicalKeyPropertyListString(); 2016 final String p2 = getCanonicalKeyPropertyListString(); 2017 return (p1.equals(p2)); 2018 } 2019 2020 /* Method inherited from QueryExp, no implementation needed here 2021 because ObjectName is not relative to an MBeanServer and does 2022 not contain a subquery. 2023 */ 2024 public void setMBeanServer(MBeanServer mbs) { } 2025 2026 // Category : QueryExp Interface <========================= 2027 2028 // Category : Comparable Interface ----------------------------------------> 2029 2030 /** 2031 * <p>Compares two ObjectName instances. The ordering relation between 2032 * ObjectNames is not completely specified but is intended to be such 2033 * that a sorted list of ObjectNames will appear in an order that is 2034 * convenient for a person to read.</p> 2035 * 2036 * <p>In particular, if the two ObjectName instances have different 2037 * domains then their order is the lexicographical order of the domains. 2038 * The ordering of the key property list remains unspecified.</p> 2039 * 2040 * <p>For example, the ObjectName instances below:</p> 2041 * <ul> 2042 * <li>Shapes:type=Square,name=3</li> 2043 * <li>Colors:type=Red,name=2</li> 2044 * <li>Shapes:type=Triangle,side=isosceles,name=2</li> 2045 * <li>Colors:type=Red,name=1</li> 2046 * <li>Shapes:type=Square,name=1</li> 2047 * <li>Colors:type=Blue,name=1</li> 2048 * <li>Shapes:type=Square,name=2</li> 2049 * <li>JMImplementation:type=MBeanServerDelegate</li> 2050 * <li>Shapes:type=Triangle,side=scalene,name=1</li> 2051 * </ul> 2052 * <p>could be ordered as follows:</p> 2053 * <ul> 2054 * <li>Colors:type=Blue,name=1</li> 2055 * <li>Colors:type=Red,name=1</li> 2056 * <li>Colors:type=Red,name=2</li> 2057 * <li>JMImplementation:type=MBeanServerDelegate</li> 2058 * <li>Shapes:type=Square,name=1</li> 2059 * <li>Shapes:type=Square,name=2</li> 2060 * <li>Shapes:type=Square,name=3</li> 2061 * <li>Shapes:type=Triangle,side=scalene,name=1</li> 2062 * <li>Shapes:type=Triangle,side=isosceles,name=2</li> 2063 * </ul> 2064 * 2065 * @param name the ObjectName to be compared. 2066 * 2067 * @return a negative integer, zero, or a positive integer as this 2068 * ObjectName is less than, equal to, or greater than the 2069 * specified ObjectName. 2070 * 2071 * @since 1.6 2072 */ 2073 public int compareTo(ObjectName name) { 2074 // Quick optimization: 2075 // 2076 if (name == this) return 0; 2077 2078 // (1) Compare domains 2079 // 2080 int domainValue = this.getDomain().compareTo(name.getDomain()); 2081 if (domainValue != 0) 2082 return domainValue; 2083 2084 // (2) Compare "type=" keys 2085 // 2086 // Within a given domain, all names with missing or empty "type=" 2087 // come before all names with non-empty type. 2088 // 2089 // When both types are missing or empty, canonical-name ordering 2090 // applies which is a total order. 2091 // 2092 String thisTypeKey = this.getKeyProperty("type"); 2093 String anotherTypeKey = name.getKeyProperty("type"); 2094 if (thisTypeKey == null) 2095 thisTypeKey = ""; 2096 if (anotherTypeKey == null) 2097 anotherTypeKey = ""; 2098 int typeKeyValue = thisTypeKey.compareTo(anotherTypeKey); 2099 if (typeKeyValue != 0) 2100 return typeKeyValue; 2101 2102 // (3) Compare canonical names 2103 // 2104 return this.getCanonicalName().compareTo(name.getCanonicalName()); 2105 } 2106 2107 // Category : Comparable Interface <========================= 2108 2109 // Public methods <======================================== 2110 2111 }