KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > management > ObjectName


1 /*
2  * @(#)ObjectName.java 1.70 07/10/23
3  *
4  * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.management;
9
10
11 // java import
12
import java.io.InvalidObjectException JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.ObjectInputStream JavaDoc;
15 import java.io.ObjectOutputStream JavaDoc;
16 import java.io.ObjectStreamField JavaDoc;
17 import java.io.Serializable JavaDoc;
18 import java.security.AccessController JavaDoc;
19 import java.security.PrivilegedAction JavaDoc;
20 import java.util.Arrays JavaDoc;
21 import java.util.Enumeration JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Hashtable JavaDoc;
24
25 import com.sun.jmx.mbeanserver.GetPropertyAction;
26
27 /**
28  * <p>Represents the object name of an MBean, or a pattern that can
29  * match the names of several MBeans. Instances of this class are
30  * immutable.</p>
31  *
32  * <p>An instance of this class can
33  * be used to represent:
34  * <ul>
35  * <li> An object name
36  * <li> An object name pattern, within the context of a query
37  * </ul></p>
38  *
39  * <p>An object name consists of two parts, the domain and the key
40  * properties.</p>
41  *
42  * <p>The <em>domain</em> is a string of characters not including
43  * the character colon (<code>:</code>).</p>
44  *
45  * <p>If the domain includes at least one occurrence of the wildcard
46  * characters asterisk (<code>*</code>) or question mark
47  * (<code>?</code>), then the object name is a pattern. The asterisk
48  * matches any sequence of zero or more characters, while the question
49  * mark matches any single character.</p>
50  *
51  * <p>If the domain is empty, it will be replaced in certain contexts
52  * by the <em>default domain</em> of the MBean server in which the
53  * ObjectName is used.</p>
54  *
55  * <p>The <em>key properties</em> are an unordered set of keys and
56  * associated values.</p>
57  *
58  * <p>Each <em>key</em> is a nonempty string of characters which may
59  * not contain any of the characters comma (<code>,</code>), equals
60  * (<code>=</code>), colon, asterisk, or question mark. The same key
61  * may not occur twice in a given ObjectName.</p>
62  *
63  * <p>Each <em>value</em> associated with a key is a string of
64  * characters that is either unquoted or quoted.</p>
65  *
66  * <p>An <em>unquoted value</em> is a possibly empty string of
67  * characters which may not contain any of the characters comma,
68  * equals, colon, quote, asterisk, or question mark.</p>
69  *
70  * <p>A <em>quoted value</em> consists of a quote (<code>"</code>),
71  * followed by a possibly empty string of characters, followed by
72  * another quote. Within the string of characters, the backslash
73  * (<code>\</code>) has a special meaning. It must be followed by
74  * one of the following characters:</p>
75  *
76  * <ul>
77  * <li>Another backslash. The second backslash has no special
78  * meaning and the two characters represent a single backslash.
79  *
80  * <li>The character 'n'. The two characters represent a newline
81  * ('\n' in Java).
82  *
83  * <li>A quote. The two characters represent a quote, and that quote
84  * is not considered to terminate the quoted value. An ending closing
85  * quote must be present for the quoted value to be valid.
86  *
87  * <li>A question mark (?) or star (*). The two characters represent
88  * a question mark or star respectively.
89  * </ul>
90  *
91  * <p>A quote, question mark, or star may not appear inside a quoted
92  * value except immediately after an odd number of consecutive
93  * backslashes.</p>
94  *
95  * <p>The quotes surrounding a quoted value, and any backslashes
96  * within that value, are considered to be part of the value.</p>
97  *
98  * <p>An ObjectName may be a <em>property pattern</em>. In this case
99  * it may have zero or more keys and associated values. It matches a
100  * nonpattern ObjectName whose domain matches and that contains the
101  * same keys and associated values, as well as possibly other keys and
102  * values.</p>
103  *
104  * <p>An ObjectName is a pattern if its domain contains a wildcard or
105  * if the ObjectName is a property pattern.</p>
106  *
107  * <p>If an ObjectName is not a pattern, it must contain at least one
108  * key with its associated value.</p>
109  *
110  * <p>An ObjectName can be written as a String with the following
111  * elements in order:</p>
112  *
113  * <ul>
114  * <li>The domain.
115  * <li>A colon (<code>:</code>).
116  * <li>A key property list as defined below.
117  * </ul>
118  *
119  * <p>A key property list written as a String is a comma-separated
120  * list of elements. Each element is either an asterisk or a key
121  * property. A key property consists of a key, an equals
122  * (<code>=</code>), and the associated value.</p>
123  *
124  * <p>At most one element of a key property list may be an asterisk.
125  * If the key property list contains an asterisk element, the
126  * ObjectName is a property pattern.</p>
127  *
128  * <p>Spaces have no special significance in a String representing an
129  * ObjectName. For example, the String:
130  * <pre>
131  * domain: key1 = value1 , key2 = value2
132  * </pre>
133  * represents an ObjectName with two keys. The name of each key
134  * contains six characters, of which the first and last are spaces.
135  * The value associated with the key <code>"&nbsp;key1&nbsp;"</code>
136  * also begins and ends with a space.</p>
137  *
138  * <p>In addition to the restrictions on characters spelt out above,
139  * no part of an ObjectName may contain a newline character
140  * (<code>'\n'</code>), whether the domain, a key, or a value, whether
141  * quoted or unquoted. The newline character can be represented in a
142  * quoted value with the sequence <code>\n</code>.
143  *
144  * <p>The rules on special characters and quoting apply regardless of
145  * which constructor is used to make an ObjectName.</p>
146  *
147  * <p>To avoid collisions between MBeans supplied by different
148  * vendors, a useful convention is to begin the domain name with the
149  * reverse DNS name of the organization that specifies the MBeans,
150  * followed by a period and a string whose interpretation is
151  * determined by that organization. For example, MBeans specified by
152  * Sun Microsystems Inc., DNS name <code>sun.com</code>, would have
153  * domains such as <code>com.sun.MyDomain</code>. This is essentially
154  * the same convention as for Java-language package names.</p>
155  *
156  * @since 1.5
157  */

