KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > management > ObjectName


1 /*
2  * @(#)ObjectName.java 1.70 07/10/23
3  *
4  * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.management;
9
10
11 // java import
12
import java.io.InvalidObjectException JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.ObjectInputStream JavaDoc;
15 import java.io.ObjectOutputStream JavaDoc;
16 import java.io.ObjectStreamField JavaDoc;
17 import java.io.Serializable JavaDoc;
18 import java.security.AccessController JavaDoc;
19 import java.security.PrivilegedAction JavaDoc;
20 import java.util.Arrays JavaDoc;
21 import java.util.Enumeration JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Hashtable JavaDoc;
24
25 import com.sun.jmx.mbeanserver.GetPropertyAction;
26
27 /**
28  * <p>Represents the object name of an MBean, or a pattern that can
29  * match the names of several MBeans. Instances of this class are
30  * immutable.</p>
31  *
32  * <p>An instance of this class can
33  * be used to represent:
34  * <ul>
35  * <li> An object name
36  * <li> An object name pattern, within the context of a query
37  * </ul></p>
38  *
39  * <p>An object name consists of two parts, the domain and the key
40  * properties.</p>
41  *
42  * <p>The <em>domain</em> is a string of characters not including
43  * the character colon (<code>:</code>).</p>
44  *
45  * <p>If the domain includes at least one occurrence of the wildcard
46  * characters asterisk (<code>*</code>) or question mark
47  * (<code>?</code>), then the object name is a pattern. The asterisk
48  * matches any sequence of zero or more characters, while the question
49  * mark matches any single character.</p>
50  *
51  * <p>If the domain is empty, it will be replaced in certain contexts
52  * by the <em>default domain</em> of the MBean server in which the
53  * ObjectName is used.</p>
54  *
55  * <p>The <em>key properties</em> are an unordered set of keys and
56  * associated values.</p>
57  *
58  * <p>Each <em>key</em> is a nonempty string of characters which may
59  * not contain any of the characters comma (<code>,</code>), equals
60  * (<code>=</code>), colon, asterisk, or question mark. The same key
61  * may not occur twice in a given ObjectName.</p>
62  *
63  * <p>Each <em>value</em> associated with a key is a string of
64  * characters that is either unquoted or quoted.</p>
65  *
66  * <p>An <em>unquoted value</em> is a possibly empty string of
67  * characters which may not contain any of the characters comma,
68  * equals, colon, quote, asterisk, or question mark.</p>
69  *
70  * <p>A <em>quoted value</em> consists of a quote (<code>"</code>),
71  * followed by a possibly empty string of characters, followed by
72  * another quote. Within the string of characters, the backslash
73  * (<code>\</code>) has a special meaning. It must be followed by
74  * one of the following characters:</p>
75  *
76  * <ul>
77  * <li>Another backslash. The second backslash has no special
78  * meaning and the two characters represent a single backslash.
79  *
80  * <li>The character 'n'. The two characters represent a newline
81  * ('\n' in Java).
82  *
83  * <li>A quote. The two characters represent a quote, and that quote
84  * is not considered to terminate the quoted value. An ending closing
85  * quote must be present for the quoted value to be valid.
86  *
87  * <li>A question mark (?) or star (*). The two characters represent
88  * a question mark or star respectively.
89  * </ul>
90  *
91  * <p>A quote, question mark, or star may not appear inside a quoted
92  * value except immediately after an odd number of consecutive
93  * backslashes.</p>
94  *
95  * <p>The quotes surrounding a quoted value, and any backslashes
96  * within that value, are considered to be part of the value.</p>
97  *
98  * <p>An ObjectName may be a <em>property pattern</em>. In this case
99  * it may have zero or more keys and associated values. It matches a
100  * nonpattern ObjectName whose domain matches and that contains the
101  * same keys and associated values, as well as possibly other keys and
102  * values.</p>
103  *
104  * <p>An ObjectName is a pattern if its domain contains a wildcard or
105  * if the ObjectName is a property pattern.</p>
106  *
107  * <p>If an ObjectName is not a pattern, it must contain at least one
108  * key with its associated value.</p>
109  *
110  * <p>An ObjectName can be written as a String with the following
111  * elements in order:</p>
112  *
113  * <ul>
114  * <li>The domain.
115  * <li>A colon (<code>:</code>).
116  * <li>A key property list as defined below.
117  * </ul>
118  *
119  * <p>A key property list written as a String is a comma-separated
120  * list of elements. Each element is either an asterisk or a key
121  * property. A key property consists of a key, an equals
122  * (<code>=</code>), and the associated value.</p>
123  *
124  * <p>At most one element of a key property list may be an asterisk.
125  * If the key property list contains an asterisk element, the
126  * ObjectName is a property pattern.</p>
127  *
128  * <p>Spaces have no special significance in a String representing an
129  * ObjectName. For example, the String:
130  * <pre>
131  * domain: key1 = value1 , key2 = value2
132  * </pre>
133  * represents an ObjectName with two keys. The name of each key
134  * contains six characters, of which the first and last are spaces.
135  * The value associated with the key <code>"&nbsp;key1&nbsp;"</code>
136  * also begins and ends with a space.</p>
137  *
138  * <p>In addition to the restrictions on characters spelt out above,
139  * no part of an ObjectName may contain a newline character
140  * (<code>'\n'</code>), whether the domain, a key, or a value, whether
141  * quoted or unquoted. The newline character can be represented in a
142  * quoted value with the sequence <code>\n</code>.
143  *
144  * <p>The rules on special characters and quoting apply regardless of
145  * which constructor is used to make an ObjectName.</p>
146  *
147  * <p>To avoid collisions between MBeans supplied by different
148  * vendors, a useful convention is to begin the domain name with the
149  * reverse DNS name of the organization that specifies the MBeans,
150  * followed by a period and a string whose interpretation is
151  * determined by that organization. For example, MBeans specified by
152  * Sun Microsystems Inc., DNS name <code>sun.com</code>, would have
153  * domains such as <code>com.sun.MyDomain</code>. This is essentially
154  * the same convention as for Java-language package names.</p>
155  *
156  * @since 1.5
157  */

