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>" key1 "</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 * "<domain>:<properties><wild>",
1103 * where: <ul>
1104 * <li><domain> represents the domain part
1105 * of the {@link ObjectName}</li>
1106 * <li><properties> represents the list of
1107 * properties, as returned by
1108 * {@link #getKeyPropertyListString}
1109 * <li><wild> is empty if not
1110 * <code>isPropertyPattern</code>, or
1111 * is the character "<code>*</code>" if
1112 * <code>isPropertyPattern</code>
1113 * and <properties> is empty, or
1114 * is "<code>,*</code>" if
1115 * <code>isPropertyPattern</code> and
1116 * <properties> 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>): <domain> <propertyList>
1126 * <propertyListString> <canonicalName>
1127 * <pattern> <propertyPattern>,
1128 * where: <ul>
1129 * <li><domain> represents the domain part
1130 * of the {@link ObjectName}</li>
1131 * <li><propertyList> is the
1132 * {@link Hashtable} that contains all the
1133 * pairs (key,value) for this
1134 * {@link ObjectName}</li>
1135 * <li><propertyListString> 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><canonicalName> is the
1141 * {@link String} containing this
1142 * {@link ObjectName}'s canonical name</li>
1143 * <li><pattern> is a boolean which is
1144 * <code>true</code> if this
1145 * {@link ObjectName} contains a pattern</li>
1146 * <li><propertyPattern> 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 * "<domain>:<properties><wild>",
1190 * where: <ul>
1191 * <li><domain> represents the domain part
1192 * of the {@link ObjectName}</li>
1193 * <li><properties> represents the list of
1194 * properties, as returned by
1195 * {@link #getKeyPropertyListString}
1196 * <li><wild> is empty if not
1197 * <code>isPropertyPattern</code>, or
1198 * is the character "<code>*</code>" if
1199 * this <code>isPropertyPattern</code>
1200 * and <properties> is empty, or
1201 * is "<code>,*</code>" if
1202 * <code>isPropertyPattern</code> and
1203 * <properties> 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>): <domain> <propertyList>
1213 * <propertyListString> <canonicalName>
1214 * <pattern> <propertyPattern>,
1215 * where: <ul>
1216 * <li><domain> represents the domain part
1217 * of the {@link ObjectName}</li>
1218 * <li><propertyList> is the
1219 * {@link Hashtable} that contains all the
1220 * pairs (key,value) for this
1221 * {@link ObjectName}</li>
1222 * <li><propertyListString> 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><canonicalName> is the
1228 * {@link String} containing this
1229 * {@link ObjectName}'s canonical name</li>
1230 * <li><pattern> is a boolean which is
1231 * <code>true</code> if this
1232 * {@link ObjectName} contains a pattern</li>
1233 * <li><propertyPattern> 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 }