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

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