158 public class ObjectName implements QueryExp JavaDoc, Serializable JavaDoc {
159
160     /**
161      * A structure recording property structure and
162      * proposing minimal services
163      */

164     private final static class Property {
165
166         int _key_index;
167         int _key_length;
168         int _value_length;
169
170         /**
171          * Constructor.
172          */

173         Property(int key_index, int key_length, int value_length) {
174             _key_index = key_index;
175             _key_length = key_length;
176             _value_length = value_length;
177         }
178
179         /**
180          * Assigns the key index of property
181          */

182         void setKeyIndex(int key_index) {
183             _key_index = key_index;
184         }
185
186         /**
187          * Returns a key string for receiver key
188          */

189         String JavaDoc getKeyString(String JavaDoc name) {
190             return name.substring(_key_index, _key_index + _key_length);
191         }
192
193         /**
194          * Returns a value string for receiver key
195          */

196         String JavaDoc getValueString(String JavaDoc name) {
197             int in_begin = _key_index + _key_length + 1;
198             int out_end = in_begin + _value_length;
199             return name.substring(in_begin, out_end);
200         }
201     }
202     // Inner classes <========================================
203

204
205
206     // Private fields ---------------------------------------->
207

208
209     // Serialization compatibility stuff -------------------->
210

211     // Two serial forms are supported in this class. The selected form depends
212
// on system property "jmx.serial.form":
213
// - "1.0" for JMX 1.0
214
// - any other value for JMX 1.1 and higher
215
//
216
// Serial version for old serial form
217
private static final long oldSerialVersionUID = -5467795090068647408L;
218     //
219
// Serial version for new serial form
220
private static final long newSerialVersionUID = 1081892073854801359L;
221     //
222
// Serializable fields in old serial form
223
private static final ObjectStreamField JavaDoc[] oldSerialPersistentFields =
224     {
225     new ObjectStreamField JavaDoc("domain", String JavaDoc.class),
226     new ObjectStreamField JavaDoc("propertyList", Hashtable JavaDoc.class),
227     new ObjectStreamField JavaDoc("propertyListString", String JavaDoc.class),
228     new ObjectStreamField JavaDoc("canonicalName", String JavaDoc.class),
229     new ObjectStreamField JavaDoc("pattern", Boolean.TYPE),
230     new ObjectStreamField JavaDoc("propertyPattern", Boolean.TYPE)
231     };
232     //
233
// Serializable fields in new serial form
234
private static final ObjectStreamField JavaDoc[] newSerialPersistentFields = { };
235     //
236
// Actual serial version and serial form
237
private static final long serialVersionUID;
238     private static final ObjectStreamField JavaDoc[] serialPersistentFields;
239     private static boolean compat = false;
240     static {
241     try {
242         PrivilegedAction JavaDoc act = new GetPropertyAction("jmx.serial.form");
243         String JavaDoc form = (String JavaDoc) AccessController.doPrivileged(act);
244         compat = (form != null && form.equals("1.0"));
245     } catch (Exception JavaDoc e) {
246         // OK: exception means no compat with 1.0, too bad
247
}
248     if (compat) {
249         serialPersistentFields = oldSerialPersistentFields;
250         serialVersionUID = oldSerialVersionUID;
251     } else {
252         serialPersistentFields = newSerialPersistentFields;
253         serialVersionUID = newSerialVersionUID;
254     }
255     }
256
257     //
258
// Serialization compatibility stuff <==============================
259

260     // Class private fields ----------------------------------->
261

262     /**
263      * a shared empty array for empty property lists
264      */

265     static final private Property[] _Empty_property_array = new Property[0];
266
267     /**
268      * a shared empty hashtable for empty property lists
269      */

270     static final private Hashtable JavaDoc _EmptyPropertyList = new Hashtable JavaDoc(1);
271
272     
273     // Class private fields <==============================
274

275     // Instance private fields ----------------------------------->
276

277     /**
278      * a String containing the canonical name
279      */

280     private transient String JavaDoc _canonicalName;
281
282     
283     /**
284      * An array of properties in the same seq order as time creation
285      */

286     private transient Property[] _kp_array;
287
288     /**
289      * An array of properties in the same seq order as canonical order
290      */

291     private transient Property[] _ca_array;
292
293
294     /**
295      * The length of the domain part of built objectname
296      */

297     private transient int _domain_length = 0;
298
299
300     /**
301      * The propertyList of built object name. Initialized lazily.
302      * Table that contains all the pairs (key,value) for this ObjectName.
303      */

304     private transient Hashtable JavaDoc _propertyList;
305
306     /**
307      * boolean that declares if this ObjectName domain part is a pattern
308      */

309     private transient boolean _domain_pattern = false;
310
311     /**
312      * boolean that declares if this ObjectName contains a pattern on the
313      * key property list
314      */

315     private transient boolean _property_pattern = false;
316
317     // Instance private fields <=======================================
318

319     // Private fields <========================================
320

321
322     // Private methods ---------------------------------------->
323

324     // Category : Instance construction ------------------------->
325

326     /**
327      * Initializes this {@link ObjectName} from the given string
328      * representation.
329      *
330      * @param name A string representation of the {@link ObjectName}
331      *
332      * @exception MalformedObjectNameException The string passed as a
333      * parameter does not have the right format.
334      * @exception NullPointerException The <code>name</code> parameter
335      * is null.
336      */

337     private void construct(String JavaDoc name)
338     throws MalformedObjectNameException JavaDoc, NullPointerException JavaDoc {
339
340     // The name cannot be null
341
if (name == null)
342         throw new NullPointerException JavaDoc("name cannot be null");
343
344     // Test if the name is empty
345
if (name.length() == 0) {
346             // this is equivalent to the whole word query object name.
347
_canonicalName = "*:*";
348             _kp_array = _Empty_property_array;
349             _ca_array = _Empty_property_array;
350             _domain_length = 1;
351             _propertyList = null;
352             _domain_pattern = true;
353             _property_pattern = true;
354             return;
355         }
356
357         // initialize parsing of the string
358
char[] name_chars = name.toCharArray();
359         int len = name_chars.length;
360         char[] canonical_chars = new char[len]; // canonical form will be same
361
// length at most
362
int cname_index = 0;
363     int index = 0;
364         char c, c1;
365
366         // parses domain part
367
domain_parsing:
368         while (index < len) {
369             switch (c = name_chars[index]) {
370                 case ':' :
371                     _domain_length = index++;
372                     break domain_parsing;
373                 case '=' :
374                     int i = ++index;
375                     while ((i < len) && (name_chars[i++] != ':'))
376                     if (i == len)
377             throw new MalformedObjectNameException JavaDoc(
378                        "Domain part must be specified");
379             break;
380                 case '\n' :
381                     throw new MalformedObjectNameException JavaDoc(
382                   "Invalid character '\\n' in domain name");
383                 case '*' :
384                 case '?' :
385                     _domain_pattern = true;
386                 default :
387                     index++;
388             }
389         }
390
391         // check for non-empty properties
392
if (index == len)
393         throw new MalformedObjectNameException JavaDoc(
394                      "Key properties cannot be empty");
395
396         // we have got the domain part, begins building of _canonicalName
397
System.arraycopy(name_chars, 0, canonical_chars, 0, _domain_length);
398         canonical_chars[_domain_length] = ':';
399         cname_index = _domain_length + 1;
400
401         // parses property list
402
Property prop;
403         HashMap JavaDoc keys_map = new HashMap JavaDoc();
404         String JavaDoc[] keys;
405         String JavaDoc key_name;
406         boolean quoted_value;
407         int property_index = 0;
408         int in_index;
409         int key_index, key_length, value_index, value_length;
410
411         keys = new String JavaDoc[10];
412         _kp_array = new Property[10];
413         _property_pattern = false;
414
415         while (index < len) {
416             c = name_chars[index];
417
418             // case of pattern properties
419
if (c == '*') {
420                 if (_property_pattern)
421             throw new MalformedObjectNameException JavaDoc(
422                   "Cannot have several '*' characters in pattern " +
423                   "properties");
424                 else {
425                     _property_pattern = true;
426                     if ((++index < len ) && (name_chars[index] != ','))
427             throw new MalformedObjectNameException JavaDoc(
428                       "Invalid character found after '*': end of " +
429                   "name or ',' expected");
430                     else if (index == len) {
431                         if (property_index == 0) {
432                             // empty properties case
433
_kp_array = _Empty_property_array;
434                             _ca_array = _Empty_property_array;
435                             _propertyList = _EmptyPropertyList;
436                         }
437                         break;
438                     }
439                     else {
440                         // correct pattern spec in props, continue
441
index++;
442                         continue;
443                     }
444                 }
445             }
446
447             // standard property case, key part
448
in_index = index;
449             key_index = in_index;
450             while ((in_index < len) && ((c1 = name_chars[in_index++]) != '='))
451                 switch (c1) {
452                     // '=' considered to introduce value part
453
case '*' :
454                     case '?' :
455                     case ',' :
456                     case ':' :
457                     case '\n' :
458             final String JavaDoc ichar = ((c1=='\n')?"\\n":""+c1);
459                         throw new MalformedObjectNameException JavaDoc(
460                   "Invalid character '" + ichar +
461                   "' in key part of property");
462                     default: ;
463                 }
464             if (in_index == len)
465         throw new MalformedObjectNameException JavaDoc(
466                          "Unterminated key property part");
467             if (in_index == index)
468         throw new MalformedObjectNameException JavaDoc("Invalid key (empty)");
469             value_index = in_index; // in_index pointing after '=' char
470
key_length = value_index - key_index - 1; // found end of key
471

472             // standard property case, value part
473
if (name_chars[in_index] == '\"') {
474                 quoted_value = true;
475                 // the case of quoted value part
476
quoted_value_parsing:
477                 while ((++in_index < len) &&
478                ((c1 = name_chars[in_index]) != '\"')) {
479                     // the case of an escaped character
480
if (c1 == '\\') {
481                         if (++in_index == len)
482                 throw new MalformedObjectNameException JavaDoc(
483                            "Unterminated quoted value");
484                         switch (c1 = name_chars[in_index]) {
485                             case '\\' :
486                             case '\"' :
487                             case '?' :
488                             case '*' :
489                             case 'n' :
490                                 break; // valid character
491
default :
492                                 throw new MalformedObjectNameException JavaDoc(
493                       "Invalid escape sequence '\\" +
494                       c1 + "' in quoted value");
495                         }
496             } else if (c1 == '\n') {
497             throw new MalformedObjectNameException JavaDoc(
498                              "Newline in quoted value");
499             } else {
500                         switch (c1) {
501                             case '?' :
502                             case '*' :
503                                 throw new MalformedObjectNameException JavaDoc(
504                       "Invalid unescaped reserved character '" +
505                       c1 + "' in quoted value");
506                             default:
507                                 break;
508                         }
509                     }
510         }
511                 if (in_index == len)
512             throw new MalformedObjectNameException JavaDoc(
513                          "Unterminated quoted value");
514                 else value_length = ++in_index - value_index;
515             }
516             else {
517                 // the case of standard value part
518
quoted_value = false;
519                 while ((in_index < len) && ((c1 = name_chars[in_index]) != ','))
520                 switch (c1) {
521                     // ',' considered to be the value separator
522
case '*' :
523                     case '?' :
524                     case '=' :
525                     case ':' :
526                     case '"' :
527                     case '\n' :
528             final String JavaDoc ichar = ((c1=='\n')?"\\n":""+c1);
529                         throw new MalformedObjectNameException JavaDoc(
530                          "Invalid character '" + c1 +
531                          "' in value part of property");
532                     default : in_index++;
533                 }
534                 value_length = in_index - value_index;
535             }
536
537             // Parsed property, checks the end of name
538
if (in_index == len - 1) {
539                 if (quoted_value)
540             throw new MalformedObjectNameException JavaDoc(
541                          "Invalid ending character `" +
542                          name_chars[in_index] + "'");
543                 else throw new MalformedObjectNameException JavaDoc(
544                           "Invalid ending comma");
545             }
546             else in_index++;
547
548             // we got the key and value part, prepare a property for this
549
prop = new Property(key_index, key_length, value_length);
550             key_name = name.substring(key_index, key_index + key_length);
551
552             if (property_index == keys.length) {
553                 String JavaDoc[] tmp_string_array = new String JavaDoc[property_index + 10];
554                 System.arraycopy(keys, 0, tmp_string_array, 0, property_index);
555                 keys = tmp_string_array;
556             }
557             keys[property_index] = key_name;
558
559             addProperty(prop, property_index, keys_map, key_name);
560             property_index++;
561             index = in_index;
562         }
563
564         // computes and set canonical name
565
setCanonicalName(name_chars, canonical_chars, keys,
566              keys_map, cname_index, property_index);
567     }
568
569     /**
570      * Construct an ObjectName from a domain and a Hashtable.
571      *
572      * @param domain Domain of the ObjectName.
573      * @param props Hashtable containing couples <i>key</i> -> <i>value</i>.
574      *
575      * @exception MalformedObjectNameException The <code>domain</code>
576      * contains an illegal character, or one of the keys or values in
577      * <code>table</code> contains an illegal character, or one of the
578      * values in <code>table</code> does not follow the rules for quoting.
579      * @exception NullPointerException One of the parameters is null.
580      */

581     private void construct(String JavaDoc domain, Hashtable JavaDoc props)
582     throws MalformedObjectNameException JavaDoc, NullPointerException JavaDoc {
583
584     // The domain cannot be null
585
if (domain == null)
586         throw new NullPointerException JavaDoc("domain cannot be null");
587
588     // The key property list cannot be null
589
if (props == null)
590         throw new NullPointerException JavaDoc("key property list cannot be null");
591
592     // The key property list cannot be empty
593
if (props.isEmpty())
594         throw new MalformedObjectNameException JavaDoc(
595                      "key property list cannot be empty");
596
597         // checks domain validity
598
if (!isDomain(domain))
599             throw new MalformedObjectNameException JavaDoc("Invalid domain: " + domain);
600
601         // init canonicalname
602
final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
603         sb.append(domain).append(':');
604         _domain_length = domain.length();
605
606         // allocates the property array
607
int nb_props = props.size();
608         _kp_array = new Property[nb_props];
609
610         String JavaDoc[] keys = new String JavaDoc[nb_props];
611     final Enumeration JavaDoc e = props.keys();
612         final HashMap JavaDoc keys_map = new HashMap JavaDoc();
613         Property prop;
614         int key_index;
615     for (int i = 0; e.hasMoreElements(); i++ ) {
616             if (i > 0) sb.append(",");
617         String JavaDoc key = "";
618         try {
619         key = (String JavaDoc)e.nextElement();
620         } catch (Exception JavaDoc x) {
621         throw new MalformedObjectNameException JavaDoc("Invalid key `" +
622                                key + "'");
623         }
624         String JavaDoc value = "";
625         try {
626         value = (String JavaDoc)props.get(key);
627         } catch (Exception JavaDoc x) {
628         throw new MalformedObjectNameException JavaDoc("Invalid value `" +
629                                value + "'");
630         }
631         key_index = sb.length();
632             checkKey(key);
633             sb.append(key);
634             keys[i] = key;
635             sb.append("=");
636         checkValue(value);
637             sb.append(value);
638             prop = new Property(key_index, key.length(), value.length());
639         addProperty(prop, i, keys_map, key);
640     }
641
642         // initialise canonical name and data structure
643
int len = sb.length();
644         char[] initial_chars = new char[len];
645         sb.getChars(0, len, initial_chars, 0);
646         char[] canonical_chars = new char[len];
647         System.arraycopy(initial_chars, 0, canonical_chars, 0,
648              _domain_length + 1);
649         setCanonicalName(initial_chars, canonical_chars, keys, keys_map,
650              _domain_length + 1, _kp_array.length);
651     }
652     // Category : Instance construction <==============================
653

654     // Category : Internal utilities ------------------------------>
655

656     /**
657      * Add passed property to the list at the given index
658      * for the passed key name
659      */

660     private void addProperty(Property prop, int index,
661                  HashMap JavaDoc keys_map, String JavaDoc key_name)
662     throws MalformedObjectNameException JavaDoc {
663
664         if (keys_map.containsKey(key_name)) throw new
665                 MalformedObjectNameException JavaDoc("key `" +
666                      key_name +"' already defined");
667             
668         // if no more space for property arrays, have to increase it
669
if (index == _kp_array.length) {
670             Property[] tmp_prop_array = new Property[index + 10];
671             System.arraycopy(_kp_array, 0, tmp_prop_array, 0, index);
672             _kp_array = tmp_prop_array;
673         }
674         _kp_array[index] = prop;
675         keys_map.put(key_name, prop);
676     }
677         
678     /**
679      * Sets the canonical name of receiver from input 'specified_chars'
680      * array, by filling 'canonical_chars' array with found 'nb-props'
681      * properties starting at position 'prop_index'.
682      */

683     private void setCanonicalName(char[] specified_chars,
684                                   char[] canonical_chars,
685                                   String JavaDoc[] keys, HashMap JavaDoc keys_map,
686                                   int prop_index, int nb_props) {
687
688         // Sort the list of found properties
689
if (_kp_array != _Empty_property_array) {
690             String JavaDoc[] tmp_keys = new String JavaDoc[nb_props];
691             Property[] tmp_props = new Property[nb_props];
692
693             System.arraycopy(keys, 0, tmp_keys, 0, nb_props);
694             Arrays.sort(tmp_keys);
695             keys = tmp_keys;
696             System.arraycopy(_kp_array, 0, tmp_props, 0 , nb_props);
697             _kp_array = tmp_props;
698             _ca_array = new Property[nb_props];
699
700             // now assigns _ca_array to the sorted list of keys
701
// (there cannot be two identical keys in an objectname.
702
for (int i = 0; i < nb_props; i++)
703                 _ca_array[i] = (Property) keys_map.get(keys[i]);
704
705             // now we build the canonical name and set begin indexes of
706
// properties to reflect canonical form
707
int last_index = nb_props - 1;
708             int prop_len;
709             Property prop;
710             for (int i = 0; i <= last_index; i++) {
711                 prop = _ca_array[i];
712         // length of prop including '=' char
713
prop_len = prop._key_length + prop._value_length + 1;
714                 System.arraycopy(specified_chars, prop._key_index,
715                  canonical_chars, prop_index, prop_len);
716                 prop.setKeyIndex(prop_index);
717                 prop_index += prop_len;
718                 if (i != last_index) {
719                     canonical_chars[prop_index] = ',';
720                     prop_index++;
721                 }
722             }
723         }
724         
725         // terminate canonicalname with '*' in case of pattern
726
if (_property_pattern) {
727             if (_kp_array != _Empty_property_array)
728         canonical_chars[prop_index++] = ',';
729             canonical_chars[prop_index++] = '*';
730         }
731
732         // we now build the canonicalname string
733
_canonicalName = (new String JavaDoc(canonical_chars, 0, prop_index)).intern();
734     }
735
736     /**
737      * Parse a key.
738      * <pre>final int endKey=parseKey(s,startKey);</pre>
739      * <p>key starts at startKey (included), and ends at endKey (excluded).
740      * If (startKey == endKey), then the key is empty.
741      *
742      * @param s The char array of the original string.
743      * @param startKey index at which to begin parsing.
744      * @return The index following the last character of the key.
745      **/

746     private final static int parseKey(final char[] s, final int startKey)
747     throws MalformedObjectNameException JavaDoc {
748     int next = startKey;
749     int endKey = startKey;
750     final int len = s.length;
751     while (next < len) {
752         final char k = s[next++];
753         switch (k) {
754         case '*':
755         case '?':
756         case ',':
757         case ':':
758         case '\n':
759         final String JavaDoc ichar = ((k=='\n')?"\\n":""+k);
760         throw new
761             MalformedObjectNameException JavaDoc("Invalid character in key: `"
762                          + ichar + "'");
763         case '=':
764         // we got the key.
765
endKey = next-1;
766         break;
767         default:
768         if (next < len) continue;
769         else endKey=next;
770         }
771         break;
772     }
773     return endKey;
774     }
775
776     /**
777      * Parse a value.
778      * <pre>final int endVal=parseValue(s,startVal);</pre>
779      * <p>value starts at startVal (included), and ends at endVal (excluded).
780      * If (startVal == endVal), then the key is empty.
781      *
782      * @param s The char array of the original string.
783      * @param startValue index at which to begin parsing.
784      * @return The index following the last character of the value.
785      **/

786     private final static int parseValue(final char[] s, final int startValue)
787     throws MalformedObjectNameException JavaDoc {
788
789     int next = startValue;
790     int endValue = startValue;
791
792     final int len = s.length;
793     final char q=s[startValue];
794
795     if (q == '"') {
796         // quoted value
797
if (++next == len) throw new
798         MalformedObjectNameException JavaDoc("Invalid quote");
799         while (next < len) {
800         char last = s[next];
801                 if (last == '\\') {
802                     if (++next == len) throw new
803                         MalformedObjectNameException JavaDoc(
804                "Invalid unterminated quoted character sequence");
805                     last = s[next];
806                     switch (last) {
807                         case '\\' :
808                         case '?' :
809                         case '*' :
810             case 'n' :
811                             break;
812                         case '\"' :
813                 // We have an escaped quote. If this escaped
814
// quote is the last character, it does not
815
// qualify as a valid termination quote.
816
//
817
if (next+1 == len) throw new
818                 MalformedObjectNameException JavaDoc(
819                          "Missing termination quote");
820                 break;
821                         default:
822                             throw new
823                                 MalformedObjectNameException JavaDoc(
824                 "Invalid quoted character sequence '\\" +
825                 last + "'");
826                     }
827                 } else if (last == '\n') {
828             throw new MalformedObjectNameException JavaDoc(
829                          "Newline in quoted value");
830                 } else if (last == '\"') {
831                     next++;
832                     break;
833                 } else {
834                     switch (last) {
835                         case '?' :
836                         case '*' :
837                             throw new MalformedObjectNameException JavaDoc(
838                       "Invalid unescaped reserved character '" +
839                       last + "' in quoted value");
840                         default:
841                             break;
842                     }
843                 }
844                 next++;
845
846         // Check that last character is a termination quote.
847
// We have already handled the case were the last
848
// character is an escaped quote earlier.
849
//
850
if ((next >= len) && (last != '\"')) throw new
851             MalformedObjectNameException JavaDoc("Missing termination quote");
852         }
853         endValue = next;
854         if (next < len) {
855         if (s[next++] != ',') throw new
856             MalformedObjectNameException JavaDoc("Invalid quote");
857         }
858     }
859         else {
860         // Non quoted value.
861
while (next < len) {
862         final char v=s[next++];
863         switch(v) {
864                     case '*':
865                     case '?':
866                     case '=':
867                     case ':':
868                     case '\n' :
869             final String JavaDoc ichar = ((v=='\n')?"\\n":""+v);
870                         throw new
871             MalformedObjectNameException JavaDoc("Invalid character `" +
872                              ichar + "' in value");
873             case ',':
874                 endValue = next-1;
875             break;
876         default:
877             if (next < len) continue;
878             else endValue=next;
879         }
880         break;
881         }
882     }
883     return endValue;
884     }
885
886     /**
887      * Check if the value given in parameter in the first constructor is a
888      * valid value
889      */

890     private String JavaDoc checkValue(String JavaDoc val)
891     throws MalformedObjectNameException JavaDoc {
892
893     if (val == null) throw new
894         MalformedObjectNameException JavaDoc("Invalid value (null)");
895
896     final int len = val.length();
897     if (len == 0) throw new
898         MalformedObjectNameException JavaDoc("Invalid value (empty)");
899
900     final char[] s = val.toCharArray();
901     final int endValue = parseValue(s,0);
902     if (endValue < len) throw new
903         MalformedObjectNameException JavaDoc("Invalid character in value: `" +
904                      s[endValue] + "'");
905     return val;
906     }
907    
908     /**
909      * Check if the key given in parameter in the first constructor is a
910      * valid key.
911      */

912     private String JavaDoc checkKey(String JavaDoc key)
913     throws MalformedObjectNameException JavaDoc {
914
915     if (key == null) throw new
916         MalformedObjectNameException JavaDoc("Invalid key (null)");
917     
918     final int len = key.length();
919     if (len == 0) throw new
920         MalformedObjectNameException JavaDoc("Invalid key (empty)");
921     final char[] k=key.toCharArray();
922     final int endKey = parseKey(k,0);
923     if (endKey < len) throw new
924         MalformedObjectNameException JavaDoc("Invalid character in value: `" +
925                      k[endKey] + "'");
926     return key;
927     }
928
929     /*
930      * Tests whether string s is matched by pattern p.
931      * Supports "?", "*" each of which may be escaped with "\";
932      * Not yet supported: internationalization; "\" inside brackets.<P>
933      * Wildcard matching routine by Karl Heuer. Public Domain.<P>
934      */

935     private static boolean wildmatch(char[] s, char[] p, int si, int pi) {
936         char c;
937         final int slen = s.length;
938         final int plen = p.length;
939
940         while (pi < plen) { // While still string
941
c = p[pi++];
942             if (c == '?') {
943                 if (++si > slen) return false;
944             } else if (c == '*') { // Wildcard
945
if (pi >= plen) return true;
946                 do {
947                     if (wildmatch(s,p,si,pi)) return true;
948                 } while (++si < slen);
949                 return false;
950             } else {
951                 if (si >= slen || c != s[si++]) return false;
952             }
953         }
954         return (si == slen);
955     }
956
957     // Category : Internal utilities <==============================
958

959     // Category : Internal accessors ------------------------------>
960

961     /**
962      * Check if domain is a valid domain
963      */

964     private boolean isDomain(String JavaDoc domain) {
965     if (domain == null) return true;
966     final char[] d=domain.toCharArray();
967     final int len = d.length;
968     int next = 0;
969     while (next < len) {
970         final char c = d[next++];
971         switch (c) {
972                 case ':' :
973                 case '\n' :
974                     return false;
975                 case '*' :
976                 case '?' :
977                     _domain_pattern = true;
978                 default:
979                     continue;
980         }
981     }
982     return true;
983     }
984
985     // Category : Internal accessors <==============================
986

987     // Category : Serialization ----------------------------------->
988

989     /**
990      * Deserializes an {@link ObjectName} from an {@link ObjectInputStream}.
991      * @serialData <ul>
992      * <li>In the current serial form (value of property
993      * <code>jmx.serial.form</code> differs from
994      * <code>1.0</code>): the string
995      * &quot;&lt;domain&gt;:&lt;properties&gt;&lt;wild&gt;&quot;,
996      * where: <ul>
997      * <li>&lt;domain&gt; represents the domain part
998      * of the {@link ObjectName}</li>
999      * <li>&lt;properties&gt; represents the list of
1000     * properties, as returned by
1001     * {@link #getKeyPropertyListString}
1002     * <li>&lt;wild&gt; is empty if not
1003     * <code>isPropertyPattern</code>, or
1004     * is the character "<code>*</code>" if
1005     * <code>isPropertyPattern</code>
1006     * and &lt;properties&gt; is empty, or
1007     * is "<code>,*</code>" if
1008     * <code>isPropertyPattern</code> and
1009     * &lt;properties&gt; is not empty.
1010     * </li>
1011     * </ul>
1012     * The intent is that this string could be supplied
1013     * to the {@link #ObjectName(String)} constructor to
1014     * produce an equivalent {@link ObjectName}.
1015     * </li>
1016     * <li>In the old serial form (value of property
1017     * <code>jmx.serial.form</code> is
1018     * <code>1.0</code>): &lt;domain&gt; &lt;propertyList&gt;
1019     * &lt;propertyListString&gt; &lt;canonicalName&gt;
1020     * &lt;pattern&gt; &lt;propertyPattern&gt;,
1021     * where: <ul>
1022     * <li>&lt;domain&gt; represents the domain part
1023     * of the {@link ObjectName}</li>
1024     * <li>&lt;propertyList&gt; is the
1025     * {@link Hashtable} that contains all the
1026     * pairs (key,value) for this
1027     * {@link ObjectName}</li>
1028     * <li>&lt;propertyListString&gt; is the
1029     * {@link String} representation of the
1030     * list of properties in any order (not
1031     * mandatorily a canonical representation)
1032     * </li>
1033     * <li>&lt;canonicalName&gt; is the
1034     * {@link String} containing this
1035     * {@link ObjectName}'s canonical name</li>
1036     * <li>&lt;pattern&gt; is a boolean which is
1037     * <code>true</code> if this
1038     * {@link ObjectName} contains a pattern</li>
1039     * <li>&lt;propertyPattern&gt; is a boolean which
1040     * is <code>true</code> if this
1041     * {@link ObjectName} contains a pattern in
1042     * the list of properties</li>
1043     * </ul>
1044     * </li>
1045     * </ul>
1046     */

1047    private void readObject(ObjectInputStream JavaDoc in)
1048    throws IOException JavaDoc, ClassNotFoundException JavaDoc {
1049
1050    String JavaDoc cn;
1051    if (compat) {
1052        // Read an object serialized in the old serial form
1053
//
1054
//in.defaultReadObject();
1055
final ObjectInputStream.GetField JavaDoc fields = in.readFields();
1056        String JavaDoc propListString =
1057        (String JavaDoc)fields.get("propertyListString", "");
1058
1059            // 6616825: take care of property patterns
1060
final boolean propPattern =
1061                    fields.get("propertyPattern" , false);
1062            if (propPattern) {
1063                propListString =
1064                        (propListString.length()==0?"*":(propListString+",*"));
1065            }
1066             
1067            cn = (String JavaDoc)fields.get("domain", "default")+
1068                ":"+ propListString;
1069    } else {
1070        // Read an object serialized in the new serial form
1071
//
1072
in.defaultReadObject();
1073        cn = (String JavaDoc)in.readObject();
1074    }
1075
1076    try {
1077        construct(cn);
1078    } catch (NullPointerException JavaDoc e) {
1079        throw new InvalidObjectException JavaDoc(e.toString());
1080    } catch (MalformedObjectNameException JavaDoc e) {
1081        throw new InvalidObjectException JavaDoc(e.toString());
1082    }
1083    }
1084
1085
1086    /**
1087     * Serializes an {@link ObjectName} to an {@link ObjectOutputStream}.
1088     * @serialData <ul>
1089     * <li>In the current serial form (value of property
1090     * <code>jmx.serial.form</code> differs from
1091     * <code>1.0</code>): the string
1092     * &quot;&lt;domain&gt;:&lt;properties&gt;&lt;wild&gt;&quot;,
1093     * where: <ul>
1094     * <li>&lt;domain&gt; represents the domain part
1095     * of the {@link ObjectName}</li>
1096     * <li>&lt;properties&gt; represents the list of
1097     * properties, as returned by
1098     * {@link #getKeyPropertyListString}
1099     * <li>&lt;wild&gt; is empty if not
1100     * <code>isPropertyPattern</code>, or
1101     * is the character "<code>*</code>" if
1102     * this <code>isPropertyPattern</code>
1103     * and &lt;properties&gt; is empty, or
1104     * is "<code>,*</code>" if
1105     * <code>isPropertyPattern</code> and
1106     * &lt;properties&gt; is not empty.
1107     * </li>
1108     * </ul>
1109     * The intent is that this string could be supplied
1110     * to the {@link #ObjectName(String)} constructor to
1111     * produce an equivalent {@link ObjectName}.
1112     * </li>
1113     * <li>In the old serial form (value of property
1114     * <code>jmx.serial.form</code> is
1115     * <code>1.0</code>): &lt;domain&gt; &lt;propertyList&gt;
1116     * &lt;propertyListString&gt; &lt;canonicalName&gt;
1117     * &lt;pattern&gt; &lt;propertyPattern&gt;,
1118     * where: <ul>
1119     * <li>&lt;domain&gt; represents the domain part
1120     * of the {@link ObjectName}</li>
1121     * <li>&lt;propertyList&gt; is the
1122     * {@link Hashtable} that contains all the
1123     * pairs (key,value) for this
1124     * {@link ObjectName}</li>
1125     * <li>&lt;propertyListString&gt; is the
1126     * {@link String} representation of the
1127     * list of properties in any order (not
1128     * mandatorily a canonical representation)
1129     * </li>
1130     * <li>&lt;canonicalName&gt; is the
1131     * {@link String} containing this
1132     * {@link ObjectName}'s canonical name</li>
1133     * <li>&lt;pattern&gt; is a boolean which is
1134     * <code>true</code> if this
1135     * {@link ObjectName} contains a pattern</li>
1136     * <li>&lt;propertyPattern&gt; is a boolean which
1137     * is <code>true</code> if this
1138     * {@link ObjectName} contains a pattern in
1139     * the list of properties</li>
1140     * </ul>
1141     * </li>
1142     * </ul>
1143     */

1144    private void writeObject(ObjectOutputStream JavaDoc out)
1145        throws IOException JavaDoc {
1146      if (compat)
1147      {
1148        // Serializes this instance in the old serial form
1149
//
1150
ObjectOutputStream.PutField JavaDoc fields = out.putFields();
1151    fields.put("domain", _canonicalName.substring(0, _domain_length));
1152    fields.put("propertyList", getKeyPropertyList());
1153    fields.put("propertyListString", getKeyPropertyListString());
1154    fields.put("canonicalName", _canonicalName);
1155    fields.put("pattern", (_domain_pattern || _property_pattern));
1156    fields.put("propertyPattern", _property_pattern);
1157    out.writeFields();
1158      }
1159      else
1160      {
1161        // Serializes this instance in the new serial form
1162
//
1163
out.defaultWriteObject();
1164        out.writeObject(getSerializedNameString());
1165      }
1166    }
1167
1168    // Category : Serialization <===================================
1169

1170    // Private methods <========================================
1171

1172    // Public methods ---------------------------------------->
1173

1174    // Category : ObjectName Construction ------------------------------>
1175

1176    /**
1177     * <p>Return an instance of ObjectName that can be used anywhere
1178     * an object obtained with {@link #ObjectName(String) new
1179     * ObjectName(name)} can be used. The returned object may be of
1180     * a subclass of ObjectName. Calling this method twice with the
1181     * same parameters may return the same object or two equal but
1182     * not identical objects.</p>
1183     *
1184     * @param name A string representation of the object name.
1185     *
1186     * @return an ObjectName corresponding to the given String.
1187     *
1188     * @exception MalformedObjectNameException The string passed as a
1189     * parameter does not have the right format.
1190     * @exception NullPointerException The <code>name</code> parameter
1191     * is null.
1192     *
1193     * @since.unbundled JMX 1.2
1194     */

1195    public static ObjectName JavaDoc getInstance(String JavaDoc name)
1196        throws MalformedObjectNameException JavaDoc, NullPointerException JavaDoc {
1197        return new ObjectName JavaDoc(name);
1198    }
1199
1200    /**
1201     * <p>Return an instance of ObjectName that can be used anywhere
1202     * an object obtained with {@link #ObjectName(String, String,
1203     * String) new ObjectName(domain, key, value)} can be used. The
1204     * returned object may be of a subclass of ObjectName. Calling
1205     * this method twice with the same parameters may return the same
1206     * object or two equal but not identical objects.</p>
1207     *
1208     * @param domain The domain part of the object name.
1209     * @param key The attribute in the key property of the object name.
1210     * @param value The value in the key property of the object name.
1211     *
1212     * @return an ObjectName corresponding to the given domain,
1213     * key, and value.
1214     *
1215     * @exception MalformedObjectNameException The
1216     * <code>domain</code>, <code>key</code>, or <code>value</code>
1217     * contains an illegal character, or <code>value</code> does not
1218     * follow the rules for quoting.
1219     * @exception NullPointerException One of the parameters is null.
1220     *
1221     * @since.unbundled JMX 1.2
1222     */

1223    public static ObjectName JavaDoc getInstance(String JavaDoc domain, String JavaDoc key,
1224                     String JavaDoc value)
1225        throws MalformedObjectNameException JavaDoc, NullPointerException JavaDoc {
1226        return new ObjectName JavaDoc(domain, key, value);
1227    }
1228
1229    /**
1230     * <p>Return an instance of ObjectName that can be used anywhere
1231     * an object obtained with {@link #ObjectName(String, Hashtable)
1232     * new ObjectName(domain, table)} can be used. The returned
1233     * object may be of a subclass of ObjectName. Calling this method
1234     * twice with the same parameters may return the same object or
1235     * two equal but not identical objects.</p>
1236     *
1237     * @param domain The domain part of the object name.
1238     * @param table A hash table containing one or more key
1239     * properties. The key of each entry in the table is the key of a
1240     * key property in the object name. The associated value in the
1241     * table is the associated value in the object name.
1242     *
1243     * @return an ObjectName corresponding to the given domain and
1244     * key mappings.
1245     *
1246     * @exception MalformedObjectNameException The <code>domain</code>
1247     * contains an illegal character, or one of the keys or values in
1248     * <code>table</code> contains an illegal character, or one of the
1249     * values in <code>table</code> does not follow the rules for
1250     * quoting.
1251     * @exception NullPointerException One of the parameters is null.
1252     *
1253     * @since.unbundled JMX 1.2
1254     */

1255    public static ObjectName JavaDoc getInstance(String JavaDoc domain, Hashtable JavaDoc table)
1256    throws MalformedObjectNameException JavaDoc, NullPointerException JavaDoc {
1257        return new ObjectName JavaDoc(domain, table);
1258    }
1259
1260    /**
1261     * <p>Return an instance of ObjectName that can be used anywhere
1262     * the given object can be used. The returned object may be of a
1263     * subclass of ObjectName. If <code>name</code> is of a subclass
1264     * of ObjectName, it is not guaranteed that the returned object
1265     * will be of the same class.</p>
1266     *
1267     * <p>The returned value may or may not be identical to
1268     * <code>name</code>. Calling this method twice with the same
1269     * parameters may return the same object or two equal but not
1270     * identical objects.</p>
1271     *
1272     * <p>Since ObjectName is immutable, it is not usually useful to
1273     * make a copy of an ObjectName. The principal use of this method
1274     * is to guard against a malicious caller who might pass an
1275     * instance of a subclass with surprising behavior to sensitive
1276     * code. Such code can call this method to obtain an ObjectName
1277     * that is known not to have surprising behavior.</p>
1278     *
1279     * @param name an instance of the ObjectName class or of a subclass
1280     *
1281     * @return an instance of ObjectName or a subclass that is known to
1282     * have the same semantics. If <code>name</code> respects the
1283     * semantics of ObjectName, then the returned object is equal
1284     * (though not necessarily identical) to <code>name</code>.
1285     *
1286     * @exception NullPointerException The <code>name</code> is null.
1287     *
1288     * @since.unbundled JMX 1.2
1289     */

1290    public static ObjectName JavaDoc getInstance(ObjectName JavaDoc name)
1291        throws NullPointerException JavaDoc {
1292    if (name.getClass().equals(ObjectName JavaDoc.class))
1293        return name;
1294    try {
1295        return new ObjectName JavaDoc(name.getSerializedNameString());
1296    } catch (MalformedObjectNameException JavaDoc e) {
1297        throw new IllegalArgumentException JavaDoc("Unexpected: " + e);
1298        // can't happen
1299
}
1300    }
1301
1302    /**
1303     * Construct an object name from the given string.
1304     *
1305     * @param name A string representation of the object name.
1306     *
1307     * @exception MalformedObjectNameException The string passed as a
1308     * parameter does not have the right format.
1309     * @exception NullPointerException The <code>name</code> parameter
1310     * is null.
1311     */

1312    public ObjectName(String JavaDoc name)
1313    throws MalformedObjectNameException JavaDoc, NullPointerException JavaDoc {
1314    construct(name);
1315    }
1316
1317    /**
1318     * Construct an object name with exactly one key property.
1319     *
1320     * @param domain The domain part of the object name.
1321     * @param key The attribute in the key property of the object name.
1322     * @param value The value in the key property of the object name.
1323     *
1324     * @exception MalformedObjectNameException The
1325     * <code>domain</code>, <code>key</code>, or <code>value</code>
1326     * contains an illegal character, or <code>value</code> does not
1327     * follow the rules for quoting.
1328     * @exception NullPointerException One of the parameters is null.
1329     */

1330    public ObjectName(String JavaDoc domain, String JavaDoc key, String JavaDoc value)
1331    throws MalformedObjectNameException JavaDoc, NullPointerException JavaDoc {
1332    // If key or value are null a NullPointerException
1333
// will be thrown by the put method in Hashtable.
1334
//
1335
Hashtable JavaDoc table = new Hashtable JavaDoc(1);
1336    table.put(key, value);
1337    construct(domain, table);
1338    }
1339
1340    /**
1341     * Construct an object name with several key properties from a Hashtable.
1342     *
1343     * @param domain The domain part of the object name.
1344     * @param table A hash table containing one or more key
1345     * properties. The key of each entry in the table is the key of a
1346     * key property in the object name. The associated value in the
1347     * table is the associated value in the object name.
1348     *
1349     * @exception MalformedObjectNameException The <code>domain</code>
1350     * contains an illegal character, or one of the keys or values in
1351     * <code>table</code> contains an illegal character, or one of the
1352     * values in <code>table</code> does not follow the rules for
1353     * quoting.
1354     * @exception NullPointerException One of the parameters is null.
1355     */

1356    public ObjectName(String JavaDoc domain, Hashtable JavaDoc table)
1357    throws MalformedObjectNameException JavaDoc, NullPointerException JavaDoc {
1358        construct(domain, table);
1359    }
1360
1361    // Category : ObjectName Construction <==============================
1362

1363
1364    // Category : Getter methods ------------------------------>
1365

1366    /**
1367     * Checks whether the object name is a pattern. An object name is
1368     * a pattern if its domain contains a wildcard or if the object
1369     * name is a property pattern.
1370     *
1371     * @return True if the name is a pattern, otherwise false.
1372     */

1373    public boolean isPattern() {
1374        return (_domain_pattern || _property_pattern);
1375    }
1376 
1377    /**
1378     * Checks whether the object name is a pattern on the domain part.
1379     *
1380     * @return True if the name is a domain pattern, otherwise false.
1381     *
1382     * @since.unbundled JMX 1.2
1383     */

1384    public boolean isDomainPattern() {
1385        return _domain_pattern;
1386    }
1387
1388    /**
1389     * Checks whether the object name is a pattern on the key properties.
1390     *
1391     * @return True if the name is a pattern, otherwise false.
1392     */

1393    public boolean isPropertyPattern() {
1394        return _property_pattern;
1395    }
1396
1397    /**
1398     * <p>Returns the canonical form of the name; that is, a string
1399     * representation where the properties are sorted in lexical
1400     * order.</p>
1401     *
1402     * <p>More precisely, the canonical form of the name is a String
1403     * consisting of the <em>domain part</em>, a colon
1404     * (<code>:</code>), the <em>canonical key property list</em>, and
1405     * a <em>pattern indication</em>.</p>
1406     *
1407     * <p>The <em>canonical key property list</em> is the same string
1408     * as described for {@link #getCanonicalKeyPropertyListString()}.</p>
1409     *
1410     * <p>The <em>pattern indication</em> is:
1411     * <ul>
1412     * <li>empty for an ObjectName
1413     * that is not a property pattern;
1414     * <li>an asterisk for an ObjectName
1415     * that is a property pattern with no keys; or
1416     * <li>a comma and an
1417     * asterisk (<code>,*</code>) for an ObjectName that is a property
1418     * pattern with at least one key.
1419     * </ul></p>
1420     *
1421     * @return The canonical form of the name.
1422     */

1423    public String JavaDoc getCanonicalName() {
1424        return _canonicalName;
1425    }
1426
1427    /**
1428     * Returns the domain part.
1429     *
1430     * @return the domain.
1431     */

1432    public String JavaDoc getDomain() {
1433        return _canonicalName.substring(0, _domain_length);
1434    }
1435   
1436    /**
1437    * Obtains the value associated with a key in a key property.
1438    *
1439    * @param property The property whose value is to be obtained.
1440    *
1441    * @return The value of the property, or null if there is no such
1442    * property in this ObjectName.
1443    *
1444    * @exception NullPointerException If <code>property</code> is null.
1445    */

1446    public String JavaDoc getKeyProperty(String JavaDoc property) throws NullPointerException JavaDoc {
1447        return (String JavaDoc) _getKeyPropertyList().get(property);
1448    }
1449
1450    /**
1451     * <p>Returns the key properties as a Hashtable. The returned
1452     * value is a Hashtable in which each key is a key in the
1453     * ObjectName's key property list and each value is the associated
1454     * value.</p>
1455     *
1456     * <p>The returned value must not be modidied.</p>
1457     *
1458     * @return The table of key properties.
1459     */

1460    private final Hashtable JavaDoc _getKeyPropertyList() {
1461        synchronized (this) {
1462            if (_propertyList == null) {
1463                // build (lazy eval) the property list from the canonical
1464
// properties array
1465
_propertyList = new Hashtable JavaDoc();
1466                int len = _ca_array.length;
1467                Property prop;
1468                for (int i = len - 1; i >= 0; i--) {
1469                    prop = _ca_array[i];
1470                    _propertyList.put(prop.getKeyString(_canonicalName),
1471                                      prop.getValueString(_canonicalName));
1472                }
1473            }
1474        }
1475        return _propertyList;
1476    }
1477
1478    /**
1479     * <p>Returns the key properties as a Hashtable. The returned
1480     * value is a Hashtable in which each key is a key in the
1481     * ObjectName's key property list and each value is the associated
1482     * value.</p>
1483     *
1484     * <p>The returned value may be unmodifiable. If it is
1485     * modifiable, changing it has no effect on this ObjectName.</p>
1486     *
1487     * @return The table of key properties.
1488     */

1489    public Hashtable JavaDoc getKeyPropertyList() {
1490        return (Hashtable JavaDoc)_getKeyPropertyList().clone();
1491    }
1492
1493    /**
1494     * <p>Returns a string representation of the list of key
1495     * properties specified at creation time. If this ObjectName was
1496     * constructed with the constructor {@link #ObjectName(String)},
1497     * the key properties in the returned String will be in the same
1498     * order as in the argument to the constructor.</p>
1499     *
1500     * @return The key property list string. This string is
1501     * independent of whether the ObjectName is a pattern.
1502     */

1503    public String JavaDoc getKeyPropertyListString() {
1504        // BEWARE : we rebuild the propertyliststring at each call !!
1505
if (_kp_array.length == 0) return "";
1506
1507        // the size of the string is the canonical one minus domain
1508
// part and pattern part
1509
final int total_size = _canonicalName.length() - _domain_length - 1
1510        - (_property_pattern?2:0);
1511
1512        final char[] dest_chars = new char[total_size];
1513        final char[] value = _canonicalName.toCharArray();
1514    writeKeyPropertyListString(value,dest_chars,0);
1515        return new String JavaDoc(dest_chars);
1516    }
1517
1518    /**
1519     * <p>Returns the serialized string of the ObjectName.
1520     * properties specified at creation time. If this ObjectName was
1521     * constructed with the constructor {@link #ObjectName(String)},
1522     * the key properties in the returned String will be in the same
1523     * order as in the argument to the constructor.</p>
1524     *
1525     * @return The key property list string. This string is
1526     * independent of whether the ObjectName is a pattern.
1527     */

1528    private String JavaDoc getSerializedNameString() {
1529
1530        // the size of the string is the canonical one
1531
final int total_size = _canonicalName.length();
1532        final char[] dest_chars = new char[total_size];
1533    final char[] value = _canonicalName.toCharArray();
1534    final int offset = _domain_length+1;
1535
1536    // copy "domain:" into dest_chars
1537
//
1538
System.arraycopy(value, 0, dest_chars, 0, offset);
1539
1540    // Add property list string
1541
final int end = writeKeyPropertyListString(value,dest_chars,offset);
1542
1543    // Add ",*" if necessary
1544
if (_property_pattern) {
1545        if (end == offset) {
1546        // Property list string is empty.
1547
dest_chars[end] = '*';
1548        } else {
1549        // Property list string is not empty.
1550
dest_chars[end] = ',';
1551        dest_chars[end+1] = '*';
1552        }
1553    }
1554
1555        return new String JavaDoc(dest_chars);
1556    }
1557
1558    /**
1559     * <p>Write a string representation of the list of key
1560     * properties specified at creation time in the given array, starting
1561     * at the specified offset. If this ObjectName was
1562     * constructed with the constructor {@link #ObjectName(String)},
1563     * the key properties in the returned String will be in the same
1564     * order as in the argument to the constructor.</p>
1565     *
1566     * @return offset + #of chars written
1567     */

1568    private int writeKeyPropertyListString(char[] canonicalChars,
1569                       char[] data, int offset) {
1570        if (_kp_array.length == 0) return offset;
1571
1572        final char[] dest_chars = data;
1573        final char[] value = _canonicalName.toCharArray();
1574
1575        int index = offset;
1576        final int len = _kp_array.length;
1577    final int last = len - 1;
1578        for (int i = 0; i < len; i++) {
1579            final Property prop = _kp_array[i];
1580            final int prop_len = prop._key_length + prop._value_length + 1;
1581            System.arraycopy(value, prop._key_index, dest_chars, index,
1582                 prop_len);
1583            index += prop_len;
1584            if (i < last ) dest_chars[index++] = ',';
1585        }
1586    return index;
1587    }
1588
1589
1590
1591    /**
1592     * Returns a string representation of the list of key properties,
1593     * in which the key properties are sorted in lexical order. This
1594     * is used in lexicographic comparisons performed in order to
1595     * select MBeans based on their key property list. Lexical order
1596     * is the order implied by {@link String#compareTo(String)
1597     * String.compareTo(String)}.
1598     *
1599     * @return The canonical key property list string. This string is
1600     * independent of whether the ObjectName is a pattern.
1601     */

1602    public String JavaDoc getCanonicalKeyPropertyListString() {
1603        if (_ca_array.length == 0) return "";
1604
1605        int len = _canonicalName.length();
1606        if (_property_pattern) len -= 2;
1607        return _canonicalName.substring(_domain_length +1, len);
1608    }
1609    // Category : Getter methods <===================================
1610

1611    // Category : Utilities ---------------------------------------->
1612

1613    /**
1614     * <p>Returns a string representation of the object name. The
1615     * format of this string is not specified, but users can expect
1616     * that two ObjectNames return the same string if and only if they
1617     * are equal.</p>
1618     *
1619     * @return a string representation of this object name.
1620     */

1621    public String JavaDoc toString() {
1622    return getSerializedNameString();
1623    }
1624
1625    /**
1626     * Compares the current object name with another object name. Two
1627     * ObjectName instances are equal if and only if their canonical
1628     * forms are equal. The canonical form is the string described
1629     * for {@link #getCanonicalName()}.
1630     *
1631     * @param object The object name that the current object name is to be
1632     * compared with.
1633     *
1634     * @return True if <code>object</code> is an ObjectName whose
1635     * canonical form is equal to that of this ObjectName.
1636     */

1637    public boolean equals(Object JavaDoc object) {
1638
1639        // same object case
1640
if (this == object) return true;
1641
1642        // object is not an object name case
1643
if (!(object instanceof ObjectName JavaDoc)) return false;
1644
1645        // equality when canonical names are the same
1646
// (because usage of intern())
1647
ObjectName JavaDoc on = (ObjectName JavaDoc) object;
1648        String JavaDoc on_string = on._canonicalName;
1649        if (_canonicalName == on_string) return true;
1650
1651        // Because we are sharing canonical form between object names,
1652
// we have finished the comparison at this stage ==> unequal
1653
return false;
1654   }
1655
1656    /**
1657     * Returns a hash code for this object name.
1658     *
1659     */

1660    public int hashCode() {
1661        return _canonicalName.hashCode();
1662    }
1663
1664    /**
1665     * <p>Returns a quoted form of the given String, suitable for
1666     * inclusion in an ObjectName. The returned value can be used as
1667     * the value associated with a key in an ObjectName. The String
1668     * <code>s</code> may contain any character. Appropriate quoting
1669     * ensures that the returned value is legal in an ObjectName.</p>
1670     *
1671     * <p>The returned value consists of a quote ('"'), a sequence of
1672     * characters corresponding to the characters of <code>s</code>,
1673     * and another quote. Characters in <code>s</code> appear
1674     * unchanged within the returned value except:</p>
1675     *
1676     * <ul>
1677     * <li>A quote ('"')is replaced by a backslash (\) followed by a quote.
1678     * <li>A star ('*') is replaced by a backslash (\) followed by a star.
1679     * <li>A question mark ('?') is replaced by a backslash (\) followed by
1680     * a question mark.
1681     * <li>A backslash ('\') is replaced by two backslashes.
1682     * <li>A newline character (the character '\n' in Java) is replaced
1683     * by a backslash followed by the character '\n'.
1684     * </ul>
1685     *
1686     * @param s the String to be quoted.
1687     *
1688     * @return the quoted String.
1689     *
1690     * @exception NullPointerException if <code>s</code> is null.
1691     *
1692     * @since.unbundled JMX 1.2
1693     */

1694    public static String JavaDoc quote(String JavaDoc s)
1695        throws NullPointerException JavaDoc {
1696    final StringBuffer JavaDoc buf = new StringBuffer JavaDoc("\"");
1697    final int len = s.length();
1698    for (int i = 0; i < len; i++) {
1699        char c = s.charAt(i);
1700        switch (c) {
1701        case '\n':
1702        c = 'n';
1703        // fall in...
1704
case '\\':
1705        case '\"':
1706        case '*':
1707        case '?':
1708        buf.append('\\');
1709        break;
1710        }
1711        buf.append(c);
1712    }
1713    buf.append('"');
1714    return buf.toString();
1715    }
1716
1717    /**
1718     * <p>Returns an unquoted form of the given String. If
1719     * <code>q</code> is a String returned by {@link #quote quote(s)},
1720     * then <code>unquote(q).equals(s)</code>. If there is no String
1721     * <code>s</code> for which <code>quote(s).equals(q)</code>, then
1722     * unquote(q) throws an IllegalArgumentException.</p>
1723     *
1724     * <p>These rules imply that there is a one-to-one mapping between
1725     * quoted and unquoted forms.</p>
1726     *
1727     * @param q the String to be unquoted.
1728     *
1729     * @return the unquoted String.
1730     *
1731     * @exception IllegalArgumentException if <code>q</code> could not
1732     * have been returned by the {@link #quote} method, for instance
1733     * if it does not begin and end with a quote (").
1734     *
1735     * @exception NullPointerException if <code>q</code> is null.
1736     *
1737     * @since.unbundled JMX 1.2
1738     */

1739    public static String JavaDoc unquote(String JavaDoc q)
1740        throws IllegalArgumentException JavaDoc, NullPointerException JavaDoc {
1741    final StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1742    final int len = q.length();
1743    if (len < 2 || q.charAt(0) != '"' || q.charAt(len - 1) != '"')
1744        throw new IllegalArgumentException JavaDoc("Argument not quoted");
1745    for (int i = 1; i < len - 1; i++) {
1746        char c = q.charAt(i);
1747        if (c == '\\') {
1748        if (i == len - 2)
1749            throw new IllegalArgumentException JavaDoc("Trailing backslash");
1750        c = q.charAt(++i);
1751        switch (c) {
1752        case 'n':
1753            c = '\n';
1754            break;
1755        case '\\':
1756        case '\"':
1757        case '*':
1758        case '?':
1759            break;
1760                default:
1761                  throw new IllegalArgumentException JavaDoc(
1762                   "Bad character '" + c + "' after backslash");
1763        }
1764        }
1765            else {
1766                switch (c) {
1767                    case '*' :
1768                    case '?' :
1769                    case '\"':
1770                    case '\n':
1771                         throw new IllegalArgumentException JavaDoc(
1772                      "Invalid unescaped character '" + c +
1773                      "' in the string to unquote");
1774                    default : ;
1775                }
1776            }
1777        buf.append(c);
1778    }
1779    return buf.toString();
1780    }
1781
1782    // Category : Utilities <===================================
1783

1784    // Category : QueryExp Interface ---------------------------------------->
1785

1786
1787    /**
1788     * <p>Test whether this ObjectName, which may be a pattern,
1789     * matches another ObjectName. If <code>name</code> is a pattern,
1790     * the result is false. If this ObjectName is a pattern, the
1791     * result is true if and only if <code>name</code> matches the
1792     * pattern. If neither this ObjectName nor <code>name</code> is
1793     * a pattern, the result is true if and only if the two
1794     * ObjectNames are equal as described for the {@link
1795     * #equals(Object)} method.</p>
1796     *
1797     * @param name The name of the MBean to compare to.
1798     *
1799     * @return True if <code>name</code> matches this ObjectName.
1800     *
1801     * @exception NullPointerException if <code>name</code> is null.
1802     *
1803     * @since.unbundled JMX 1.2
1804     */

1805    public boolean apply(ObjectName JavaDoc name) throws NullPointerException JavaDoc {
1806
1807        if (name == null) throw new NullPointerException JavaDoc();
1808        
1809    if (name._domain_pattern || name._property_pattern)
1810        return false;
1811
1812    // No pattern
1813
if (!_domain_pattern && !_property_pattern)
1814        return _canonicalName.equals(name._canonicalName);
1815
1816    return matchDomains(name) && matchKeys(name);
1817    }
1818
1819    private final boolean matchDomains(ObjectName JavaDoc name) {
1820    if (_domain_pattern) {
1821        // wildmatch domains
1822
final char[] dom_pattern = getDomain().toCharArray();
1823        final char[] dom_string = name.getDomain().toCharArray();
1824        return wildmatch(dom_string,dom_pattern,0,0);
1825    }
1826    return getDomain().equals(name.getDomain());
1827    }
1828
1829    private final boolean matchKeys(ObjectName JavaDoc name) {
1830    if (_property_pattern) {
1831        // Every property inside pattern should exist in name
1832
final Hashtable JavaDoc nameProps = name._getKeyPropertyList();
1833        final Property[] props=_ca_array;
1834        final String JavaDoc cn=_canonicalName;
1835        for (int i= props.length -1; i >= 0 ; i--) {
1836        
1837        // find value in given object name for key at current
1838
// index in receiver
1839

1840        final Property p = props[i];
1841        final String JavaDoc k = p.getKeyString(cn);
1842        final String JavaDoc v = (String JavaDoc)nameProps.get(k);
1843
1844        // did we find a value for this key ?
1845
if (v == null) return false;
1846                    
1847        // if this property is ok (same key, same value),
1848
// go to next
1849
if (v.equals(p.getValueString(cn))) continue;
1850        return false;
1851        }
1852        return true;
1853    }
1854    final String JavaDoc p1 = name.getCanonicalKeyPropertyListString();
1855    final String JavaDoc p2 = getCanonicalKeyPropertyListString();
1856    return (p1.equals(p2));
1857    }
1858
1859    /* Method inherited from QueryExp, no implementation needed here
1860       because ObjectName is not relative to an MBeanServer and does
1861       not contain a subquery.
1862    */

1863    public void setMBeanServer(MBeanServer JavaDoc mbs) { }
1864
1865    // Category : QueryExp Interface <=========================
1866

1867    // Public methods <========================================
1868

1869}
1870
Popular Tags