KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > management > modelmbean > DescriptorSupport


1 /*
2  * @(#)file DescriptorSupport.java
3  * @(#)author IBM Corp.
4  * @(#)version 1.54
5  * @(#)lastedit 07/07/24
6  */

7 /*
8  * Copyright IBM Corp. 1999-2000. All rights reserved.
9  *
10  * The program is provided "as is" without any warranty express or implied,
11  * including the warranty of non-infringement and the implied warranties of
12  * merchantibility and fitness for a particular purpose. IBM will not be
13  * liable for any damages suffered by you or any third party claim against
14  * you regarding the Program.
15  *
16  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
17  * This software is the proprietary information of Sun Microsystems, Inc.
18  * Use is subject to license terms.
19  *
20  * Copyright 2005 Sun Microsystems, Inc. Tous droits reserves.
21  * Ce logiciel est propriete de Sun Microsystems, Inc.
22  * Distribue par des licences qui en restreignent l'utilisation.
23  *
24  */

25
26 package javax.management.modelmbean;
27
28 import java.io.IOException JavaDoc;
29 import java.io.ObjectInputStream JavaDoc;
30 import java.io.ObjectOutputStream JavaDoc;
31 import java.io.ObjectStreamField JavaDoc;
32
33 import java.lang.reflect.Constructor JavaDoc;
34
35 import java.security.AccessController JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.Map JavaDoc;
39 import java.util.Set JavaDoc;
40 import java.util.StringTokenizer JavaDoc;
41
42 import javax.management.RuntimeOperationsException JavaDoc;
43 import javax.management.MBeanException JavaDoc;
44
45 import com.sun.jmx.mbeanserver.GetPropertyAction;
46
47 import com.sun.jmx.trace.Trace;
48 import java.util.Collections JavaDoc;
49 import java.util.SortedMap JavaDoc;
50 import java.util.TreeMap JavaDoc;
51
52 import sun.reflect.misc.ReflectUtil;
53
54 /**
55  * This class represents the metadata set for a ModelMBean element. A
56  * descriptor is part of the ModelMBeanInfo,
57  * ModelMBeanNotificationInfo, ModelMBeanAttributeInfo,
58  * ModelMBeanConstructorInfo, and ModelMBeanParameterInfo.
59  * <P>
60  * A descriptor consists of a collection of fields. Each field is in
61  * fieldname=fieldvalue format. Field names are not case sensitive,
62  * case will be preserved on field values.
63  * <P>
64  * All field names and values are not predefined. New fields can be
65  * defined and added by any program. Some fields have been predefined
66  * for consistency of implementation and support by the
67  * ModelMBeanInfo, ModelMBeanAttributeInfo, ModelMBeanConstructorInfo,
68  * ModelMBeanNotificationInfo, ModelMBeanOperationInfo and ModelMBean
69  * classes.
70  *
71  * @since 1.5
72  */