158 public class ObjectName implements QueryExp JavaDoc, Serializable JavaDoc {
159
160     /**
161      * A structure recording property structure and
162      * proposing minimal services
163      */

164     private final static class Property {
165
166         int _key_index;
167         int _key_length;
168         int _value_length;
169
170         /**
171          * Constructor.
172          */

173         Property(int key_index, int key_length, int value_length) {
174             _key_index = key_index;
175             _key_length = key_length;
176             _value_length = value_length;
177         }
178
179         /**
180          * Assigns the key index of property
181          */

182         void setKeyIndex(int key_index) {
183             _key_index = key_index;
184         }
185
186         /**
187          * Returns a key string for receiver key
188          */

189         String JavaDoc getKeyString(String JavaDoc name) {
190             return name.substring(_key_index, _key_index + _key_length);
191         }
192
193         /**
194          * Returns a value string for receiver key
195          */

196         String JavaDoc getValueString(String JavaDoc name) {
197             int in_begin = _key_index + _key_length + 1;
198             int out_end = in_begin + _value_length;
199             return name.substring(in_begin, out_end);
200         }
201     }
202     // Inner classes <========================================
203

204
205
206     // Private fields ---------------------------------------->
207

208
209     // Serialization compatibility stuff -------------------->
210

211     // Two serial forms are supported in this class. The selected form depends
212
// on system property "jmx.serial.form":
213
// - "1.0" for JMX 1.0
214
// - any other value for JMX 1.1 and higher
215
//
216
// Serial version for old serial form
217
private static final long oldSerialVersionUID = -5467795090068647408L;
218     //
219
// Serial version for new serial form
220
private static final long newSerialVersionUID = 1081892073854801359L;
221     //
222
// Serializable fields in old serial form
223
private static final ObjectStreamField JavaDoc[] oldSerialPersistentFields =
224     {
225     new ObjectStreamField JavaDoc("domain", String JavaDoc.class),
226     new ObjectStreamField JavaDoc("propertyList", Hashtable JavaDoc.class),
227     new ObjectStreamField JavaDoc("propertyListString", String JavaDoc.class),
228     new ObjectStreamField JavaDoc("canonicalName", String JavaDoc.class),
229     new ObjectStreamField JavaDoc("pattern", Boolean.TYPE),
230     new ObjectStreamField JavaDoc("propertyPattern", Boolean.TYPE)
231     };
232     //
233
// Serializable fields in new serial form
234
private static final ObjectStreamField JavaDoc[] newSerialPersistentFields = { };
235     //
236
// Actual serial version and serial form
237
private static final long serialVersionUID;
238     private static final ObjectStreamField JavaDoc[] serialPersistentFields;
239     private static boolean compat = false;
240     static {
241     try {
242         PrivilegedAction JavaDoc act = new GetPropertyAction("jmx.serial.form");
243         String JavaDoc form = (String JavaDoc) AccessController.doPrivileged(act);
244         compat = (form != null && form.equals("1.0"));
245     } catch (Exception JavaDoc e) {
246         // OK: exception means no compat with 1.0, too bad
247
}
248     if (compat) {
249         serialPersistentFields = oldSerialPersistentFields;
250         serialVersionUID = oldSerialVersionUID;
251     } else {
252         serialPersistentFields = newSerialPersistentFields;
253         serialVersionUID = newSerialVersionUID;
254     }
255     }
256
257     //
258
// Serialization compatibility stuff <==============================
259

260     // Class private fields ----------------------------------->
261

262     /**
263      * a shared empty array for empty property lists
264      */

265     static final private Property[] _Empty_property_array = new Property[0];
266
267     /**
268      * a shared empty hashtable for empty property lists
269      */

270     static final private Hashtable JavaDoc _EmptyPropertyList = new Hashtable JavaDoc(1);
271
272     
273     // Class private fields <==============================
274

275     // Instance private fields ----------------------------------->
276

277     /**
278      * a String containing the canonical name
279      */

280     private transient String JavaDoc _canonicalName;
281
282     
283     /**
284      * An array of properties in the same seq order as time creation
285      */

286     private transient Property[] _kp_array;
287
288     /**
289      * An array of properties in the same seq order as canonical order
290      */

291     private transient Property[] _ca_array;
292
293
294     /**
295      * The length of the domain part of built objectname
296      */

297     private transient int _domain_length = 0;
298
299
300     /**
301      * The propertyList of built object name. Initialized lazily.
302      * Table that contains all the pairs (key,value) for this ObjectName.
303      */

304     private transient Hashtable JavaDoc _propertyList;
305
306     /**
307      * boolean that declares if this ObjectName domain part is a pattern
308      */

309     private transient boolean _domain_pattern = false;
310
311     /**
312      * boolean that declares if this ObjectName contains a pattern on the
313      * key property list
314      */

315     private transient boolean _property_pattern = false;
316
317     // Instance private fields <=======================================
318

319     // Private fields <========================================
320

321
322     // Private methods ---------------------------------------->
323

324     // Category : Instance construction ------------------------->
325

326     /**
327      * Initializes this {@link ObjectName} from the given string
328      * representation.
329      *
330      * @param name A string representation of the {@link ObjectName}
331      *
332      * @exception MalformedObjectNameException The string passed as a
333      * parameter does not have the right format.
334      * @exception NullPointerException The <code>name</code> parameter
335      * is null.
336      */

337     private void construct(String JavaDoc name)
338     throws MalformedObjectNameException JavaDoc, NullPointerException JavaDoc {
339
340     // The name cannot be null
341
if (name == null)
342         throw new NullPointerException JavaDoc("name cannot be null");
343
344     // Test if the name is empty
345
if (name.length() == 0) {
346             // this is equivalent to the whole word query object name.
347
_canonicalName = "*:*";
348             _kp_array = _Empty_property_array;
349             _ca_array = _Empty_property_array;
350             _domain_length = 1;
351             _propertyList = null;
352             _domain_pattern = true;
353             _property_pattern = true;
354             return;
355         }
356
357         // initialize parsing of the string
358
char[] name_chars = name.toCharArray();
359         int len = name_chars.length;
360         char[] canonical_chars = new char[len]; // canonical form will be same
361
// length at most
362
int cname_index = 0;
363     int index = 0;
364         char c, c1;
365
366         // parses domain part
367
domain_parsing:
368         while (index < len) {
369             switch (c = name_chars[index]) {
370                 case ':' :
371                     _domain_length = index++;
372                     break domain_parsing;
373                 case '=' :
374                     int i = ++index;
375                     while ((i < len) && (name_chars[i++] != ':'))
376                     if (i == len)
377             throw new MalformedObjectNameException JavaDoc(
378                        "Domain part must be specified");
379             break;
380                 case '\n' :
381                     throw new MalformedObjectNameException JavaDoc(
382                   "Invalid character '\\n' in domain name");
383                 case '*' :
384                 case '?' :
385                     _domain_pattern = true;
386                 default :
387                     index++;
388             }
389         }
390
391         // check for non-empty properties
392
if (index == len)
393         throw new MalformedObjectNameException JavaDoc(
394                      "Key properties cannot be empty");
395
396         // we have got the domain part, begins building of _canonicalName
397
System.arraycopy(name_chars, 0, canonical_chars, 0, _domain_length);
398         canonical_chars[_domain_length] = ':';
399         cname_index = _domain_length + 1;
400
401         // parses property list
402
Property prop;
403         HashMap JavaDoc keys_map = new HashMap JavaDoc();
404         String JavaDoc[] keys;
405         String JavaDoc key_name;
406         boolean quoted_value;
407         int property_index = 0;
408         int in_index;
409         int key_index, key_length, value_index, value_length;
410
411         keys = new String JavaDoc[10];
412         _kp_array = new Property[10];
413         _property_pattern = false;
414
415         while (index < len) {
416             c = name_chars[index];
417
418             // case of pattern properties
419
if (c == '*') {
420                 if (_property_pattern)
421             throw new MalformedObjectNameException JavaDoc(
422                   "Cannot have several '*' characters in pattern " +
423                   "properties");
424                 else {
425                     _property_pattern = true;
426                     if ((++index < len ) && (name_chars[index] != ','))
427             throw new MalformedObjectNameException JavaDoc(
428                       "Invalid character found after '*': end of " +
429                   "name or ',' expected");
430                     else if (index == len) {
431                         if (property_index == 0) {
432                             // empty properties case
433
_kp_array = _Empty_property_array;
434                             _ca_array = _Empty_property_array;
435                             _propertyList = _EmptyPropertyList;
436                         }
437                         break;
438                     }
439                     else {
440                         // correct pattern spec in props, continue
441
index++;
442                         continue;
443                     }
444                 }
445             }
446
447             // standard property case, key part
448
in_index = index;
449             key_index = in_index;
450             while ((in_index < len) && ((c1 = name_chars[in_index++]) != '='))
451                 switch (c1) {
452                     // '=' considered to introduce value part
453
case '*' :
454                     case '?' :
455                     case ',' :
456                     case ':' :
457                     case '\n' :
458             final String JavaDoc ichar = ((c1=='\n')?"\\n":""+c1);
459                         throw new MalformedObjectNameException JavaDoc(
460                   "Invalid character '" + ichar +
461                   "' in key part of property");
462                     default: ;
463                 }
464             if (in_index == len)
465         throw new MalformedObjectNameException JavaDoc(
466                          "Unterminated key property part");
467             if (in_index == index)
468         throw new MalformedObjectNameException JavaDoc("Invalid key (empty)");
469             value_index = in_index; // in_index pointing after '=' char
470
key_length = value_index - key_index - 1; // found end of key
471

472             // standard property case, value part
473
if (name_chars[in_index] == '\"') {
474                 quoted_value = true;
475                 // the case of quoted value part
476
quoted_value_parsing:
477                 while ((++in_index < len) &&
478                ((c1 = name_chars[in_index]) != '\"')) {
479                     // the case of an escaped character
480
if (c1 == '\\') {
481                         if (++in_index == len)
482                 throw new MalformedObjectNameException JavaDoc(
483                            "Unterminated quoted value");
484                         switch (c1 = name_chars[in_index]) {
485                             case '\\' :
486                             case '\"' :
487                             case '?' :
488                             case '*' :
489                             case 'n' :
490                                 break; // valid character
491
default :
492                                 throw new MalformedObjectNameException JavaDoc(
493                       "Invalid escape sequence '\\" +
494                       c1 + "' in quoted value");
495                         }
496             } else if (c1 == '\n') {
497             throw new MalformedObjectNameException JavaDoc(
498                              "Newline in quoted value");
499             } else {
500                         switch (c1) {
501                             case '?' :
502                             case '*' :
503                                 throw new MalformedObjectNameException JavaDoc(
504                       "Invalid unescaped reserved character '" +
505                       c1 + "' in quoted value");
506                             default:
507                                 break;
508                         }
509                     }
510         }
511                 if (in_index == len)
512             throw new MalformedObjectNameException JavaDoc(
513                          "Unterminated quoted value");
514                 else value_length = ++in_index - value_index;
515             }
516             else {
517                 // the case of standard value part
518
quoted_value = false;
519                 while ((in_index < len) && ((c1 = name_chars[in_index]) != ','))
520                 switch (c1) {
521                     // ',' considered to be the value separator
522
case '*' :
523                     case '?' :
524                     case '=' :
525                     case ':' :
526                     case '"' :
527                     case '\n' :
528             final String JavaDoc ichar = ((c1=='\n')?"\\n":""+c1);
529                         throw new MalformedObjectNameException JavaDoc(
530                          "Invalid character '" + c1 +
531                          "' in value part of property");
532                     default : in_index++;
533                 }
534                 value_length = in_index - value_index;
535             }
536
537             // Parsed property, checks the end of name
538
if (in_index == len - 1) {
539                 if (quoted_value)
540             throw new MalformedObjectNameException JavaDoc(
541                          "Invalid ending character `" +
542                          name_chars[in_index] + "'");
543                 else throw new MalformedObjectNameException JavaDoc(
544                           "Invalid ending comma");
545             }
546             else in_index++;
547
548             // we got the key and value part, prepare a property for this
549
prop = new Property(key_index, key_length, value_length);
550             key_name = name.substring(key_index, key_index + key_length);
551
552             if (property_index == keys.length) {
553                 String JavaDoc[] tmp_string_array = new String JavaDoc[property_index + 10];
554                 System.arraycopy(keys, 0, tmp_string_array, 0, property_index);
555                 keys = tmp_string_array;
556             }
557             keys[property_index] = key_name;
558
559             addProperty(prop, property_index, keys_map, key_name);
560             property_index++;
561             index = in_index;
562         }
563
564         // computes and set canonical name
565
setCanonicalName(name_chars, canonical_chars, keys,
566              keys_map, cname_index, property_index);
567     }
568
569     /**
570      * Construct an ObjectName from a domain and a Hashtable.
571      *
572      * @param domain Domain of the ObjectName.
573      * @param props Hashtable containing couples <i>key</i> -> <i>value</i>.
574      *
575      * @exception MalformedObjectNameException The <code>domain</code>
576      * contains an illegal character, or one of the keys or values in
577      * <code>table</code> contains an illegal character, or one of the
578      * values in <code>table</code> does not follow the rules for quoting.
579      * @exception NullPointerException One of the parameters is null.
580      */

581     private void construct(String JavaDoc domain, Hashtable JavaDoc props)
582     throws MalformedObjectNameException JavaDoc, NullPointerException JavaDoc {
583
584     // The domain cannot be null
585
if (domain == null)
586         throw new NullPointerException JavaDoc("domain cannot be null");
587
588     // The key property list cannot be null
589
if (props == null)
590         throw new NullPointerException JavaDoc("key property list cannot be null");
591
592     // The key property list cannot be empty
593
if (props.isEmpty())
594         throw new MalformedObjectNameException JavaDoc(
595                      "key property list cannot be empty");
596
597         // checks domain validity
598
if (!isDomain(domain))
599             throw new MalformedObjectNameException JavaDoc("Invalid domain: " + domain);
600
601         // init canonicalname
602
final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
603         sb.append(domain).append(':');
604         _domain_length = domain.length();
605
606         // allocates the property array
607
int nb_props = props.size();
608         _kp_array = new Property[nb_props];
609
610         String JavaDoc[] keys = new String JavaDoc[nb_props];
611     final Enumeration JavaDoc e = props.keys();
612         final HashMap JavaDoc keys_map = new HashMap JavaDoc();
613         Property prop;
614         int key_index;
615     for (int i = 0; e.hasMoreElements(); i++ ) {
616             if (i > 0) sb.append(",");
617         String JavaDoc key = "";
618         try {
619         key = (String JavaDoc)e.nextElement();
620         } catch (Exception JavaDoc x) {
621         throw new MalformedObjectNameException JavaDoc("Invalid key `" +
622                                key + "'");
623         }
624         String JavaDoc value = "";
625         try {
626         value = (String JavaDoc)props.get(key);
627         } catch (Exception JavaDoc x) {
628         throw new MalformedObjectNameException JavaDoc("Invalid value `" +
629                                value + "'");
630         }
631         key_index = sb.length();
632             checkKey(key);
633             sb.append(key);
634             keys[i] = key;
635             sb.append("=");
636         checkValue(value);
637             sb.append(value);
638             prop = new Property(key_index, key.length(), value.length());
639         addProperty(prop, i, keys_map, key);
640     }
641
642         // initialise canonical name and data structure
643
int len = sb.length();
644         char[] initial_chars = new char[len];
645         sb.getChars(0, len, initial_chars, 0);
646         char[] canonical_chars = new char[len];
647         System.arraycopy(initial_chars, 0, canonical_chars, 0,
648              _domain_length + 1);
649         setCanonicalName(initial_chars, canonical_chars, keys, keys_map,
650              _domain_length + 1, _kp_array.length);
651     }
652     // Category : Instance construction <==============================
653

654     // Category : Internal utilities ------------------------------>
655

656     /**
657      * Add passed property to the list at the given index
658      * for the passed key name
659      */

660     private void addProperty(Property prop, int index,
661                  HashMap JavaDoc keys_map, String JavaDoc key_name)
662     throws MalformedObjectNameException JavaDoc {
663
664         if (keys_map.containsKey(key_name)) throw new
665                 MalformedObjectNameException JavaDoc("key `" +
666                      key_name +"' already defined");
667             
668         // if no more space for property arrays, have to increase it
669
if (index == _kp_array.length) {
670             Property[] tmp_prop_array = new Property[index + 10];
671             System.arraycopy(_kp_array, 0, tmp_prop_array, 0, index);
672             _kp_array = tmp_prop_array;
673         }
674         _kp_array[index] = prop;
675         keys_map.put(key_name, prop);
676     }
677         
678     /**
679      * Sets the canonical name of receiver from input 'specified_chars'
680      * array, by filling 'canonical_chars' array with found 'nb-props'
681      * properties starting at position 'prop_index'.
682      */

683     private void setCanonicalName(char[] specified_chars,
684                                   char[] canonical_chars,
685                                   String JavaDoc[] keys, HashMap JavaDoc keys_map,
686                                   int prop_index, int nb_props) {
687
688         // Sort the list of found properties
689
if (_kp_array != _Empty_property_array) {
690             String JavaDoc[] tmp_keys = new String JavaDoc[nb_props];
691             Property[] tmp_props = new Property[nb_props];
692
693             System.arraycopy(keys, 0, tmp_keys, 0, nb_props);
694             Arrays.sort(tmp_keys);
695             keys = tmp_keys;
696             System.arraycopy(_kp_array, 0, tmp_props, 0 , nb_props);
697             _kp_array = tmp_props;
698             _ca_array = new Property[nb_props];
699
700             // now assigns _ca_array to the sorted list of keys
701
// (there cannot be two identical keys in an objectname.
702
for (int i = 0; i < nb_props; i++)
703                 _ca_array[i] = (Property) keys_map.get(keys[i]);
704
705             // now we build the canonical name and set begin indexes of
706
// properties to reflect canonical form
707
int last_index = nb_props - 1;
708             int prop_len;
709             Property prop;
710             for (int i = 0; i <= last_index; i++) {
711                 prop = _ca_array[i];
712         // length of prop including '=' char
713
prop_len = prop._key_length + prop._value_length + 1;
714                 System.arraycopy(specified_chars, prop._key_index,
715                  canonical_chars, prop_index, prop_len);
716                 prop.setKeyIndex(prop_index);
717                 prop_index += prop_len;
718                 if (i != last_index) {
719                     canonical_chars[prop_index] = ',';
720                     prop_index++;
721                 }
722             }
723         }
724         
725         // terminate canonicalname with '*' in case of pattern
726
if (_property_pattern) {
727             if (_kp_array != _Empty_property_array)
728         canonical_chars[prop_index++] = ',';
729             canonical_chars[prop_index++] = '*';
730         }
731
732         // we now build the canonicalname string
733
_canonicalName = (new String JavaDoc(canonical_chars, 0, prop_index)).intern();
734     }
735
736     /**
737      * Parse a key.
738      * <pre>final int endKey=parseKey(s,startKey);</pre>
739      * <p>key starts at startKey (included), and ends at endKey (excluded).
740      * If (startKey == endKey), then the key is empty.
741      *
742      * @param s The char array of the original string.
743      * @param startKey index at which to begin parsing.
744      * @return The index following the last character of the key.
745      **/

746     private final static int parseKey(final char[] s, final int startKey)
747     throws MalformedObjectNameException JavaDoc {
748     int next = startKey;
749     int endKey = startKey;
750     final int len = s.length;
751     while (next < len) {
752         final char k = s[next++];
753         switch (k) {
754         case '*':
755         case '?':
756         case ',':
757         case ':':
758         case '\n':
759         final String JavaDoc ichar = ((k=='\n')?"\\n":""+k);
760         throw new
761             MalformedObjectNameException JavaDoc("Invalid character in key: `"
762                          + ichar + "'");
763         case '=':
764         // we got the key.
765
endKey = next-1;
766         break;
767         default:
768         if (next < len) continue;
769         else endKey=next;
770         }
771         break;
772     }
773     return endKey;
774     }
775
776     /**
777      * Parse a value.
778      * <pre>final int endVal=parseValue(s,startVal);</pre>
779      * <p>value starts at startVal (included), and ends at endVal (excluded).
780      * If (startVal == endVal), then the key is empty.
781      *
782      * @param s The char array of the original string.
783      * @param startValue index at which to begin parsing.
784      * @return The index following the last character of the value.
785      **/

786     private final static int parseValue(final char[] s, final int startValue)
787     throws MalformedObjectNameException JavaDoc {
788
789     int next = startValue;
790     int endValue = startValue;
791
792     final int len = s.length;
793     final char q=s[startValue];
794
795     if (q == '"') {
796         // quoted value
797
if (++next == len) throw new
798        &n