GNU Classpath (0.95) | |
Frames | No Frames |
1: /* ObjectName.java -- Represent the name of a bean, or a pattern for a name. 2: Copyright (C) 2006, 2007 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.management; 39: 40: import java.io.Serializable; 41: 42: import java.util.Collections; 43: import java.util.Hashtable; 44: import java.util.Iterator; 45: import java.util.Map; 46: import java.util.TreeMap; 47: 48: import java.io.IOException; 49: import java.io.InvalidObjectException; 50: import java.io.ObjectInputStream; 51: import java.io.ObjectOutputStream; 52: 53: /** 54: * <p> 55: * An {@link ObjectName} instance represents the name of a management 56: * bean, or a pattern which may match the name of one or more 57: * management beans. Patterns are distinguished from names by the 58: * presence of the '?' and '*' characters (which match a single 59: * character and a series of zero or more characters, respectively). 60: * </p> 61: * <p> 62: * Each name begins with a domain element, which is terminated by 63: * a ':' character. The domain may be empty. If so, it will be 64: * replaced by the default domain of the bean server in certain 65: * contexts. The domain is a pattern, if it contains either '?' 66: * or '*'. To avoid collisions, it is usual to use reverse 67: * DNS names for the domain, as in Java package and property names. 68: * </p> 69: * <p> 70: * Following the ':' character is a series of properties. The list 71: * is separated by commas, and largely consists of unordered key-value 72: * pairs, separated by an equals sign ('='). At most one element may 73: * be an asterisk ('*'), which turns the {@link ObjectName} instance 74: * into a <emph>property pattern</emph>. In this situation, the pattern 75: * matches a name if the name contains at least those key-value pairs 76: * given and has the same domain. 77: * </p> 78: * <p> 79: * A <emph>key</emph> is a string of characters which doesn't include 80: * any of those used as delimiters or in patterns (':', '=', ',', '?' 81: * and '*'). Keys must be unique. 82: * </p> 83: * <p> 84: * A value may be <emph>quoted</emph> or <emph>unquoted</emph>. Unquoted 85: * values obey the same rules as given for keys above. Quoted values are 86: * surrounded by quotation marks ("), and use a backslash ('\') character 87: * to include quotes ('\"'), backslashes ('\\'), newlines ('\n'), and 88: * the pattern characters ('\?' and '\*'). The quotes and backslashes 89: * (after expansion) are considered part of the value. 90: * </p> 91: * <p> 92: * Spaces are maintained within the different parts of the name. Thus, 93: * '<code>domain: key1 = value1 </code>' has a key ' key1 ' with value 94: * ' value1 '. Newlines are disallowed, except where escaped in quoted 95: * values. 96: * </p> 97: * 98: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 99: * @since 1.5 100: */ 101: public class ObjectName 102: implements Serializable, QueryExp 103: { 104: 105: private static final long serialVersionUID = 1081892073854801359L; 106: 107: /** 108: * The wildcard {@link ObjectName} {@code "*:*"} 109: * 110: * @since 1.6 111: */ 112: public static final ObjectName WILDCARD; 113: 114: /** 115: * The domain of the name. 116: */ 117: private transient String domain; 118: 119: /** 120: * The properties, as key-value pairs. 121: */ 122: private transient TreeMap<String,String> properties; 123: 124: /** 125: * The properties as a string (stored for ordering). 126: */ 127: private transient String propertyListString; 128: 129: /** 130: * True if this object name is a property pattern. 131: */ 132: private transient boolean propertyPattern; 133: 134: /** 135: * The management server associated with this object name. 136: */ 137: private transient MBeanServer server; 138: 139: /** 140: * Static initializer to set up the wildcard. 141: */ 142: static 143: { 144: try 145: { 146: WILDCARD = new ObjectName(""); 147: } 148: catch (MalformedObjectNameException e) 149: { 150: throw (InternalError) (new InternalError("A problem occurred " + 151: "initializing the ObjectName " + 152: "wildcard.").initCause(e)); 153: } 154: } 155: 156: /** 157: * Constructs an {@link ObjectName} instance from the given string, 158: * which should be of the form 159: * <domain>:<properties><wild>. <domain> 160: * represents the domain section of the name. <properties> 161: * represents the key-value pairs, as returned by {@link 162: * #getKeyPropertyListString()}. <wild> is the optional 163: * asterisk present in the property list. If the string doesn't 164: * represent a property pattern, it will be empty. If it does, 165: * it will be either ',*' or '*', depending on whether other 166: * properties are present or not, respectively. 167: * 168: * @param name the string to use to construct this instance. 169: * @throws MalformedObjectNameException if the string is of the 170: * wrong format. 171: * @throws NullPointerException if <code>name</code> is 172: * <code>null</code>. 173: */ 174: public ObjectName(String name) 175: throws MalformedObjectNameException 176: { 177: if (name.length() == 0) 178: name = "*:*"; 179: parse(name); 180: } 181: 182: /** 183: * Parse the name in the same form as the constructor. Used by 184: * readObject(). 185: */ 186: private void parse(String name) 187: throws MalformedObjectNameException 188: { 189: int domainSep = name.indexOf(':'); 190: if (domainSep == -1) 191: throw new MalformedObjectNameException("No domain separator was found."); 192: domain = name.substring(0, domainSep); 193: String rest = name.substring(domainSep + 1); 194: properties = new TreeMap<String,String>(); 195: String[] pairs = rest.split(","); 196: if (pairs.length == 0 && !isPattern()) 197: throw new MalformedObjectNameException("A name that is not a " + 198: "pattern must contain at " + 199: "least one key-value pair."); 200: propertyListString = ""; 201: for (int a = 0; a < pairs.length; ++a) 202: { 203: if (pairs[a].equals("*")) 204: { 205: if (propertyPattern) 206: throw new MalformedObjectNameException("Multiple wildcards " + 207: "in properties."); 208: propertyPattern = true; 209: continue; 210: } 211: int sep = pairs[a].indexOf('='); 212: if (sep == -1) 213: throw new MalformedObjectNameException("A key must be " + 214: "followed by a value."); 215: String key = pairs[a].substring(0, sep); 216: if (properties.containsKey(key)) 217: throw new MalformedObjectNameException("The same key occurs " + 218: "more than once."); 219: String value = pairs[a].substring(sep+1); 220: properties.put(key, value); 221: propertyListString += key + "=" + value + ","; 222: } 223: if (propertyListString.length() > 0) 224: propertyListString = 225: propertyListString.substring(0, propertyListString.length() - 1); 226: checkComponents(); 227: } 228: 229: /** 230: * Constructs an {@link ObjectName} instance using the given 231: * domain and the one specified property. 232: * 233: * @param domain the domain part of the object name. 234: * @param key the key of the property. 235: * @param value the value of the property. 236: * @throws MalformedObjectNameException the domain, key or value 237: * contains an illegal 238: * character or the value 239: * does not follow the quoting 240: * specifications. 241: * @throws NullPointerException if one of the parameters is 242: * <code>null</code>. 243: */ 244: public ObjectName(String domain, String key, String value) 245: throws MalformedObjectNameException 246: { 247: this.domain = domain; 248: properties = new TreeMap<String,String>(); 249: properties.put(key, value); 250: checkComponents(); 251: } 252: 253: /** 254: * Constructs an {@link ObjectName} instance using the given 255: * domain and properties. 256: * 257: * @param domain the domain part of the object name. 258: * @param properties the key-value property pairs. 259: * @throws MalformedObjectNameException the domain, a key or a value 260: * contains an illegal 261: * character or a value 262: * does not follow the quoting 263: * specifications. 264: * @throws NullPointerException if one of the parameters is 265: * <code>null</code>. 266: */ 267: public ObjectName(String domain, Hashtable<String,String> properties) 268: throws MalformedObjectNameException 269: { 270: this.domain = domain; 271: this.properties = new TreeMap<String,String>(); 272: this.properties.putAll(properties); 273: checkComponents(); 274: } 275: 276: /** 277: * Checks the legality of the domain and the properties. 278: * 279: * @throws MalformedObjectNameException the domain, a key or a value 280: * contains an illegal 281: * character or a value 282: * does not follow the quoting 283: * specifications. 284: */ 285: private void checkComponents() 286: throws MalformedObjectNameException 287: { 288: if (domain.indexOf(':') != -1) 289: throw new MalformedObjectNameException("The domain includes a ':' " + 290: "character."); 291: if (domain.indexOf('\n') != -1) 292: throw new MalformedObjectNameException("The domain includes a newline " + 293: "character."); 294: char[] chars = new char[] { '\n', ':', ',', '*', '?', '=' }; 295: Iterator i = properties.entrySet().iterator(); 296: while (i.hasNext()) 297: { 298: Map.Entry entry = (Map.Entry) i.next(); 299: String key = (String) entry.getKey(); 300: for (int a = 0; a < chars.length; ++a) 301: if (key.indexOf(chars[a]) != -1) 302: throw new MalformedObjectNameException("A key contains a '" + 303: chars[a] + "' " + 304: "character."); 305: String value = (String) entry.getValue(); 306: int quote = value.indexOf('"'); 307: if (quote == 0) 308: { 309: try 310: { 311: unquote(value); 312: } 313: catch (IllegalArgumentException e) 314: { 315: throw (MalformedObjectNameException) 316: new MalformedObjectNameException("The quoted value is " + 317: "invalid.").initCause(e); 318: } 319: } 320: else if (quote != -1) 321: throw new MalformedObjectNameException("A value contains " + 322: "a '\"' character."); 323: else 324: { 325: for (int a = 0; a < chars.length; ++a) 326: if (value.indexOf(chars[a]) != -1) 327: throw new MalformedObjectNameException("A value contains " + 328: "a '" + chars[a] + "' " + 329: "character."); 330: } 331: } 332: } 333: 334: /** 335: * <p> 336: * Attempts to find a match between this name and the one supplied. 337: * The following criteria are used: 338: * </p> 339: * <ul> 340: * <li>If the supplied name is a pattern, <code>false</code> is 341: * returned.</li> 342: * <li>If this name is a pattern, this method returns <code>true</code> 343: * if the supplied name matches the pattern.</li> 344: * <li>If this name is not a pattern, the result of 345: * <code>equals(name)</code> is returned. 346: * </ul> 347: * 348: * @param name the name to find a match with. 349: * @return true if the name either matches this pattern or is 350: * equivalent to this name under the criteria of 351: * {@link #equals(java.lang.Object)} 352: * @throws NullPointerException if <code>name</code> is <code>null</code>. 353: */ 354: public boolean apply(ObjectName name) 355: { 356: if (name.isPattern()) 357: return false; 358: 359: if (!isPattern()) 360: return equals(name); 361: 362: if (isDomainPattern()) 363: { 364: if (!domainMatches(domain, 0, name.getDomain(), 0)) 365: return false; 366: } 367: else 368: { 369: if (!domain.equals(name.getDomain())) 370: return false; 371: } 372: 373: if (isPropertyPattern()) 374: { 375: Hashtable oProps = name.getKeyPropertyList(); 376: Iterator i = properties.entrySet().iterator(); 377: while (i.hasNext()) 378: { 379: Map.Entry entry = (Map.Entry) i.next(); 380: String key = (String) entry.getKey(); 381: if (!(oProps.containsKey(key))) 382: return false; 383: String val = (String) entry.getValue(); 384: if (!(val.equals(oProps.get(key)))) 385: return false; 386: } 387: } 388: else 389: { 390: if (!getCanonicalKeyPropertyListString().equals 391: (name.getCanonicalKeyPropertyListString())) 392: return false; 393: } 394: return true; 395: } 396: 397: /** 398: * Returns true if the domain matches the pattern. 399: * 400: * @param pattern the pattern to match against. 401: * @param patternindex the index into the pattern to start matching. 402: * @param domain the domain to match. 403: * @param domainindex the index into the domain to start matching. 404: * @return true if the domain matches the pattern. 405: */ 406: private static boolean domainMatches(String pattern, int patternindex, 407: String domain, int domainindex) 408: { 409: while (patternindex < pattern.length()) 410: { 411: char c = pattern.charAt(patternindex++); 412: 413: if (c == '*') 414: { 415: for (int i = domain.length(); i >= domainindex; i--) 416: { 417: if (domainMatches(pattern, patternindex, domain, i)) 418: return true; 419: } 420: return false; 421: } 422: 423: if (domainindex >= domain.length()) 424: return false; 425: 426: if (c != '?' && c != domain.charAt(domainindex)) 427: return false; 428: 429: domainindex++; 430: } 431: return true; 432: } 433: 434: /** 435: * Compares the specified object with this one. The two 436: * are judged to be equivalent if the given object is an 437: * instance of {@link ObjectName} and has an equal canonical 438: * form (as returned by {@link #getCanonicalName()}). 439: * 440: * @param obj the object to compare with this. 441: * @return true if the object is also an {@link ObjectName} 442: * with an equivalent canonical form. 443: */ 444: public boolean equals(Object obj) 445: { 446: if (obj instanceof ObjectName) 447: { 448: ObjectName o = (ObjectName) obj; 449: return getCanonicalName().equals(o.getCanonicalName()); 450: } 451: return false; 452: } 453: 454: /** 455: * Returns the property list in canonical form. The keys 456: * are ordered using the lexicographic ordering used by 457: * {@link java.lang.String#compareTo(java.lang.Object)}. 458: * 459: * @return the property list, with the keys in lexicographic 460: * order. 461: */ 462: public String getCanonicalKeyPropertyListString() 463: { 464: StringBuilder builder = new StringBuilder(); 465: Iterator i = properties.entrySet().iterator(); 466: while (i.hasNext()) 467: { 468: Map.Entry entry = (Map.Entry) i.next(); 469: builder.append(entry.getKey() + "=" + entry.getValue()); 470: if (i.hasNext()) 471: builder.append(","); 472: } 473: return builder.toString(); 474: } 475: 476: /** 477: * <p> 478: * Returns the name as a string in canonical form. More precisely, 479: * this returns a string of the format 480: * <domain>:<properties><wild>. <properties> 481: * is the same value as returned by 482: * {@link #getCanonicalKeyPropertyListString()}. <wild> 483: * is: 484: * </p> 485: * <ul> 486: * <li>an empty string, if the object name is not a property pattern.</li> 487: * <li>'*' if <properties> is empty.</li> 488: * <li>',*' if there is at least one key-value pair.</li> 489: * </ul> 490: * 491: * @return the canonical string form of the object name, as specified 492: * above. 493: */ 494: public String getCanonicalName() 495: { 496: return domain + ":" + 497: getCanonicalKeyPropertyListString() + 498: (isPropertyPattern() ? (properties.isEmpty() ? "*" : ",*") : ""); 499: } 500: 501: /** 502: * Returns the domain part of the object name. 503: * 504: * @return the domain. 505: */ 506: public String getDomain() 507: { 508: return domain; 509: } 510: 511: /** 512: * Returns an {@link ObjectName} instance that is substitutable for the 513: * one given. The instance returned may be a subclass of {@link ObjectName}, 514: * but is not guaranteed to be of the same type as the given name, if that 515: * should also turn out to be a subclass. The returned instance may or may 516: * not be equivalent to the one given. The purpose of this method is to provide 517: * an instance of {@link ObjectName} with a well-defined semantics, such as may 518: * be used in cases where the given name is not trustworthy. 519: * 520: * @param name the {@link ObjectName} to provide a substitute for. 521: * @return a substitute for the given name, which may or may not be a subclass 522: * of {@link ObjectName}. In either case, the returned object is 523: * guaranteed to have the semantics defined here. 524: * @throws NullPointerException if <code>name</code> is <code>null</code>. 525: */ 526: public static ObjectName getInstance(ObjectName name) 527: { 528: try 529: { 530: return new ObjectName(name.getCanonicalName()); 531: } 532: catch (MalformedObjectNameException e) 533: { 534: throw (InternalError) 535: (new InternalError("The canonical name of " + 536: "the given name is invalid.").initCause(e)); 537: } 538: } 539: 540: /** 541: * Returns an {@link ObjectName} instance for the specified name, represented 542: * as a {@link java.lang.String}. The instance returned may be a subclass of 543: * {@link ObjectName} and may or may not be equivalent to earlier instances 544: * returned by this method for the same string. 545: * 546: * @param name the {@link ObjectName} to provide an instance of. 547: * @return a instance for the given name, which may or may not be a subclass 548: * of {@link ObjectName}. 549: * @throws MalformedObjectNameException the domain, a key or a value 550: * contains an illegal 551: * character or a value 552: * does not follow the quoting 553: * specifications. 554: * @throws NullPointerException if <code>name</code> is <code>null</code>. 555: */ 556: public static ObjectName getInstance(String name) 557: throws MalformedObjectNameException 558: { 559: return new ObjectName(name); 560: } 561: 562: /** 563: * Returns an {@link ObjectName} instance for the specified name, represented 564: * as a series of {@link java.lang.String} objects for the domain and a single 565: * property, as a key-value pair. The instance returned may be a subclass of 566: * {@link ObjectName} and may or may not be equivalent to earlier instances 567: * returned by this method for the same parameters. 568: * 569: * @param domain the domain part of the object name. 570: * @param key the key of the property. 571: * @param value the value of the property. 572: * @return a instance for the given name, which may or may not be a subclass 573: * of {@link ObjectName}. 574: * @throws MalformedObjectNameException the domain, a key or a value 575: * contains an illegal 576: * character or a value 577: * does not follow the quoting 578: * specifications. 579: * @throws NullPointerException if <code>name</code> is <code>null</code>. 580: */ 581: public static ObjectName getInstance(String domain, String key, String value) 582: throws MalformedObjectNameException 583: { 584: return new ObjectName(domain, key, value); 585: } 586: 587: /** 588: * Returns an {@link ObjectName} instance for the specified name, represented 589: * as a domain {@link java.lang.String} and a table of properties. The 590: * instance returned may be a subclass of {@link ObjectName} and may or may 591: * not be equivalent to earlier instances returned by this method for the 592: * same string. 593: * 594: * @param domain the domain part of the object name. 595: * @param properties the key-value property pairs. 596: * @return a instance for the given name, which may or may not be a subclass 597: * of {@link ObjectName}. 598: * @throws MalformedObjectNameException the domain, a key or a value 599: * contains an illegal 600: * character or a value 601: * does not follow the quoting 602: * specifications. 603: * @throws NullPointerException if <code>name</code> is <code>null</code>. 604: */ 605: public static ObjectName getInstance(String domain, 606: Hashtable<String,String> properties) 607: throws MalformedObjectNameException 608: { 609: return new ObjectName(domain, properties); 610: } 611: 612: /** 613: * Returns the property value corresponding to the given key. 614: * 615: * @param key the key of the property to be obtained. 616: * @return the value of the specified property. 617: * @throws NullPointerException if <code>key</code> is <code>null</code>. 618: */ 619: public String getKeyProperty(String key) 620: { 621: if (key == null) 622: throw new NullPointerException("Null key given in request for a value."); 623: return (String) properties.get(key); 624: } 625: 626: /** 627: * Returns the properties in a {@link java.util.Hashtable}. The table 628: * contains each of the properties as keys mapped to their value. The 629: * returned table is not unmodifiable, but changes made to it will not 630: * be reflected in the object name. 631: * 632: * @return a {@link java.util.Hashtable}, containing each of the object 633: * name's properties. 634: */ 635: public Hashtable<String,String> getKeyPropertyList() 636: { 637: return new Hashtable<String,String>(properties); 638: } 639: 640: /** 641: * Returns a {@link java.lang.String} representation of the property 642: * list. If the object name was created using {@link 643: * ObjectName(String)}, then this string will contain the properties 644: * in the same order they were given in at creation. 645: * 646: * @return the property list. 647: */ 648: public String getKeyPropertyListString() 649: { 650: if (propertyListString != null) 651: return propertyListString; 652: return getCanonicalKeyPropertyListString(); 653: } 654: 655: /** 656: * Returns a hash code for this object name. This is calculated as the 657: * summation of the hash codes of the domain and the properties. 658: * 659: * @return a hash code for this object name. 660: */ 661: public int hashCode() 662: { 663: return domain.hashCode() + properties.hashCode(); 664: } 665: 666: /** 667: * Returns true if the domain of this object name is a pattern. 668: * This is the case if it contains one or more wildcard characters 669: * ('*' or '?'). 670: * 671: * @return true if the domain is a pattern. 672: */ 673: public boolean isDomainPattern() 674: { 675: return domain.contains("?") || domain.contains("*"); 676: } 677: 678: /** 679: * Returns true if this is an object name pattern. An object 680: * name pattern has a domain containing a wildcard character 681: * ('*' or '?') and/or a '*' in the list of properties. 682: * This method will return true if either {@link #isDomainPattern()} 683: * or {@link #isPropertyPattern()} does. 684: * 685: * @return true if this is an object name pattern. 686: */ 687: public boolean isPattern() 688: { 689: return isDomainPattern() || isPropertyPattern(); 690: } 691: 692: /** 693: * Returns true if this object name is a property pattern. This is 694: * the case if the list of properties contains an '*'. 695: * 696: * @return true if this is a property pattern. 697: */ 698: public boolean isPropertyPattern() 699: { 700: return propertyPattern; 701: } 702: 703: /** 704: * <p> 705: * Returns a quoted version of the supplied string. The string may 706: * contain any character. The resulting quoted version is guaranteed 707: * to be usable as the value of a property, so this method provides 708: * a good way of ensuring that a value is legal. 709: * </p> 710: * <p> 711: * The string is transformed as follows: 712: * </p> 713: * <ul> 714: * <li>The string is prefixed with an opening quote character, '"'. 715: * <li>For each character, s: 716: * <ul> 717: * <li>If s is a quote ('"'), it is replaced by a backslash 718: * followed by a quote.</li> 719: * <li>If s is a star ('*'), it is replaced by a backslash followed 720: * by a star.</li> 721: * <li>If s is a question mark ('?'), it is replaced by a backslash 722: * followed by a question mark.</li> 723: * <li>If s is a backslash ('\'), it is replaced by two backslashes.</li> 724: * <li>If s is a newline character, it is replaced by a backslash followed by 725: * a '\n'.</li> 726: * <li>Otherwise, s is used verbatim. 727: * </ul></li> 728: * <li>The string is terminated with a closing quote character, '"'.</li> 729: * </ul> 730: * 731: * @param string the string to quote. 732: * @return a quoted version of the supplied string. 733: * @throws NullPointerException if <code>string</code> is <code>null</code>. 734: */ 735: public static String quote(String string) 736: { 737: StringBuilder builder = new StringBuilder(); 738: builder.append('"'); 739: for (int a = 0; a < string.length(); ++a) 740: { 741: char s = string.charAt(a); 742: switch (s) 743: { 744: case '"': 745: builder.append("\\\""); 746: break; 747: case '*': 748: builder.append("\\*"); 749: break; 750: case '?': 751: builder.append("\\?"); 752: break; 753: case '\\': 754: builder.append("\\\\"); 755: break; 756: case '\n': 757: builder.append("\\\n"); 758: break; 759: default: 760: builder.append(s); 761: } 762: } 763: builder.append('"'); 764: return builder.toString(); 765: } 766: 767: /** 768: * Changes the {@link MBeanServer} on which this query is performed. 769: * 770: * @param server the new server to use. 771: */ 772: public void setMBeanServer(MBeanServer server) 773: { 774: this.server = server; 775: } 776: 777: /** 778: * Returns a textual representation of the object name. 779: * 780: * <p>The format is unspecified beyond that equivalent object 781: * names will return the same string from this method, but note 782: * that Tomcat depends on the string returned by this method 783: * being a valid textual representation of the object name and 784: * will fail to start if it is not. 785: * 786: * @return a textual representation of the object name. 787: */ 788: public String toString() 789: { 790: return getCanonicalName(); 791: } 792: 793: 794: /** 795: * Serialize this {@link ObjectName}. The serialized 796: * form is the same as the string parsed by the constructor. 797: * 798: * @param out the output stream to write to. 799: * @throws IOException if an I/O error occurs. 800: */ 801: private void writeObject(ObjectOutputStream out) 802: throws IOException 803: { 804: out.defaultWriteObject(); 805: StringBuffer buffer = new StringBuffer(getDomain()); 806: buffer.append(':'); 807: String properties = getKeyPropertyListString(); 808: buffer.append(properties); 809: if (isPropertyPattern()) 810: { 811: if (properties.length() == 0) 812: buffer.append("*"); 813: else 814: buffer.append(",*"); 815: } 816: out.writeObject(buffer.toString()); 817: } 818: 819: /** 820: * Reads the serialized form, which is that used 821: * by the constructor. 822: * 823: * @param in the input stream to read from. 824: * @throws IOException if an I/O error occurs. 825: */ 826: private void readObject(ObjectInputStream in) 827: throws IOException, ClassNotFoundException 828: { 829: in.defaultReadObject(); 830: String objectName = (String)in.readObject(); 831: try 832: { 833: parse(objectName); 834: } 835: catch (MalformedObjectNameException x) 836: { 837: throw new InvalidObjectException(x.toString()); 838: } 839: } 840: 841: 842: /** 843: * Unquotes the supplied string. The quotation marks are removed as 844: * are the backslashes preceding the escaped characters ('"', '?', 845: * '*', '\n', '\\'). A one-to-one mapping exists between quoted and 846: * unquoted values. As a result, a string <code>s</code> should be 847: * equal to <code>unquote(quote(s))</code>. 848: * 849: * @param q the quoted string to unquote. 850: * @return the unquoted string. 851: * @throws NullPointerException if <code>q</code> is <code>null</code>. 852: * @throws IllegalArgumentException if the string is not a valid 853: * quoted string i.e. it is not 854: * surrounded by quotation marks 855: * and/or characters are not properly 856: * escaped. 857: */ 858: public static String unquote(String q) 859: { 860: if (q.charAt(0) != '"') 861: throw new IllegalArgumentException("The string does " + 862: "not start with a quote."); 863: if (q.charAt(q.length() - 1) != '"') 864: throw new IllegalArgumentException("The string does " + 865: "not end with a quote."); 866: StringBuilder builder = new StringBuilder(); 867: for (int a = 1; a < (q.length() - 1); ++a) 868: { 869: char n = q.charAt(a); 870: if (n == '\\') 871: { 872: n = q.charAt(++a); 873: if (n != '"' && n != '?' && n != '*' && 874: n != 'n' && n != '\\') 875: throw new IllegalArgumentException("Illegal escaped character: " 876: + n); 877: } 878: else if (n == '"' || n == '\n') 879: throw new IllegalArgumentException("Illegal character: " + n); 880: builder.append(n); 881: } 882: 883: return builder.toString(); 884: } 885: 886: }
GNU Classpath (0.95) |