73
74 public class DescriptorSupport
75      implements javax.management.Descriptor JavaDoc
76 {
77
78     // Serialization compatibility stuff:
79
// Two serial forms are supported in this class. The selected form depends
80
// on system property "jmx.serial.form":
81
// - "1.0" for JMX 1.0
82
// - any other value for JMX 1.1 and higher
83
//
84
// Serial version for old serial form
85
private static final long oldSerialVersionUID = 8071560848919417985L;
86     //
87
// Serial version for new serial form
88
private static final long newSerialVersionUID = -6292969195866300415L;
89     //
90
// Serializable fields in old serial form
91
private static final ObjectStreamField JavaDoc[] oldSerialPersistentFields =
92     {
93       new ObjectStreamField JavaDoc("descriptor", HashMap JavaDoc.class),
94       new ObjectStreamField JavaDoc("currClass", String JavaDoc.class)
95     };
96     //
97
// Serializable fields in new serial form
98
private static final ObjectStreamField JavaDoc[] newSerialPersistentFields =
99     {
100       new ObjectStreamField JavaDoc("descriptor", HashMap JavaDoc.class)
101     };
102     //
103
// Actual serial version and serial form
104
private static final long serialVersionUID;
105     /**
106      * @serialField descriptor HashMap The collection of fields representing this descriptor
107      */

108     private static final ObjectStreamField JavaDoc[] serialPersistentFields;
109     private static final String JavaDoc serialForm;
110     static {
111     String JavaDoc form = null;
112     boolean compat = false;
113     try {
114         GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
115         form = (String JavaDoc) AccessController.doPrivileged(act);
116         compat = "1.0".equals(form); // form may be null
117
} catch (Exception JavaDoc e) {
118         // OK: No compat with 1.0
119
}
120     serialForm = form;
121     if (compat) {
122         serialPersistentFields = oldSerialPersistentFields;
123         serialVersionUID = oldSerialVersionUID;
124     } else {
125         serialPersistentFields = newSerialPersistentFields;
126         serialVersionUID = newSerialVersionUID;
127     }
128     }
129     //
130
// END Serialization compatibility stuff
131

132     /* Spec says that field names are case-insensitive, but that case
133        is preserved. This means that we need to be able to map from a
134        name that may differ in case to the actual name that is used in
135        the HashMap. Thus, descriptorMap is a TreeMap with a Comparator
136        that ignores case.
137
138        Previous versions of this class had a field called "descriptor"
139        of type HashMap where the keys were directly Strings. This is
140        hard to reconcile with the required semantics, so we fabricate
141        that field virtually during serialization and deserialization
142        but keep the real information in descriptorMap.
143     */

144     private transient SortedMap JavaDoc<String JavaDoc, Object JavaDoc> descriptorMap;
145
146     private static final int DEFAULT_SIZE = 20;
147     private static final String JavaDoc currClass = "DescriptorSupport";
148
149
150     /**
151      * Descriptor default constructor.
152      * Default initial descriptor size is 20. It will grow as needed.<br>
153      * Note that the created empty descriptor is not a valid descriptor
154      * (the method {@link #isValid isValid} returns <CODE>false</CODE>)
155      */

156     public DescriptorSupport() {
157         if (tracing())
158             trace("DescriptorSupport()", "Constructor");
159         init(null);
160     }
161
162     /**
163      * Descriptor constructor. Takes as parameter the initial
164      * capacity of the Map that stores the descriptor fields.
165      * Capacity will grow as needed.<br> Note that the created empty
166      * descriptor is not a valid descriptor (the method {@link
167      * #isValid isValid} returns <CODE>false</CODE>).
168      *
169      * @param initNumFields The initial capacity of the Map that
170      * stores the descriptor fields.
171      *
172      * @exception RuntimeOperationsException for illegal value for
173      * initNumFields (&lt;= 0)
174      * @exception MBeanException Wraps a distributed communication Exception.
175      */

176     public DescriptorSupport(int initNumFields)
177         throws MBeanException JavaDoc, RuntimeOperationsException JavaDoc {
178         if (tracing()) {
179             trace("Descriptor(initNumFields=" + initNumFields + ")",
180                   "Constructor");
181         }
182     if (initNumFields <= 0) {
183         if (tracing()) {
184         trace("Descriptor(maxNumFields)",
185               "Illegal arguments: initNumFields <= 0");
186         }
187         final String JavaDoc msg =
188         "Descriptor field limit invalid: " + initNumFields;
189         final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
190         throw new RuntimeOperationsException JavaDoc(iae, msg);
191     }
192         init(null);
193     }
194
195     /**
196      * Descriptor constructor taking a Descriptor as parameter.
197      * Creates a new descriptor initialized to the values of the
198      * descriptor passed in parameter.
199      *
200      * @param inDescr the descriptor to be used to initialize the
201      * constructed descriptor. If it is null or contains no descriptor
202      * fields, an empty Descriptor will be created.
203      */

204     public DescriptorSupport(DescriptorSupport JavaDoc inDescr) {
205     if (tracing()) {
206         trace("Descriptor(Descriptor)","Constructor");
207     }
208     if (inDescr == null)
209             init(null);
210         else
211             init(inDescr.descriptorMap);
212     }
213
214
215     /**
216      * <p>Descriptor constructor taking an XML String.</p>
217      *
218      * <p>The format of the XML string is not defined, but an
219      * implementation must ensure that the string returned by
220      * {@link #toXMLString() toXMLString()} on an existing
221      * descriptor can be used to instantiate an equivalent
222      * descriptor using this constructor.</p>
223      *
224      * <p>In this implementation, all field values will be created
225      * as Strings. If the field values are not Strings, the
226      * programmer will have to reset or convert these fields
227      * correctly.</p>
228      *
229      * @param inStr An XML-formatted string used to populate this
230      * Descriptor. The format is not defined, but any
231      * implementation must ensure that the string returned by
232      * method {@link #toXMLString toXMLString} on an existing
233      * descriptor can be used to instantiate an equivalent
234      * descriptor when instantiated using this constructor.
235      *
236      * @exception RuntimeOperationsException If the String inStr
237      * passed in parameter is null
238      * @exception XMLParseException XML parsing problem while parsing
239      * the input String
240      * @exception MBeanException Wraps a distributed communication Exception.
241      */

242     /* At some stage we should rewrite this code to be cleverer. Using
243        a StringTokenizer as we do means, first, that we accept a lot of
244        bogus strings without noticing they are bogus, and second, that we
245        split the string being parsed at characters like > even if they
246        occur in the middle of a field value. */

247     public DescriptorSupport(String JavaDoc inStr)
248         throws MBeanException JavaDoc, RuntimeOperationsException JavaDoc,
249            XMLParseException JavaDoc {
250     /* parse an XML-formatted string and populate internal
251      * structure with it */

252     if (tracing()) {
253         trace("Descriptor(String ='" + inStr + "')","Constructor");
254     }
255     if (inStr == null) {
256         if (tracing()) {
257         trace("Descriptor(String = null)","Illegal arguments");
258         }
259         final String JavaDoc msg = "String in parameter is null";
260         final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
261         throw new RuntimeOperationsException JavaDoc(iae, msg);
262     }
263
264     final String JavaDoc lowerInStr = inStr.toLowerCase();
265     if (!lowerInStr.startsWith("<descriptor>")
266         || !lowerInStr.endsWith("</descriptor>")) {
267         throw new XMLParseException JavaDoc("No <descriptor>, </descriptor> pair");
268     }
269
270     // parse xmlstring into structures
271
init(null);
272     // create dummy descriptor: should have same size
273
// as number of fields in xmlstring
274
// loop through structures and put them in descriptor
275

276     StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(inStr, "<> \t\n\r\f");
277
278     boolean inFld = false;
279     boolean inDesc = false;
280     String JavaDoc fieldName = null;
281     String JavaDoc fieldValue = null;
282
283
284     while (st.hasMoreTokens()) { // loop through tokens
285
String JavaDoc tok = st.nextToken();
286
287         if (tok.equalsIgnoreCase("FIELD")) {
288         inFld = true;
289         } else if (tok.equalsIgnoreCase("/FIELD")) {
290         if ((fieldName != null) && (fieldValue != null)) {
291             fieldName =
292             fieldName.substring(fieldName.indexOf('"') + 1,
293                         fieldName.lastIndexOf('"'));
294             final Object JavaDoc fieldValueObject =
295             parseQuotedFieldValue(fieldValue);
296             setField(fieldName, fieldValueObject);
297         }
298         fieldName = null;
299         fieldValue = null;
300         inFld = false;
301         } else if (tok.equalsIgnoreCase("DESCRIPTOR")) {
302         inDesc = true;
303         } else if (tok.equalsIgnoreCase("/DESCRIPTOR")) {
304         inDesc = false;
305         fieldName = null;
306         fieldValue = null;
307         inFld = false;
308         } else if (inFld && inDesc) {
309         // want kw=value, eg, name="myname" value="myvalue"
310
int eq_separator = tok.indexOf("=");
311         if (eq_separator > 0) {
312             String JavaDoc kwPart = tok.substring(0,eq_separator);
313             String JavaDoc valPart = tok.substring(eq_separator+1);
314             if (kwPart.equalsIgnoreCase("NAME"))
315             fieldName = valPart;
316             else if (kwPart.equalsIgnoreCase("VALUE"))
317             fieldValue = valPart;
318             else { // xml parse exception
319
final String JavaDoc msg =
320                 "Expected `name' or `value', got `" + tok + "'";
321             throw new XMLParseException JavaDoc(msg);
322             }
323         } else { // xml parse exception
324
final String JavaDoc msg =
325             "Expected `keyword=value', got `" + tok + "'";
326             throw new XMLParseException JavaDoc(msg);
327         }
328         }
329     } // while tokens
330

331     if (tracing()) {
332         trace("Descriptor(XMLString)","Exit");
333     }
334     }
335
336     /**
337      * Constructor taking field names and field values. The array and
338      * array elements cannot be null.
339      *
340      * @param fieldNames String array of field names. No elements of
341      * this array can be null.
342      * @param fieldValues Object array of the corresponding field
343      * values. Elements of the array can be null. The
344      * <code>fieldValue</code> must be valid for the
345      * <code>fieldName</code> (as defined in method {@link #isValid
346      * isValid})
347      *
348      * <p>Note: array sizes of parameters should match. If both arrays
349      * are null or empty, then an empty descriptor is created.</p>
350      *
351      * @exception RuntimeOperationsException for illegal value for
352      * field Names or field Values. The array lengths must be equal.
353      * If the descriptor construction fails for any reason, this
354      * exception will be thrown.
355      *
356      */

357     public DescriptorSupport(String JavaDoc[] fieldNames, Object JavaDoc[] fieldValues)
358         throws RuntimeOperationsException JavaDoc {
359     if (tracing()) {
360         trace("Descriptor(fieldNames, fieldObjects)","Constructor");
361     }
362
363     if ((fieldNames == null) || (fieldValues == null) ||
364         (fieldNames.length != fieldValues.length)) {
365         if (tracing()) {
366         trace("Descriptor(String[],Object[])","Illegal arguments");
367         }
368
369         final String JavaDoc msg =
370         "Null or invalid fieldNames or fieldValues";
371         final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
372         throw new RuntimeOperationsException JavaDoc(iae, msg);
373     }
374
375     /* populate internal structure with fields */
376         init(null);
377     for (int i=0; i < fieldNames.length; i++) {
378         // setField will throw an exception if a fieldName is be null.
379
// the fieldName and fieldValue will be validated in setField.
380
setField(fieldNames[i], fieldValues[i]);
381     }
382     if (tracing()) {
383         trace("Descriptor(fieldNames, fieldObjects)","Exit");
384     }
385     }
386
387     /**
388      * Constructor taking fields in the <i>fieldName=fieldValue</i>
389      * format.
390      *
391      * @param fields String array with each element containing a
392      * field name and value. If this array is null or empty, then the
393      * default constructor will be executed. Null strings or empty
394      * strings will be ignored.
395      *
396      * <p>All field values should be Strings. If the field values are
397      * not Strings, the programmer will have to reset or convert these
398      * fields correctly.
399      *
400      * <p>Note: Each string should be of the form
401      * <i>fieldName=fieldValue</i>.
402      *
403      * @exception RuntimeOperationsException for illegal value for
404      * field Names or field Values. The field must contain an
405      * "=". "=fieldValue", "fieldName", and "fieldValue" are illegal.
406      * FieldName cannot be null. "fieldName=" will cause the value to
407      * be null. If the descriptor construction fails for any reason,
408      * this exception will be thrown.
409      *
410      */

411     public DescriptorSupport(String JavaDoc[] fields)
412     {
413     if (tracing()) {
414         trace("Descriptor(fields)","Constructor");
415     }
416         init(null);
417     if (( fields == null ) || ( fields.length == 0))
418             return;
419
420         init(null);
421
422     for (int i=0; i < fields.length; i++) {
423         if ((fields[i] == null) || (fields[i].equals(""))) {
424         continue;
425         }
426         int eq_separator = fields[i].indexOf("=");
427         if (eq_separator < 0) {
428         // illegal if no = or is first character
429
if (tracing()) {
430             trace("Descriptor(String[])",
431               "Illegal arguments: field does not have '=' " +
432               "as a name and value separator");
433         }
434         final String JavaDoc msg = "Field in invalid format: no equals sign";
435         final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
436         throw new RuntimeOperationsException JavaDoc(iae, msg);
437         }
438
439         String JavaDoc fieldName = fields[i].substring(0,eq_separator);
440         String JavaDoc fieldValue = null;
441         if (eq_separator < fields[i].length()) {
442         // = is not in last character
443
fieldValue = fields[i].substring(eq_separator+1);
444         }
445
446         if (fieldName.equals("")) {
447         if (tracing()) {
448             trace("Descriptor(String[])",
449               "Illegal arguments: fieldName is empty");
450         }
451
452         final String JavaDoc msg = "Field in invalid format: no fieldName";
453         final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
454         throw new RuntimeOperationsException JavaDoc(iae, msg);
455         }
456
457         setField(fieldName,fieldValue);
458     }
459     if (tracing()) {
460         trace("Descriptor(fields)","Exit");
461     }
462     }
463     
464     private void init(Map JavaDoc<String JavaDoc, ?> initMap) {
465         descriptorMap =
466                 new TreeMap JavaDoc<String JavaDoc, Object JavaDoc>(String.CASE_INSENSITIVE_ORDER);
467         if (initMap != null)
468             descriptorMap.putAll(initMap);
469     }
470
471     // Implementation of the Descriptor interface
472

473
474     /**
475      * Returns the value for a specific fieldname.
476      *
477      * @param inFieldName The field name in question; if not found,
478      * null is returned.
479      *
480      * @return An Object representing the field value
481      *
482      * @exception RuntimeOperationsException for illegal value (null
483      * or empty string) for field Names.
484      */

485     public synchronized Object JavaDoc getFieldValue(String JavaDoc inFieldName)
486         throws RuntimeOperationsException JavaDoc {
487
488     if ((inFieldName == null) || (inFieldName.equals(""))) {
489         if (tracing()) {
490         trace("getField()","Illegal arguments: null field name.");
491         }
492         final String JavaDoc msg = "Fieldname requested is null";
493         final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
494         throw new RuntimeOperationsException JavaDoc(iae, msg);
495     }
496     Object JavaDoc retValue = descriptorMap.get(inFieldName);
497     if (tracing()) {
498         trace("getField(" + inFieldName + ")",
499           "Returns '" + retValue + "'");
500     }
501     return(retValue);
502     }
503
504     /**
505      * Sets the string value for a specific fieldname. The value
506      * must be valid for the field (as defined in method {@link
507      * #isValid isValid}). If the field does not exist, it is
508      * added to the Descriptor. If it does exist, the
509      * value is replaced.
510      *
511      * @param inFieldName The field name to be set. Must
512      * not be null or empty string.
513      * @param fieldValue The field value to be set for the field
514      * name. Can be null or empty string.
515      *
516      * @exception RuntimeOperationsException for illegal value for
517      * field Names.
518      *
519      */

520     public synchronized void setField(String JavaDoc inFieldName, Object JavaDoc fieldValue)
521         throws RuntimeOperationsException JavaDoc {
522
523     // field name cannot be null or empty
524
if ((inFieldName == null) || (inFieldName.equals(""))) {
525         if (tracing()) {
526         trace("setField(String,String)",
527               "Illegal arguments: null or empty field name");
528         }
529
530         final String JavaDoc msg = "Fieldname to be set is null or empty";
531         final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
532         throw new RuntimeOperationsException JavaDoc(iae, msg);
533     }
534
535     if (!validateField(inFieldName, fieldValue)) {
536         if (tracing()) {
537         trace("setField(fieldName,FieldValue)","Illegal arguments");
538         }
539
540         final String JavaDoc msg =
541         "Field value invalid: " + inFieldName + "=" + fieldValue;
542         final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
543         throw new RuntimeOperationsException JavaDoc(iae, msg);
544     }
545
546     if (tracing()) {
547         if (fieldValue != null) {
548         trace("setField(fieldName, fieldValue)",
549               "Entry: setting '" + inFieldName + "' to '" +
550               fieldValue + "'.");
551         }
552     }
553
554         // Since we do not remove any existing entry with this name,
555
// the field will preserve whatever case it had, ignoring
556
// any difference there might be in inFieldName.
557
descriptorMap.put(inFieldName, fieldValue);
558     }
559
560     /**
561      * Returns all the fields in the descriptor. The order is not the
562      * order in which the fields were set.
563      *
564      * @return String array of fields in the format
565      * <i>fieldName=fieldValue</i>. If there are no fields in the
566      * descriptor, then an empty String array is returned. If a
567      * fieldValue is not a String then the toString() method is called
568      * on it and its returned value is used as the value for the field
569      * enclosed in parenthesis.
570      *
571      * @see #setFields
572      */

573     public synchronized String JavaDoc[] getFields() {
574     if (tracing()) {
575         trace("getFields()","Entry");
576     }
577     int numberOfEntries = descriptorMap.size();
578
579     String JavaDoc[] responseFields = new String JavaDoc[numberOfEntries];
580     Set JavaDoc returnedSet = descriptorMap.entrySet();
581
582     int i = 0;
583     Object JavaDoc currValue = null;
584     Map.Entry JavaDoc currElement = null;
585
586     if (tracing()) {
587         trace("getFields()","Returning " + numberOfEntries + " fields");
588     }
589     for (Iterator JavaDoc iter = returnedSet.iterator(); iter.hasNext(); i++) {
590         currElement = (Map.Entry JavaDoc) iter.next();
591
592         if (currElement == null) {
593         if (tracing()) {
594             trace("getFields()","Element is null");
595         }
596         } else {
597         currValue = currElement.getValue();
598         if (currValue == null) {
599             responseFields[i] = currElement.getKey() + "=";
600         } else {
601             if (currValue instanceof java.lang.String JavaDoc) {
602             responseFields[i] =
603                 currElement.getKey() + "=" + currValue.toString();
604             } else {
605             responseFields[i] =
606                 currElement.getKey() + "=(" +
607                 currValue.toString() + ")";
608             }
609         }
610         }
611     }
612
613     if (tracing()) {
614         trace("getFields()","Exit");
615     }
616
617     return responseFields;
618     }
619
620     /**
621      * Returns all the fields names in the descriptor. The order is
622      * not the order in which the fields were set.
623      *
624      * @return String array of fields names. If the descriptor is
625      * empty, you will get an empty array.
626      *
627      */

628     public synchronized String JavaDoc[] getFieldNames() {
629     if (tracing()) {
630         trace("getFieldNames()","Entry");
631     }
632     int numberOfEntries = descriptorMap.size();
633
634     String JavaDoc[] responseFields = new String JavaDoc[numberOfEntries];
635     Set JavaDoc returnedSet = descriptorMap.entrySet();
636
637     int i = 0;
638
639     if (tracing()) {
640         trace("getFieldNames()","Returning " + numberOfEntries + " fields");
641     }
642
643     for (Iterator JavaDoc iter = returnedSet.iterator(); iter.hasNext(); i++) {
644         Map.Entry JavaDoc currElement = (Map.Entry JavaDoc) iter.next();
645
646         if (( currElement == null ) || (currElement.getKey() == null)) {
647         if (tracing()) {
648             trace("getFieldNames()","Field is null");
649         }
650         } else {
651         responseFields[i] = currElement.getKey().toString();
652         }
653     }
654
655     if (tracing()) {
656         trace("getFieldNames()","Exit");
657     }
658
659     return responseFields;
660     }
661
662
663     /**
664      * Returns all the field values in the descriptor as an array of
665      * Objects. The returned values are in the same order as the
666      * fieldNames String array parameter.
667      *
668      * @param fieldNames String array of the names of the fields that
669      * the values should be returned for.<br>
670      * If the array is empty then an empty array will be returned.<br>
671      * If the array is 'null' then all values will be returned. The
672      * order is not the order in which the fields were set.<br>
673      * If a field name in the array does not exist, then null is
674      * returned for the matching array element being returned.
675      *
676      * @return Object array of field values. If the descriptor is
677      * empty, you will get an empty array.
678      */

679     public synchronized Object JavaDoc[] getFieldValues(String JavaDoc[] fieldNames) {
680     if (tracing()) {
681         trace("getFieldValues(fieldNames)","Entry");
682     }
683     // if fieldNames == null return all values
684
// if fieldNames is String[0] return no values
685

686     int numberOfEntries = descriptorMap.size();
687
688     /* Following test is somewhat inconsistent but is called for
689        by the @return clause above. */

690     if (numberOfEntries == 0)
691         return new Object JavaDoc[0];
692
693     Object JavaDoc[] responseFields;
694     if (fieldNames != null) {
695         responseFields = new Object JavaDoc[fieldNames.length];
696         // room for selected
697
} else {
698         responseFields = new Object JavaDoc[numberOfEntries];
699         // room for all
700
}
701
702     int i = 0;
703
704     if (tracing()) {
705         trace("getFieldValues()",
706           "Returning " + numberOfEntries + " fields");
707     }
708
709     if (fieldNames == null) {
710         for (Iterator JavaDoc iter = descriptorMap.values().iterator();
711          iter.hasNext(); i++)
712         responseFields[i] = iter.next();
713     } else {
714         for (i=0; i < fieldNames.length; i++) {
715         if ((fieldNames[i] == null) || (fieldNames[i].equals(""))) {
716             responseFields[i] = null;
717         } else {
718             responseFields[i] = getFieldValue(fieldNames[i]);
719         }
720         }
721     }
722
723
724     if (tracing()) {
725         trace("getFieldValues()","Exit");
726     }
727
728     return responseFields;
729     }
730
731     /**
732      * Sets all Fields in the list to the new value with the same
733      * index in the fieldValue array. Array sizes must match. The
734      * field value will be validated before it is set (by calling the
735      * method {@link #isValid isValid}). If it is not valid, then an
736      * exception will be thrown. If the arrays are empty, then no
737      * change will take effect.
738      *
739      * @param fieldNames String array of field names. The array and
740      * array elements cannot be null.
741      * @param fieldValues Object array of the corresponding field
742      * values. The array cannot be null. Elements of the array can
743      * be null.
744      *
745      * @exception RuntimeOperationsException for illegal value for
746      * field Names or field Values. Neither can be null. The array
747      * lengths must be equal.
748      *
749      * @see #getFields
750      */

751     public synchronized void setFields(String JavaDoc[] fieldNames,
752                        Object JavaDoc[] fieldValues)
753         throws RuntimeOperationsException JavaDoc {
754
755     if (tracing()) {
756         trace("setFields(fieldNames, ObjectValues)","Entry");
757     }
758
759
760     if ((fieldNames == null) || (fieldValues == null) ||
761         (fieldNames.length != fieldValues.length)) {
762         if (tracing()) {
763         trace("Descriptor.setFields(String[],Object[])",
764               "Illegal arguments");
765         }
766
767         final String JavaDoc msg = "FieldNames and FieldValues are null or invalid";
768         final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
769         throw new RuntimeOperationsException JavaDoc(iae, msg);
770     }
771
772     for (int i=0; i < fieldNames.length; i++) {
773         if (( fieldNames[i] == null) || (fieldNames[i].equals(""))) {
774         if (tracing()) {
775             trace("Descriptor.setFields(String[],Object[])",
776               "Null field name encountered at " + i + " element");
777         }
778
779         final String JavaDoc msg = "FieldNames is null or invalid";
780         final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
781         throw new RuntimeOperationsException JavaDoc(iae, msg);
782         }
783         setField(fieldNames[i], fieldValues[i]);
784     }
785     if (tracing()) {
786         trace("Descriptor.setFields(fieldNames, fieldObjects)","Exit");
787     }
788     }
789
790     /**
791      * Returns a new Descriptor which is a duplicate of the Descriptor.
792      *
793      * @exception RuntimeOperationsException for illegal value for
794      * field Names or field Values. If the descriptor construction
795      * fails for any reason, this exception will be thrown.
796      */

797
798     public synchronized Object JavaDoc clone() throws RuntimeOperationsException JavaDoc {
799     if (tracing()) {
800         trace("Descriptor.clone()","Executed");
801     }
802     return(new DescriptorSupport JavaDoc(this));
803     }
804
805     /**
806      * Removes a field from the descriptor.
807      *
808      * @param fieldName String name of the field to be removed.
809      * If the field is not found no exception is thrown.
810      */

811     public synchronized void removeField(String JavaDoc fieldName) {
812     if ((fieldName == null) || (fieldName.equals(""))) {
813         return;
814     }
815
816     descriptorMap.remove(fieldName);
817     }
818
819
820     /**
821      * Returns true if all of the fields have legal values given their
822      * names.
823      * <P>
824      * This implementation does not support interoperating with a directory
825      * or lookup service. Thus, conforming to the specification, no checking is
826      * done on the <i>"export"</i> field.
827      * <P>
828      * Otherwise this implementation returns false if:
829      * <P>
830      * <UL>
831      * <LI> name and descriptorType fieldNames are not defined, or
832      * null, or empty, or not String
833      * <LI> class, role, getMethod, setMethod fieldNames, if defined,
834      * are null or not String
835      * <LI> persistPeriod, currencyTimeLimit, lastUpdatedTimeStamp,
836      * lastReturnedTimeStamp if defined, are null, or not a Numeric
837      * String or not a Numeric Value >= -1
838      * <LI> log fieldName, if defined, is null, or not a Boolean or
839      * not a String with value "t", "f", "true", "false". These String
840      * values must not be case sensitive.
841      * <LI> visibility fieldName, if defined, is null, or not a
842      * Numeric String or a not Numeric Value >= 1 and <= 4
843      * <LI> severity fieldName, if defined, is null, or not a Numeric
844      * String or not a Numeric Value >= 0 and <= 6<br>
845      * <LI> persistPolicy fieldName, if defined, is null, or not a
846      * following String :<br>
847      * "OnUpdate", "OnTimer", "NoMoreOftenThan", "Always",
848      * "Never". These String values must not be case sensitive.<br>
849      * </UL>
850      *
851      * @exception RuntimeOperationsException If the validity checking
852      * fails for any reason, this exception will be thrown.
853      */

854
855     public synchronized boolean isValid() throws RuntimeOperationsException JavaDoc {
856     if (tracing()) {
857         trace("Descriptor.isValid()","Executed");
858     }
859     // verify that the descriptor is valid, by iterating over each field...
860

861     Set JavaDoc returnedSet = descriptorMap.entrySet();
862
863     if (returnedSet == null) { // null descriptor, not valid
864
if (tracing()) {
865         trace("Descriptor.isValid()","returns false (null set)");
866         }
867         return false;
868     }
869     // must have a name and descriptor type field
870
String JavaDoc thisName = (String JavaDoc)(this.getFieldValue("name"));
871     String JavaDoc thisDescType = (String JavaDoc)(getFieldValue("descriptorType"));
872
873     if ((thisName == null) || (thisDescType == null) ||
874         (thisName.equals("")) || (thisDescType.equals(""))) {
875         return false;
876     }
877
878     // According to the descriptor type we validate the fields contained
879

880     for (Iterator JavaDoc iter = returnedSet.iterator(); iter.hasNext();) {
881         Map.Entry JavaDoc currElement = (Map.Entry JavaDoc) iter.next();
882
883         if (currElement != null) {
884         if (currElement.getValue() != null) {
885             // validate the field valued...
886
if (validateField((currElement.getKey()).toString(),
887                       (currElement.getValue()).toString())) {
888             continue;
889             } else {
890             if (tracing()) {
891                 trace("isValid()",
892                   "Field " + currElement.getKey() + "=" +
893                   currElement.getValue() + " is not valid");
894             }
895             return false;
896             }
897         }
898         }
899     }
900
901     // fell through, all fields OK
902

903     if (tracing()) {
904         trace("Descriptor.isValid()","returns true");
905     }
906
907     return true;
908     }
909
910
911     // worker routine for isValid()
912
// name is not null
913
// descriptorType is not null
914
// getMethod and setMethod are not null
915
// persistPeriod is numeric
916
// currencyTimeLimit is numeric
917
// lastUpdatedTimeStamp is numeric
918
// visibility is 1-4
919
// severity is 0-6
920
// log is T or F
921
// role is not null
922
// class is not null
923
// lastReturnedTimeStamp is numeric
924

925
926     private boolean validateField(String JavaDoc fldName, Object JavaDoc fldValue) {
927     if ((fldName == null) || (fldName.equals("")))
928         return false;
929     String JavaDoc SfldValue = "";
930     boolean isAString = false;
931     if ((fldValue != null) && (fldValue instanceof java.lang.String JavaDoc)) {
932         SfldValue = (String JavaDoc) fldValue;
933         isAString = true;
934     }
935
936     boolean nameOrDescriptorType =
937         (fldName.equalsIgnoreCase("Name") ||
938          fldName.equalsIgnoreCase("DescriptorType"));
939     if (nameOrDescriptorType ||
940         fldName.equalsIgnoreCase("SetMethod") ||
941         fldName.equalsIgnoreCase("GetMethod") ||
942         fldName.equalsIgnoreCase("Role") ||
943         fldName.equalsIgnoreCase("Class")) {
944         if (fldValue == null || !isAString)
945         return false;
946         if (nameOrDescriptorType && SfldValue.equals(""))
947         return false;
948         return true;
949     } else if (fldName.equalsIgnoreCase("visibility")) {
950         long v;
951         if ((fldValue != null) && (isAString)) {
952         v = toNumeric(SfldValue);
953         } else if (fldValue instanceof java.lang.Integer JavaDoc) {
954         v = ((Integer JavaDoc)fldValue).intValue();
955         } else return false;
956
957         if (v >= 1 && v <= 4)
958         return true;
959         else
960         return false;
961     } else if (fldName.equalsIgnoreCase("severity")) {
962
963         long v;
964         if ((fldValue != null) && (isAString)) {
965         v = toNumeric(SfldValue);
966         } else if (fldValue instanceof java.lang.Integer JavaDoc) {
967         v = ((Integer JavaDoc)fldValue).intValue();
968         } else return false;
969
970         return (v >= 0 && v <= 6);
971     } else if (fldName.equalsIgnoreCase("PersistPolicy")) {
972         return (((fldValue != null) && (isAString)) &&
973             ( SfldValue.equalsIgnoreCase("OnUpdate") ||
974               SfldValue.equalsIgnoreCase("OnTimer") ||
975               SfldValue.equalsIgnoreCase("NoMoreOftenThan") ||
976               SfldValue.equalsIgnoreCase("Always") ||
977               SfldValue.equalsIgnoreCase("Never") ));
978     } else if (fldName.equalsIgnoreCase("PersistPeriod") ||
979            fldName.equalsIgnoreCase("CurrencyTimeLimit") ||
980            fldName.equalsIgnoreCase("LastUpdatedTimeStamp") ||
981            fldName.equalsIgnoreCase("LastReturnedTimeStamp")) {
982
983         long v;
984         if ((fldValue != null) && (isAString)) {
985         v = toNumeric(SfldValue);
986         } else if (fldValue instanceof java.lang.Number JavaDoc) {
987         v = ((Number JavaDoc)fldValue).longValue();
988         } else return false;
989
990         return (v >= -1);
991     } else if (fldName.equalsIgnoreCase("log")) {
992         return ((fldValue instanceof java.lang.Boolean JavaDoc) ||
993             (isAString &&
994              (SfldValue.equalsIgnoreCase("T") ||
995               SfldValue.equalsIgnoreCase("true") ||
996               SfldValue.equalsIgnoreCase("F") ||
997               SfldValue.equalsIgnoreCase("false") )));
998     }
999
1000    // default to true, it is a field we aren't validating (user etc.)
1001
return true;
1002    }
1003
1004
1005
1006    /**
1007     * <p>Returns an XML String representing the descriptor.</p>
1008     *
1009     * <p>The format is not defined, but an implementation must
1010     * ensure that the string returned by this method can be
1011     * used to build an equivalent descriptor when instantiated
1012     * using the constructor {@link #DescriptorSupport(String)
1013     * DescriptorSupport(String inStr)}.</p>
1014     *
1015     * <p>Fields which are not String objects will have toString()
1016     * called on them to create the value. The value will be
1017     * enclosed in parentheses. It is not guaranteed that you can
1018     * reconstruct these objects unless they have been
1019     * specifically set up to support toString() in a meaningful
1020     * format and have a matching constructor that accepts a
1021     * String in the same format.</p>
1022     *
1023     * <p>If the descriptor is empty the following String is
1024     * returned: &lt;Descriptor&gt;&lt;/Descriptor&gt;</p>
1025     *
1026     * @return the XML string.
1027     *
1028     * @exception RuntimeOperationsException for illegal value for
1029     * field Names or field Values. If the XML formated string
1030     * construction fails for any reason, this exception will be
1031     * thrown.
1032     */

1033    public synchronized String JavaDoc toXMLString() {
1034    StringBuffer JavaDoc buf = new StringBuffer JavaDoc("<Descriptor>");
1035    Set JavaDoc returnedSet = descriptorMap.entrySet();
1036    for (Iterator JavaDoc iter = returnedSet.iterator(); iter.hasNext(); ) {
1037        final Map.Entry JavaDoc currElement = (Map.Entry JavaDoc) iter.next();
1038        final String JavaDoc name = currElement.getKey().toString();
1039        Object JavaDoc value = currElement.getValue();
1040        String JavaDoc valueString = null;
1041        /* Set valueString to non-null iff this is a string that
1042           cannot be confused with the encoding of an object. If it
1043           could be so confused (surrounded by parentheses) then we
1044           call makeFieldValue as for any non-String object and end
1045           up with an encoding like "(java.lang.String/(thing))". */

1046        if (value instanceof String JavaDoc) {
1047        final String JavaDoc svalue = (String JavaDoc) value;
1048        if (!svalue.startsWith("(") || !svalue.endsWith(")"))
1049            valueString = quote(svalue);
1050        }
1051        if (valueString == null)
1052        valueString = makeFieldValue(value);
1053        buf.append("<field name=\"").append(name).append("\" value=\"")
1054        .append(valueString).append("\"></field>");
1055    }
1056    buf.append("</Descriptor>");
1057    return buf.toString();
1058    }
1059
1060    private static final String JavaDoc[] entities = {
1061    " &#32;",
1062    "\"&quot;",
1063    "<&lt;",
1064    ">&gt;",
1065    "&&amp;",
1066    "\r&#13;",
1067    "\t&#9;",
1068    "\n&#10;",
1069    "\f&#12;",
1070    };
1071    private static final Map JavaDoc<String JavaDoc,Character JavaDoc> entityToCharMap =
1072    new HashMap JavaDoc<String JavaDoc,Character JavaDoc>();
1073    private static final String JavaDoc[] charToEntityMap;
1074
1075    static {
1076    char maxChar = 0;
1077    for (int i = 0; i < entities.length; i++) {
1078        final char c = entities[i].charAt(0);
1079        if (c > maxChar)
1080        maxChar = c;
1081    }
1082    charToEntityMap = new String JavaDoc[maxChar + 1];
1083    for (int i = 0; i < entities.length; i++) {
1084        final char c = entities[i].charAt(0);
1085        final String JavaDoc entity = entities[i].substring(1);
1086        charToEntityMap[c] = entity;
1087        entityToCharMap.put(entity, new Character JavaDoc(c));
1088    }
1089    }
1090
1091    private static boolean isMagic(char c) {
1092    return (c < charToEntityMap.length && charToEntityMap[c] != null);
1093    }
1094
1095    /*
1096     * Quote the string so that it will be acceptable to the (String)
1097     * constructor. Since the parsing code in that constructor is fairly
1098     * stupid, we're obliged to quote apparently innocuous characters like
1099     * space, <, and >. In a future version, we should rewrite the parser
1100     * and only quote " plus either \ or & (depending on the quote syntax).
1101     */

1102    private static String JavaDoc quote(String JavaDoc s) {
1103    boolean found = false;
1104    for (int i = 0; i < s.length(); i++) {
1105        if (isMagic(s.charAt(i))) {
1106        found = true;
1107        break;
1108        }
1109    }
1110    if (!found)
1111        return s;
1112    StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1113    for (int i = 0; i < s.length(); i++) {
1114        char c = s.charAt(i);
1115        if (isMagic(c))
1116        buf.append(charToEntityMap[c]);
1117        else
1118        buf.append(c);
1119    }
1120    return buf.toString();
1121    }
1122
1123    private static String JavaDoc unquote(String JavaDoc s) throws XMLParseException JavaDoc {
1124    if (!s.startsWith("\"") || !s.endsWith("\""))
1125        throw new XMLParseException JavaDoc("Value must be quoted: <" + s + ">");
1126    StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1127    final int len = s.length() - 1;
1128    for (int i = 1; i < len; i++) {
1129        final char c = s.charAt(i);
1130        final int semi;
1131        final Character JavaDoc quoted;
1132        if (c == '&'
1133        && (semi = s.indexOf(';', i + 1)) >= 0
1134        && ((quoted =
1135            (Character JavaDoc) entityToCharMap.get(s.substring(i, semi+1)))
1136            != null)) {
1137        buf.append(quoted);
1138        i = semi;
1139        } else
1140        buf.append(c);
1141    }
1142    return buf.toString();
1143    }
1144
1145    /**
1146     * Make the string that will go inside "..." for a value that is not
1147     * a plain String.
1148     * @throws RuntimeOperationsException if the value cannot be encoded.
1149     */

1150    private static String JavaDoc makeFieldValue(Object JavaDoc value) {
1151    if (value == null)
1152        return "(null)";
1153
1154    Class JavaDoc valueClass = value.getClass();
1155    try {
1156        valueClass.getConstructor(new Class JavaDoc[] {String JavaDoc.class});
1157    } catch (NoSuchMethodException JavaDoc e) {
1158        final String JavaDoc msg =
1159        "Class " + valueClass + " does not have a public " +
1160        "constructor with a single string arg";
1161        final RuntimeException JavaDoc iae = new IllegalArgumentException JavaDoc(msg);
1162        throw new RuntimeOperationsException JavaDoc(iae,
1163                         "Cannot make XML descriptor");
1164    } catch (SecurityException JavaDoc e) {
1165        // OK: we'll pretend the constructor is there
1166
// too bad if it's not: we'll find out when we try to
1167
// reconstruct the DescriptorSupport
1168
}
1169
1170    final String JavaDoc quotedValueString = quote(value.toString());
1171    
1172    return "(" + valueClass.getName() + "/" + quotedValueString + ")";
1173    }
1174
1175    /*
1176     * Parse a field value from the XML produced by toXMLString().
1177     * Given a descriptor XML containing <field name="nnn" value="vvv">,
1178     * the argument to this method will be "vvv" (a string including the
1179     * containing quote characters). If vvv begins and ends with parentheses,
1180     * then it may contain:
1181     * - the characters "null", in which case the result is null;
1182     * - a value of the form "some.class.name/xxx", in which case the
1183     * result is equivalent to `new some.class.name("xxx")';
1184     * - some other string, in which case the result is that string,
1185     * without the parentheses.
1186     */

1187    private static Object JavaDoc parseQuotedFieldValue(String JavaDoc s)
1188        throws XMLParseException JavaDoc {
1189    s = unquote(s);
1190    if (s.equalsIgnoreCase("(null)"))
1191        return null;
1192    if (!s.startsWith("(") || !s.endsWith(")"))
1193        return s;
1194    final int slash = s.indexOf('/');
1195    if (slash < 0) {
1196        // compatibility: old code didn't include class name
1197
return s.substring(1, s.length() - 1);
1198    }
1199    final String JavaDoc className = s.substring(1, slash);
1200    final Constructor JavaDoc constr;
1201    try {
1202        final ClassLoader JavaDoc contextClassLoader =
1203        Thread.currentThread().getContextClassLoader();
1204            if (contextClassLoader == null)
1205                ReflectUtil.checkPackageAccess(className);
1206        final Class JavaDoc c =
1207        Class.forName(className, false, contextClassLoader);
1208        constr = c.getConstructor(new Class JavaDoc[] {String JavaDoc.class});
1209    } catch (Exception JavaDoc e) {
1210        throw new XMLParseException JavaDoc(e,
1211                    "Cannot parse value: <" + s + ">");
1212    }
1213    final String JavaDoc arg = s.substring(slash + 1, s.length() - 1);
1214    try {
1215        return constr.newInstance(new Object JavaDoc[] {arg});
1216    } catch (Exception JavaDoc e) {
1217        final String JavaDoc msg =
1218        "Cannot construct instance of " + className +
1219        " with arg: <" + s + ">";
1220        throw new XMLParseException JavaDoc(e, msg);
1221    }
1222    }
1223
1224    /**
1225     * Returns <pv>a human readable string representing the
1226     * descriptor</pv>. The string will be in the format of
1227     * "fieldName=fieldValue,fieldName2=fieldValue2,..."<br>
1228     *
1229     * If there are no fields in the descriptor, then an empty String
1230     * is returned.<br>
1231     *
1232     * If a fieldValue is an object then the toString() method is
1233     * called on it and its returned value is used as the value for
1234     * the field enclosed in parenthesis.
1235     *
1236     * @exception RuntimeOperationsException for illegal value for
1237     * field Names or field Values. If the descriptor string fails
1238     * for any reason, this exception will be thrown.
1239     */

1240    public synchronized String JavaDoc toString() {
1241    if (tracing()) {
1242        trace("Descriptor.toString()","Entry");
1243    }
1244
1245    String JavaDoc respStr = "";
1246    String JavaDoc[] fields = getFields();
1247
1248    if (tracing()) {
1249        trace("Descriptor.toString()",
1250          "Printing " + fields.length + " fields");
1251    }
1252
1253    if ((fields == null) || (fields.length == 0)) {
1254        if (tracing()) {
1255        trace("Descriptor.toString()","Empty Descriptor");
1256        }
1257        return respStr;
1258    }
1259
1260    for (int i=0; i < fields.length; i++) {
1261        if (i == (fields.length - 1)) {
1262        respStr = respStr.concat(fields[i]);
1263        } else {
1264        respStr = respStr.concat(fields[i] + ", ");
1265        }
1266    }
1267
1268    if (tracing()) {
1269        trace("Descriptor.toString()","Exit returning " + respStr);
1270    }
1271
1272    return respStr;
1273    }
1274
1275    // utility to convert to int, returns -2 if bogus.
1276

1277    private long toNumeric(String JavaDoc inStr) {
1278    long result = -2;
1279    try {
1280        result = java.lang.Long.parseLong(inStr);
1281    } catch (Exception JavaDoc e) {
1282        return -2;
1283    }
1284    return result;
1285    }
1286
1287
1288    // Trace and debug functions
1289

1290    private boolean tracing() {
1291    return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_MODELMBEAN);
1292    }
1293
1294    private void trace(String JavaDoc inClass, String JavaDoc inMethod, String JavaDoc inText) {
1295    Trace.send(Trace.LEVEL_TRACE, Trace.INFO_MODELMBEAN, inClass,
1296           inMethod,
1297           Integer.toHexString(this.hashCode()) + " " + inText);
1298    }
1299
1300    private void trace(String JavaDoc inMethod, String JavaDoc inText) {
1301    trace(currClass, inMethod, inText);
1302    }
1303
1304    /**
1305     * Deserializes a {@link DescriptorSupport} from an {@link
1306     * ObjectInputStream}.
1307     */

