Home » openjdk-7 » javax » management » [javadoc | source]

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

Home » openjdk-7 » javax » management » [javadoc | source]