History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/management/ObjectName.java (1 of 18352 files). Show all

Unified · Split

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