1308    private void readObject(ObjectInputStream JavaDoc in)
1309        throws IOException JavaDoc, ClassNotFoundException JavaDoc {
1310    ObjectInputStream.GetField JavaDoc fields = in.readFields();
1311    Map JavaDoc descriptor = (Map JavaDoc) fields.get("descriptor", null);
1312    init(null);
1313        descriptorMap.putAll(descriptor);
1314    }
1315
1316
1317    /**
1318     * Serializes a {@link DescriptorSupport} to an {@link ObjectOutputStream}.
1319     */

1320    /* If you set jmx.serial.form to "1.2.0" or "1.2.1", then we are
1321       bug-compatible with those versions. Specifically, field names
1322       are forced to lower-case before being written. This
1323       contradicts the spec, which, though it does not mention
1324       serialization explicitly, does say that the case of field names
1325       is preserved. But in 1.2.0 and 1.2.1, this requirement was not
1326       met. Instead, field names in the descriptor map were forced to
1327       lower case. Those versions expect this to have happened to a
1328       descriptor they deserialize and e.g. getFieldValue will not
1329       find a field whose name is spelt with a different case.
1330    */

1331    private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
1332    ObjectOutputStream.PutField JavaDoc fields = out.putFields();
1333    boolean compat = "1.0".equals(serialForm);
1334    if (compat)
1335        fields.put("currClass", currClass);
1336        
1337        /* Purge the field "targetObject" from the DescriptorSupport before
1338         * serializing since the referenced object is typically not
1339         * serializable. We do this here rather than purging the "descriptor"
1340         * variable below because that HashMap doesn't do case-insensitivity.
1341         * See CR 6332962.
1342         */

1343        SortedMap JavaDoc<String JavaDoc, Object JavaDoc> startMap = descriptorMap;
1344        if (startMap.containsKey("targetObject")) {
1345            startMap = new TreeMap JavaDoc<String JavaDoc, Object JavaDoc>(descriptorMap);
1346            startMap.remove("targetObject");
1347        }
1348
1349    final HashMap JavaDoc<String JavaDoc, Object JavaDoc> descriptor;
1350    if (compat || "1.2.0".equals(serialForm) ||
1351                "1.2.1".equals(serialForm)) {
1352            descriptor = new HashMap JavaDoc<String JavaDoc, Object JavaDoc>();
1353            for (Map.Entry JavaDoc<String JavaDoc, Object JavaDoc> entry : startMap.entrySet())
1354                descriptor.put(entry.getKey().toLowerCase(), entry.getValue());
1355        } else
1356            descriptor = new HashMap JavaDoc<String JavaDoc, Object JavaDoc>(startMap);
1357
1358    fields.put("descriptor", descriptor);
1359    out.writeFields();
1360    }
1361}
1362
Popular Tags