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