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