Source Code Cross Referenced for DescriptorSupport.java in  » 6.0-JDK-Core » management » javax » management » modelmbean » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » management » javax.management.modelmbean 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Portions Copyright 2000-2007 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025        /*
0026         * @(#)author    IBM Corp.
0027         * 
0028         * Copyright IBM Corp. 1999-2000.  All rights reserved.
0029         */
0030
0031        package javax.management.modelmbean;
0032
0033        import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER;
0034        import static com.sun.jmx.mbeanserver.Util.cast;
0035        import com.sun.jmx.mbeanserver.GetPropertyAction;
0036
0037        import java.io.IOException;
0038        import java.io.ObjectInputStream;
0039        import java.io.ObjectOutputStream;
0040        import java.io.ObjectStreamField;
0041
0042        import java.lang.reflect.Constructor;
0043
0044        import java.security.AccessController;
0045        import java.util.HashMap;
0046        import java.util.Iterator;
0047        import java.util.Map;
0048        import java.util.Set;
0049        import java.util.SortedMap;
0050        import java.util.StringTokenizer;
0051        import java.util.TreeMap;
0052        import java.util.logging.Level;
0053
0054        import javax.management.Descriptor;
0055        import javax.management.ImmutableDescriptor;
0056        import javax.management.MBeanException;
0057        import javax.management.RuntimeOperationsException;
0058
0059        import sun.reflect.misc.ReflectUtil;
0060
0061        /**
0062         * This class represents the metadata set for a ModelMBean element.  A
0063         * descriptor is part of the ModelMBeanInfo,
0064         * ModelMBeanNotificationInfo, ModelMBeanAttributeInfo,
0065         * ModelMBeanConstructorInfo, and ModelMBeanParameterInfo.
0066         * <P>
0067         * A descriptor consists of a collection of fields.  Each field is in
0068         * fieldname=fieldvalue format.  Field names are not case sensitive,
0069         * case will be preserved on field values.
0070         * <P>
0071         * All field names and values are not predefined. New fields can be
0072         * defined and added by any program.  Some fields have been predefined
0073         * for consistency of implementation and support by the
0074         * ModelMBeanInfo, ModelMBeanAttributeInfo, ModelMBeanConstructorInfo,
0075         * ModelMBeanNotificationInfo, ModelMBeanOperationInfo and ModelMBean
0076         * classes.
0077         *
0078         * <p>The <b>serialVersionUID</b> of this class is <code>-6292969195866300415L</code>.
0079         * 
0080         * @since 1.5
0081         */
0082        @SuppressWarnings("serial")
0083        // serialVersionUID not constant
0084        public class DescriptorSupport implements  javax.management.Descriptor {
0085
0086            // Serialization compatibility stuff:
0087            // Two serial forms are supported in this class. The selected form depends
0088            // on system property "jmx.serial.form":
0089            //  - "1.0" for JMX 1.0
0090            //  - any other value for JMX 1.1 and higher
0091            //
0092            // Serial version for old serial form
0093            private static final long oldSerialVersionUID = 8071560848919417985L;
0094            //
0095            // Serial version for new serial form
0096            private static final long newSerialVersionUID = -6292969195866300415L;
0097            //
0098            // Serializable fields in old serial form
0099            private static final ObjectStreamField[] oldSerialPersistentFields = {
0100                    new ObjectStreamField("descriptor", HashMap.class),
0101                    new ObjectStreamField("currClass", String.class) };
0102            //
0103            // Serializable fields in new serial form
0104            private static final ObjectStreamField[] newSerialPersistentFields = { new ObjectStreamField(
0105                    "descriptor", HashMap.class) };
0106            //
0107            // Actual serial version and serial form
0108            private static final long serialVersionUID;
0109            /**
0110             * @serialField descriptor HashMap The collection of fields representing this descriptor
0111             */
0112            private static final ObjectStreamField[] serialPersistentFields;
0113            private static final String serialForm;
0114            static {
0115                String form = null;
0116                boolean compat = false;
0117                try {
0118                    GetPropertyAction act = new GetPropertyAction(
0119                            "jmx.serial.form");
0120                    form = AccessController.doPrivileged(act);
0121                    compat = "1.0".equals(form); // form may be null
0122                } catch (Exception e) {
0123                    // OK: No compat with 1.0
0124                }
0125                serialForm = form;
0126                if (compat) {
0127                    serialPersistentFields = oldSerialPersistentFields;
0128                    serialVersionUID = oldSerialVersionUID;
0129                } else {
0130                    serialPersistentFields = newSerialPersistentFields;
0131                    serialVersionUID = newSerialVersionUID;
0132                }
0133            }
0134            //
0135            // END Serialization compatibility stuff
0136
0137            /* Spec says that field names are case-insensitive, but that case
0138               is preserved.  This means that we need to be able to map from a
0139               name that may differ in case to the actual name that is used in
0140               the HashMap.  Thus, descriptorMap is a TreeMap with a Comparator
0141               that ignores case.
0142
0143               Previous versions of this class had a field called "descriptor"
0144               of type HashMap where the keys were directly Strings.  This is
0145               hard to reconcile with the required semantics, so we fabricate
0146               that field virtually during serialization and deserialization
0147               but keep the real information in descriptorMap.
0148             */
0149            private transient SortedMap<String, Object> descriptorMap;
0150
0151            private static final String currClass = "DescriptorSupport";
0152
0153            /**
0154             * Descriptor default constructor.
0155             * Default initial descriptor size is 20.  It will grow as needed.<br>
0156             * Note that the created empty descriptor is not a valid descriptor
0157             * (the method {@link #isValid isValid} returns <CODE>false</CODE>)
0158             */
0159            public DescriptorSupport() {
0160                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0161                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0162                            DescriptorSupport.class.getName(),
0163                            "DescriptorSupport()", "Constructor");
0164                }
0165                init(null);
0166            }
0167
0168            /**
0169             * Descriptor constructor.  Takes as parameter the initial
0170             * capacity of the Map that stores the descriptor fields.
0171             * Capacity will grow as needed.<br> Note that the created empty
0172             * descriptor is not a valid descriptor (the method {@link
0173             * #isValid isValid} returns <CODE>false</CODE>).
0174             *
0175             * @param initNumFields The initial capacity of the Map that
0176             * stores the descriptor fields.
0177             *
0178             * @exception RuntimeOperationsException for illegal value for
0179             * initNumFields (&lt;= 0)
0180             * @exception MBeanException Wraps a distributed communication Exception.
0181             */
0182            public DescriptorSupport(int initNumFields) throws MBeanException,
0183                    RuntimeOperationsException {
0184                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0185                    MODELMBEAN_LOGGER
0186                            .logp(Level.FINEST, DescriptorSupport.class
0187                                    .getName(), "Descriptor(initNumFields = "
0188                                    + initNumFields + ")", "Constructor");
0189                }
0190                if (initNumFields <= 0) {
0191                    if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0192                        MODELMBEAN_LOGGER.logp(Level.FINEST,
0193                                DescriptorSupport.class.getName(),
0194                                "Descriptor(initNumFields)",
0195                                "Illegal arguments: initNumFields <= 0");
0196                    }
0197                    final String msg = "Descriptor field limit invalid: "
0198                            + initNumFields;
0199                    final RuntimeException iae = new IllegalArgumentException(
0200                            msg);
0201                    throw new RuntimeOperationsException(iae, msg);
0202                }
0203                init(null);
0204            }
0205
0206            /**
0207             * Descriptor constructor taking a Descriptor as parameter.
0208             * Creates a new descriptor initialized to the values of the
0209             * descriptor passed in parameter.
0210             *
0211             * @param inDescr the descriptor to be used to initialize the
0212             * constructed descriptor. If it is null or contains no descriptor
0213             * fields, an empty Descriptor will be created.
0214             */
0215            public DescriptorSupport(DescriptorSupport inDescr) {
0216                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0217                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0218                            DescriptorSupport.class.getName(),
0219                            "Descriptor(Descriptor)", "Constructor");
0220                }
0221                if (inDescr == null)
0222                    init(null);
0223                else
0224                    init(inDescr.descriptorMap);
0225            }
0226
0227            /**
0228             * <p>Descriptor constructor taking an XML String.</p>
0229             *
0230             * <p>The format of the XML string is not defined, but an
0231             * implementation must ensure that the string returned by
0232             * {@link #toXMLString() toXMLString()} on an existing
0233             * descriptor can be used to instantiate an equivalent
0234             * descriptor using this constructor.</p>
0235             *
0236             * <p>In this implementation, all field values will be created
0237             * as Strings.  If the field values are not Strings, the
0238             * programmer will have to reset or convert these fields
0239             * correctly.</p>
0240             *
0241             * @param inStr An XML-formatted string used to populate this
0242             * Descriptor.  The format is not defined, but any
0243             * implementation must ensure that the string returned by
0244             * method {@link #toXMLString toXMLString} on an existing
0245             * descriptor can be used to instantiate an equivalent
0246             * descriptor when instantiated using this constructor.
0247             *
0248             * @exception RuntimeOperationsException If the String inStr
0249             * passed in parameter is null
0250             * @exception XMLParseException XML parsing problem while parsing
0251             * the input String
0252             * @exception MBeanException Wraps a distributed communication Exception.
0253             */
0254            /* At some stage we should rewrite this code to be cleverer.  Using
0255               a StringTokenizer as we do means, first, that we accept a lot of
0256               bogus strings without noticing they are bogus, and second, that we
0257               split the string being parsed at characters like > even if they
0258               occur in the middle of a field value. */
0259            public DescriptorSupport(String inStr) throws MBeanException,
0260                    RuntimeOperationsException, XMLParseException {
0261                /* parse an XML-formatted string and populate internal
0262                 * structure with it */
0263                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0264                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0265                            DescriptorSupport.class.getName(),
0266                            "Descriptor(String = '" + inStr + "')",
0267                            "Constructor");
0268                }
0269                if (inStr == null) {
0270                    if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0271                        MODELMBEAN_LOGGER.logp(Level.FINEST,
0272                                DescriptorSupport.class.getName(),
0273                                "Descriptor(String = null)",
0274                                "Illegal arguments");
0275                    }
0276                    final String msg = "String in parameter is null";
0277                    final RuntimeException iae = new IllegalArgumentException(
0278                            msg);
0279                    throw new RuntimeOperationsException(iae, msg);
0280                }
0281
0282                final String lowerInStr = inStr.toLowerCase();
0283                if (!lowerInStr.startsWith("<descriptor>")
0284                        || !lowerInStr.endsWith("</descriptor>")) {
0285                    throw new XMLParseException(
0286                            "No <descriptor>, </descriptor> pair");
0287                }
0288
0289                // parse xmlstring into structures
0290                init(null);
0291                // create dummy descriptor: should have same size
0292                // as number of fields in xmlstring
0293                // loop through structures and put them in descriptor
0294
0295                StringTokenizer st = new StringTokenizer(inStr, "<> \t\n\r\f");
0296
0297                boolean inFld = false;
0298                boolean inDesc = false;
0299                String fieldName = null;
0300                String fieldValue = null;
0301
0302                while (st.hasMoreTokens()) { // loop through tokens
0303                    String tok = st.nextToken();
0304
0305                    if (tok.equalsIgnoreCase("FIELD")) {
0306                        inFld = true;
0307                    } else if (tok.equalsIgnoreCase("/FIELD")) {
0308                        if ((fieldName != null) && (fieldValue != null)) {
0309                            fieldName = fieldName.substring(fieldName
0310                                    .indexOf('"') + 1, fieldName
0311                                    .lastIndexOf('"'));
0312                            final Object fieldValueObject = parseQuotedFieldValue(fieldValue);
0313                            setField(fieldName, fieldValueObject);
0314                        }
0315                        fieldName = null;
0316                        fieldValue = null;
0317                        inFld = false;
0318                    } else if (tok.equalsIgnoreCase("DESCRIPTOR")) {
0319                        inDesc = true;
0320                    } else if (tok.equalsIgnoreCase("/DESCRIPTOR")) {
0321                        inDesc = false;
0322                        fieldName = null;
0323                        fieldValue = null;
0324                        inFld = false;
0325                    } else if (inFld && inDesc) {
0326                        // want kw=value, eg, name="myname" value="myvalue"
0327                        int eq_separator = tok.indexOf("=");
0328                        if (eq_separator > 0) {
0329                            String kwPart = tok.substring(0, eq_separator);
0330                            String valPart = tok.substring(eq_separator + 1);
0331                            if (kwPart.equalsIgnoreCase("NAME"))
0332                                fieldName = valPart;
0333                            else if (kwPart.equalsIgnoreCase("VALUE"))
0334                                fieldValue = valPart;
0335                            else { // xml parse exception
0336                                final String msg = "Expected `name' or `value', got `"
0337                                        + tok + "'";
0338                                throw new XMLParseException(msg);
0339                            }
0340                        } else { // xml parse exception
0341                            final String msg = "Expected `keyword=value', got `"
0342                                    + tok + "'";
0343                            throw new XMLParseException(msg);
0344                        }
0345                    }
0346                } // while tokens
0347                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0348                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0349                            DescriptorSupport.class.getName(),
0350                            "Descriptor(XMLString)", "Exit");
0351                }
0352            }
0353
0354            /**
0355             * Constructor taking field names and field values.  Neither array
0356             * can be null.
0357             *
0358             * @param fieldNames String array of field names.  No elements of
0359             * this array can be null.
0360             * @param fieldValues Object array of the corresponding field
0361             * values.  Elements of the array can be null. The
0362             * <code>fieldValue</code> must be valid for the
0363             * <code>fieldName</code> (as defined in method {@link #isValid
0364             * isValid})
0365             *
0366             * <p>Note: array sizes of parameters should match. If both arrays
0367             * are empty, then an empty descriptor is created.</p>
0368             *
0369             * @exception RuntimeOperationsException for illegal value for
0370             * field Names or field Values.  The array lengths must be equal.
0371             * If the descriptor construction fails for any reason, this
0372             * exception will be thrown.
0373             *
0374             */
0375            public DescriptorSupport(String[] fieldNames, Object[] fieldValues)
0376                    throws RuntimeOperationsException {
0377                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0378                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0379                            DescriptorSupport.class.getName(),
0380                            "Descriptor(fieldNames,fieldObjects)",
0381                            "Constructor");
0382                }
0383
0384                if ((fieldNames == null) || (fieldValues == null)
0385                        || (fieldNames.length != fieldValues.length)) {
0386                    if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0387                        MODELMBEAN_LOGGER.logp(Level.FINEST,
0388                                DescriptorSupport.class.getName(),
0389                                "Descriptor(fieldNames,fieldObjects)",
0390                                "Illegal arguments");
0391                    }
0392
0393                    final String msg = "Null or invalid fieldNames or fieldValues";
0394                    final RuntimeException iae = new IllegalArgumentException(
0395                            msg);
0396                    throw new RuntimeOperationsException(iae, msg);
0397                }
0398
0399                /* populate internal structure with fields */
0400                init(null);
0401                for (int i = 0; i < fieldNames.length; i++) {
0402                    // setField will throw an exception if a fieldName is be null.
0403                    // the fieldName and fieldValue will be validated in setField.
0404                    setField(fieldNames[i], fieldValues[i]);
0405                }
0406                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0407                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0408                            DescriptorSupport.class.getName(),
0409                            "Descriptor(fieldNames,fieldObjects)", "Exit");
0410                }
0411            }
0412
0413            /**
0414             * Constructor taking fields in the <i>fieldName=fieldValue</i>
0415             * format.
0416             *
0417             * @param fields String array with each element containing a
0418             * field name and value.  If this array is null or empty, then the
0419             * default constructor will be executed. Null strings or empty
0420             * strings will be ignored.
0421             *
0422             * <p>All field values should be Strings.  If the field values are
0423             * not Strings, the programmer will have to reset or convert these
0424             * fields correctly.
0425             *
0426             * <p>Note: Each string should be of the form
0427             * <i>fieldName=fieldValue</i>.  The field name
0428             * ends at the first {@code =} character; for example if the String
0429             * is {@code a=b=c} then the field name is {@code a} and its value
0430             * is {@code b=c}.
0431             *
0432             * @exception RuntimeOperationsException for illegal value for
0433             * field Names or field Values.  The field must contain an
0434             * "=". "=fieldValue", "fieldName", and "fieldValue" are illegal.
0435             * FieldName cannot be null.  "fieldName=" will cause the value to
0436             * be null.  If the descriptor construction fails for any reason,
0437             * this exception will be thrown.
0438             *
0439             */
0440            public DescriptorSupport(String... fields) {
0441                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0442                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0443                            DescriptorSupport.class.getName(),
0444                            "Descriptor(String... fields)", "Constructor");
0445                }
0446                init(null);
0447                if ((fields == null) || (fields.length == 0))
0448                    return;
0449
0450                init(null);
0451
0452                for (int i = 0; i < fields.length; i++) {
0453                    if ((fields[i] == null) || (fields[i].equals(""))) {
0454                        continue;
0455                    }
0456                    int eq_separator = fields[i].indexOf("=");
0457                    if (eq_separator < 0) {
0458                        // illegal if no = or is first character
0459                        if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0460                            MODELMBEAN_LOGGER
0461                                    .logp(
0462                                            Level.FINEST,
0463                                            DescriptorSupport.class.getName(),
0464                                            "Descriptor(String... fields)",
0465                                            "Illegal arguments: field does not have "
0466                                                    + "'=' as a name and value separator");
0467                        }
0468                        final String msg = "Field in invalid format: no equals sign";
0469                        final RuntimeException iae = new IllegalArgumentException(
0470                                msg);
0471                        throw new RuntimeOperationsException(iae, msg);
0472                    }
0473
0474                    String fieldName = fields[i].substring(0, eq_separator);
0475                    String fieldValue = null;
0476                    if (eq_separator < fields[i].length()) {
0477                        // = is not in last character
0478                        fieldValue = fields[i].substring(eq_separator + 1);
0479                    }
0480
0481                    if (fieldName.equals("")) {
0482                        if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0483                            MODELMBEAN_LOGGER.logp(Level.FINEST,
0484                                    DescriptorSupport.class.getName(),
0485                                    "Descriptor(String... fields)",
0486                                    "Illegal arguments: fieldName is empty");
0487                        }
0488
0489                        final String msg = "Field in invalid format: no fieldName";
0490                        final RuntimeException iae = new IllegalArgumentException(
0491                                msg);
0492                        throw new RuntimeOperationsException(iae, msg);
0493                    }
0494
0495                    setField(fieldName, fieldValue);
0496                }
0497                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0498                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0499                            DescriptorSupport.class.getName(),
0500                            "Descriptor(String... fields)", "Exit");
0501                }
0502            }
0503
0504            private void init(Map<String, ?> initMap) {
0505                descriptorMap = new TreeMap<String, Object>(
0506                        String.CASE_INSENSITIVE_ORDER);
0507                if (initMap != null)
0508                    descriptorMap.putAll(initMap);
0509            }
0510
0511            // Implementation of the Descriptor interface
0512
0513            public synchronized Object getFieldValue(String fieldName)
0514                    throws RuntimeOperationsException {
0515
0516                if ((fieldName == null) || (fieldName.equals(""))) {
0517                    if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0518                        MODELMBEAN_LOGGER.logp(Level.FINEST,
0519                                DescriptorSupport.class.getName(),
0520                                "getFieldValue(String fieldName)",
0521                                "Illegal arguments: null field name");
0522                    }
0523                    final String msg = "Fieldname requested is null";
0524                    final RuntimeException iae = new IllegalArgumentException(
0525                            msg);
0526                    throw new RuntimeOperationsException(iae, msg);
0527                }
0528                Object retValue = descriptorMap.get(fieldName);
0529                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0530                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0531                            DescriptorSupport.class.getName(),
0532                            "getFieldValue(String fieldName = " + fieldName
0533                                    + ")", "Returns '" + retValue + "'");
0534                }
0535                return (retValue);
0536            }
0537
0538            public synchronized void setField(String fieldName,
0539                    Object fieldValue) throws RuntimeOperationsException {
0540
0541                // field name cannot be null or empty
0542                if ((fieldName == null) || (fieldName.equals(""))) {
0543                    if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0544                        MODELMBEAN_LOGGER.logp(Level.FINEST,
0545                                DescriptorSupport.class.getName(),
0546                                "setField(fieldName,fieldValue)",
0547                                "Illegal arguments: null or empty field name");
0548                    }
0549
0550                    final String msg = "Field name to be set is null or empty";
0551                    final RuntimeException iae = new IllegalArgumentException(
0552                            msg);
0553                    throw new RuntimeOperationsException(iae, msg);
0554                }
0555
0556                if (!validateField(fieldName, fieldValue)) {
0557                    if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0558                        MODELMBEAN_LOGGER.logp(Level.FINEST,
0559                                DescriptorSupport.class.getName(),
0560                                "setField(fieldName,fieldValue)",
0561                                "Illegal arguments");
0562                    }
0563
0564                    final String msg = "Field value invalid: " + fieldName
0565                            + "=" + fieldValue;
0566                    final RuntimeException iae = new IllegalArgumentException(
0567                            msg);
0568                    throw new RuntimeOperationsException(iae, msg);
0569                }
0570
0571                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0572                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0573                            DescriptorSupport.class.getName(),
0574                            "setField(fieldName,fieldValue)",
0575                            "Entry: setting '" + fieldName + "' to '"
0576                                    + fieldValue + "'");
0577                }
0578
0579                // Since we do not remove any existing entry with this name,
0580                // the field will preserve whatever case it had, ignoring
0581                // any difference there might be in fieldName.
0582                descriptorMap.put(fieldName, fieldValue);
0583            }
0584
0585            public synchronized String[] getFields() {
0586                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0587                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0588                            DescriptorSupport.class.getName(), "getFields()",
0589                            "Entry");
0590                }
0591                int numberOfEntries = descriptorMap.size();
0592
0593                String[] responseFields = new String[numberOfEntries];
0594                Set returnedSet = descriptorMap.entrySet();
0595
0596                int i = 0;
0597                Object currValue = null;
0598                Map.Entry currElement = null;
0599
0600                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0601                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0602                            DescriptorSupport.class.getName(), "getFields()",
0603                            "Returning " + numberOfEntries + " fields");
0604                }
0605                for (Iterator iter = returnedSet.iterator(); iter.hasNext(); i++) {
0606                    currElement = (Map.Entry) iter.next();
0607
0608                    if (currElement == null) {
0609                        if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0610                            MODELMBEAN_LOGGER.logp(Level.FINEST,
0611                                    DescriptorSupport.class.getName(),
0612                                    "getFields()", "Element is null");
0613                        }
0614                    } else {
0615                        currValue = currElement.getValue();
0616                        if (currValue == null) {
0617                            responseFields[i] = currElement.getKey() + "=";
0618                        } else {
0619                            if (currValue instanceof  java.lang.String) {
0620                                responseFields[i] = currElement.getKey() + "="
0621                                        + currValue.toString();
0622                            } else {
0623                                responseFields[i] = currElement.getKey() + "=("
0624                                        + currValue.toString() + ")";
0625                            }
0626                        }
0627                    }
0628                }
0629
0630                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0631                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0632                            DescriptorSupport.class.getName(), "getFields()",
0633                            "Exit");
0634                }
0635
0636                return responseFields;
0637            }
0638
0639            public synchronized String[] getFieldNames() {
0640                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0641                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0642                            DescriptorSupport.class.getName(),
0643                            "getFieldNames()", "Entry");
0644                }
0645                int numberOfEntries = descriptorMap.size();
0646
0647                String[] responseFields = new String[numberOfEntries];
0648                Set returnedSet = descriptorMap.entrySet();
0649
0650                int i = 0;
0651
0652                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0653                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0654                            DescriptorSupport.class.getName(),
0655                            "getFieldNames()", "Returning " + numberOfEntries
0656                                    + " fields");
0657                }
0658
0659                for (Iterator iter = returnedSet.iterator(); iter.hasNext(); i++) {
0660                    Map.Entry currElement = (Map.Entry) iter.next();
0661
0662                    if ((currElement == null) || (currElement.getKey() == null)) {
0663                        if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0664                            MODELMBEAN_LOGGER.logp(Level.FINEST,
0665                                    DescriptorSupport.class.getName(),
0666                                    "getFieldNames()", "Field is null");
0667                        }
0668                    } else {
0669                        responseFields[i] = currElement.getKey().toString();
0670                    }
0671                }
0672
0673                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0674                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0675                            DescriptorSupport.class.getName(),
0676                            "getFieldNames()", "Exit");
0677                }
0678
0679                return responseFields;
0680            }
0681
0682            public synchronized Object[] getFieldValues(String... fieldNames) {
0683                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0684                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0685                            DescriptorSupport.class.getName(),
0686                            "getFieldValues(String... fieldNames)", "Entry");
0687                }
0688                // if fieldNames == null return all values
0689                // if fieldNames is String[0] return no values
0690
0691                final int numberOfEntries = (fieldNames == null) ? descriptorMap
0692                        .size()
0693                        : fieldNames.length;
0694                final Object[] responseFields = new Object[numberOfEntries];
0695
0696                int i = 0;
0697
0698                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0699                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0700                            DescriptorSupport.class.getName(),
0701                            "getFieldValues(String... fieldNames)",
0702                            "Returning " + numberOfEntries + " fields");
0703                }
0704
0705                if (fieldNames == null) {
0706                    for (Iterator iter = descriptorMap.values().iterator(); iter
0707                            .hasNext(); i++)
0708                        responseFields[i] = iter.next();
0709                } else {
0710                    for (i = 0; i < fieldNames.length; i++) {
0711                        if ((fieldNames[i] == null)
0712                                || (fieldNames[i].equals(""))) {
0713                            responseFields[i] = null;
0714                        } else {
0715                            responseFields[i] = getFieldValue(fieldNames[i]);
0716                        }
0717                    }
0718                }
0719
0720                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0721                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0722                            DescriptorSupport.class.getName(),
0723                            "getFieldValues(String... fieldNames)", "Exit");
0724                }
0725
0726                return responseFields;
0727            }
0728
0729            public synchronized void setFields(String[] fieldNames,
0730                    Object[] fieldValues) throws RuntimeOperationsException {
0731
0732                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0733                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0734                            DescriptorSupport.class.getName(),
0735                            "setFields(fieldNames,fieldValues)", "Entry");
0736                }
0737
0738                if ((fieldNames == null) || (fieldValues == null)
0739                        || (fieldNames.length != fieldValues.length)) {
0740                    if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0741                        MODELMBEAN_LOGGER.logp(Level.FINEST,
0742                                DescriptorSupport.class.getName(),
0743                                "setFields(fieldNames,fieldValues)",
0744                                "Illegal arguments");
0745                    }
0746
0747                    final String msg = "fieldNames and fieldValues are null or invalid";
0748                    final RuntimeException iae = new IllegalArgumentException(
0749                            msg);
0750                    throw new RuntimeOperationsException(iae, msg);
0751                }
0752
0753                for (int i = 0; i < fieldNames.length; i++) {
0754                    if ((fieldNames[i] == null) || (fieldNames[i].equals(""))) {
0755                        if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0756                            MODELMBEAN_LOGGER.logp(Level.FINEST,
0757                                    DescriptorSupport.class.getName(),
0758                                    "setFields(fieldNames,fieldValues)",
0759                                    "Null field name encountered at element "
0760                                            + i);
0761                        }
0762                        final String msg = "fieldNames is null or invalid";
0763                        final RuntimeException iae = new IllegalArgumentException(
0764                                msg);
0765                        throw new RuntimeOperationsException(iae, msg);
0766                    }
0767                    setField(fieldNames[i], fieldValues[i]);
0768                }
0769                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0770                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0771                            DescriptorSupport.class.getName(),
0772                            "setFields(fieldNames,fieldValues)", "Exit");
0773                }
0774            }
0775
0776            /**
0777             * Returns a new Descriptor which is a duplicate of the Descriptor.
0778             *
0779             * @exception RuntimeOperationsException for illegal value for
0780             * field Names or field Values.  If the descriptor construction
0781             * fails for any reason, this exception will be thrown.
0782             */
0783
0784            public synchronized Object clone()
0785                    throws RuntimeOperationsException {
0786                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0787                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0788                            DescriptorSupport.class.getName(), "clone()",
0789                            "Entry");
0790                }
0791                return (new DescriptorSupport(this ));
0792            }
0793
0794            public synchronized void removeField(String fieldName) {
0795                if ((fieldName == null) || (fieldName.equals(""))) {
0796                    return;
0797                }
0798
0799                descriptorMap.remove(fieldName);
0800            }
0801
0802            /**
0803             * Compares this descriptor to the given object.  The objects are equal if
0804             * the given object is also a Descriptor, and if the two Descriptors have
0805             * the same field names (possibly differing in case) and the same
0806             * associated values.  The respective values for a field in the two
0807             * Descriptors are equal if the following conditions hold:</p>
0808             * 
0809             * <ul>
0810             * <li>If one value is null then the other must be too.</li>
0811             * <li>If one value is a primitive array then the other must be a primitive
0812             * array of the same type with the same elements.</li>
0813             * <li>If one value is an object array then the other must be too and
0814             * {@link java.util.Arrays#deepEquals(Object[],Object[]) Arrays.deepEquals} 
0815             * must return true.</li>
0816             * <li>Otherwise {@link Object#equals(Object)} must return true.</li>
0817             * </ul>
0818             *
0819             * @param o the object to compare with.
0820             *
0821             * @return {@code true} if the objects are the same; {@code false}
0822             * otherwise.
0823             *
0824             */
0825            // XXXX TODO: This is not very efficient! 
0826            // Note: this Javadoc is copied from javax.management.Descriptor
0827            //       due to 6369229.
0828            public synchronized boolean equals(Object o) {
0829                if (o == this )
0830                    return true;
0831
0832                return new ImmutableDescriptor(descriptorMap).equals(o);
0833            }
0834
0835            /**
0836             * <p>Returns the hash code value for this descriptor.  The hash
0837             * code is computed as the sum of the hash codes for each field in
0838             * the descriptor.  The hash code of a field with name {@code n}
0839             * and value {@code v} is {@code n.toLowerCase().hashCode() ^ h}.
0840             * Here {@code h} is the hash code of {@code v}, computed as
0841             * follows:</p>
0842             * 
0843             * <ul>
0844             * <li>If {@code v} is null then {@code h} is 0.</li>
0845             * <li>If {@code v} is a primitive array then {@code h} is computed using
0846             * the appropriate overloading of {@code java.util.Arrays.hashCode}.</li>
0847             * <li>If {@code v} is an object array then {@code h} is computed using
0848             * {@link java.util.Arrays#deepHashCode(Object[]) Arrays.deepHashCode}.</li>
0849             * <li>Otherwise {@code h} is {@code v.hashCode()}.</li>
0850             * </ul>
0851             *
0852             * @return A hash code value for this object.
0853             *
0854             */
0855            // XXXX TODO: This is not very efficient! 
0856            // Note: this Javadoc is copied from javax.management.Descriptor
0857            //       due to 6369229.
0858            public synchronized int hashCode() {
0859                return new ImmutableDescriptor(descriptorMap).hashCode();
0860            }
0861
0862            /**
0863             * Returns true if all of the fields have legal values given their
0864             * names.
0865             * <P>
0866             * This implementation does not support  interoperating with a directory
0867             * or lookup service. Thus, conforming to the specification, no checking is
0868             * done on the <i>"export"</i> field.
0869             * <P>
0870             * Otherwise this implementation returns false if:
0871             * <P>
0872             * <UL>
0873             * <LI> name and descriptorType fieldNames are not defined, or
0874             * null, or empty, or not String
0875             * <LI> class, role, getMethod, setMethod fieldNames, if defined,
0876             * are null or not String
0877             * <LI> persistPeriod, currencyTimeLimit, lastUpdatedTimeStamp,
0878             * lastReturnedTimeStamp if defined, are null, or not a Numeric
0879             * String or not a Numeric Value >= -1
0880             * <LI> log fieldName, if defined, is null, or not a Boolean or
0881             * not a String with value "t", "f", "true", "false". These String
0882             * values must not be case sensitive.
0883             * <LI> visibility fieldName, if defined, is null, or not a
0884             * Numeric String or a not Numeric Value >= 1 and <= 4
0885             * <LI> severity fieldName, if defined, is null, or not a Numeric
0886             * String or not a Numeric Value >= 0 and <= 6<br>
0887             * <LI> persistPolicy fieldName, if defined, is null, or not one of
0888             * the following strings:<br>
0889             *   "OnUpdate", "OnTimer", "NoMoreOftenThan", "OnUnregister", "Always",
0890             *   "Never". These String values must not be case sensitive.<br>
0891             * </UL>
0892             *
0893             * @exception RuntimeOperationsException If the validity checking
0894             * fails for any reason, this exception will be thrown.
0895             */
0896
0897            public synchronized boolean isValid()
0898                    throws RuntimeOperationsException {
0899                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0900                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0901                            DescriptorSupport.class.getName(), "isValid()",
0902                            "Entry");
0903                }
0904                // verify that the descriptor is valid, by iterating over each field...
0905
0906                Set returnedSet = descriptorMap.entrySet();
0907
0908                if (returnedSet == null) { // null descriptor, not valid
0909                    if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0910                        MODELMBEAN_LOGGER.logp(Level.FINEST,
0911                                DescriptorSupport.class.getName(), "isValid()",
0912                                "Returns false (null set)");
0913                    }
0914                    return false;
0915                }
0916                // must have a name and descriptor type field
0917                String this Name = (String) (this .getFieldValue("name"));
0918                String this DescType = (String) (getFieldValue("descriptorType"));
0919
0920                if ((this Name == null) || (this DescType == null)
0921                        || (this Name.equals("")) || (this DescType.equals(""))) {
0922                    return false;
0923                }
0924
0925                // According to the descriptor type we validate the fields contained
0926
0927                for (Iterator iter = returnedSet.iterator(); iter.hasNext();) {
0928                    Map.Entry currElement = (Map.Entry) iter.next();
0929
0930                    if (currElement != null) {
0931                        if (currElement.getValue() != null) {
0932                            // validate the field valued...
0933                            if (validateField(
0934                                    (currElement.getKey()).toString(),
0935                                    (currElement.getValue()).toString())) {
0936                                continue;
0937                            } else {
0938                                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0939                                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0940                                            DescriptorSupport.class.getName(),
0941                                            "isValid()", "Field "
0942                                                    + currElement.getKey()
0943                                                    + "="
0944                                                    + currElement.getValue()
0945                                                    + " is not valid");
0946                                }
0947                                return false;
0948                            }
0949                        }
0950                    }
0951                }
0952
0953                // fell through, all fields OK
0954                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
0955                    MODELMBEAN_LOGGER.logp(Level.FINEST,
0956                            DescriptorSupport.class.getName(), "isValid()",
0957                            "Returns true");
0958                }
0959                return true;
0960            }
0961
0962            // worker routine for isValid()
0963            // name is not null
0964            // descriptorType is not null
0965            // getMethod and setMethod are not null
0966            // persistPeriod is numeric
0967            // currencyTimeLimit is numeric
0968            // lastUpdatedTimeStamp is numeric
0969            // visibility is 1-4
0970            // severity is 0-6
0971            // log is T or F
0972            // role is not null
0973            // class is not null
0974            // lastReturnedTimeStamp is numeric
0975
0976            private boolean validateField(String fldName, Object fldValue) {
0977                if ((fldName == null) || (fldName.equals("")))
0978                    return false;
0979                String SfldValue = "";
0980                boolean isAString = false;
0981                if ((fldValue != null)
0982                        && (fldValue instanceof  java.lang.String)) {
0983                    SfldValue = (String) fldValue;
0984                    isAString = true;
0985                }
0986
0987                boolean nameOrDescriptorType = (fldName
0988                        .equalsIgnoreCase("Name") || fldName
0989                        .equalsIgnoreCase("DescriptorType"));
0990                if (nameOrDescriptorType
0991                        || fldName.equalsIgnoreCase("SetMethod")
0992                        || fldName.equalsIgnoreCase("GetMethod")
0993                        || fldName.equalsIgnoreCase("Role")
0994                        || fldName.equalsIgnoreCase("Class")) {
0995                    if (fldValue == null || !isAString)
0996                        return false;
0997                    if (nameOrDescriptorType && SfldValue.equals(""))
0998                        return false;
0999                    return true;
1000                } else if (fldName.equalsIgnoreCase("visibility")) {
1001                    long v;
1002                    if ((fldValue != null) && (isAString)) {
1003                        v = toNumeric(SfldValue);
1004                    } else if (fldValue instanceof  java.lang.Integer) {
1005                        v = ((Integer) fldValue).intValue();
1006                    } else
1007                        return false;
1008
1009                    if (v >= 1 && v <= 4)
1010                        return true;
1011                    else
1012                        return false;
1013                } else if (fldName.equalsIgnoreCase("severity")) {
1014
1015                    long v;
1016                    if ((fldValue != null) && (isAString)) {
1017                        v = toNumeric(SfldValue);
1018                    } else if (fldValue instanceof  java.lang.Integer) {
1019                        v = ((Integer) fldValue).intValue();
1020                    } else
1021                        return false;
1022
1023                    return (v >= 0 && v <= 6);
1024                } else if (fldName.equalsIgnoreCase("PersistPolicy")) {
1025                    return (((fldValue != null) && (isAString)) && (SfldValue
1026                            .equalsIgnoreCase("OnUpdate")
1027                            || SfldValue.equalsIgnoreCase("OnTimer")
1028                            || SfldValue.equalsIgnoreCase("NoMoreOftenThan")
1029                            || SfldValue.equalsIgnoreCase("Always")
1030                            || SfldValue.equalsIgnoreCase("Never") || SfldValue
1031                            .equalsIgnoreCase("OnUnregister")));
1032                } else if (fldName.equalsIgnoreCase("PersistPeriod")
1033                        || fldName.equalsIgnoreCase("CurrencyTimeLimit")
1034                        || fldName.equalsIgnoreCase("LastUpdatedTimeStamp")
1035                        || fldName.equalsIgnoreCase("LastReturnedTimeStamp")) {
1036
1037                    long v;
1038                    if ((fldValue != null) && (isAString)) {
1039                        v = toNumeric(SfldValue);
1040                    } else if (fldValue instanceof  java.lang.Number) {
1041                        v = ((Number) fldValue).longValue();
1042                    } else
1043                        return false;
1044
1045                    return (v >= -1);
1046                } else if (fldName.equalsIgnoreCase("log")) {
1047                    return ((fldValue instanceof  java.lang.Boolean) || (isAString && (SfldValue
1048                            .equalsIgnoreCase("T")
1049                            || SfldValue.equalsIgnoreCase("true")
1050                            || SfldValue.equalsIgnoreCase("F") || SfldValue
1051                            .equalsIgnoreCase("false"))));
1052                }
1053
1054                // default to true, it is a field we aren't validating (user etc.)
1055                return true;
1056            }
1057
1058            /**
1059             * <p>Returns an XML String representing the descriptor.</p>
1060             *
1061             * <p>The format is not defined, but an implementation must
1062             * ensure that the string returned by this method can be
1063             * used to build an equivalent descriptor when instantiated
1064             * using the constructor {@link #DescriptorSupport(String)
1065             * DescriptorSupport(String inStr)}.</p>
1066             *
1067             * <p>Fields which are not String objects will have toString()
1068             * called on them to create the value. The value will be
1069             * enclosed in parentheses.  It is not guaranteed that you can
1070             * reconstruct these objects unless they have been
1071             * specifically set up to support toString() in a meaningful
1072             * format and have a matching constructor that accepts a
1073             * String in the same format.</p>
1074             *
1075             * <p>If the descriptor is empty the following String is
1076             * returned: &lt;Descriptor&gt;&lt;/Descriptor&gt;</p>
1077             *
1078             * @return the XML string.
1079             *
1080             * @exception RuntimeOperationsException for illegal value for
1081             * field Names or field Values.  If the XML formatted string
1082             * construction fails for any reason, this exception will be
1083             * thrown.
1084             */
1085            public synchronized String toXMLString() {
1086                final StringBuilder buf = new StringBuilder("<Descriptor>");
1087                Set returnedSet = descriptorMap.entrySet();
1088                for (Iterator iter = returnedSet.iterator(); iter.hasNext();) {
1089                    final Map.Entry currElement = (Map.Entry) iter.next();
1090                    final String name = currElement.getKey().toString();
1091                    Object value = currElement.getValue();
1092                    String valueString = null;
1093                    /* Set valueString to non-null if and only if this is a string that
1094                       cannot be confused with the encoding of an object.  If it
1095                       could be so confused (surrounded by parentheses) then we
1096                       call makeFieldValue as for any non-String object and end
1097                       up with an encoding like "(java.lang.String/(thing))".  */
1098                    if (value instanceof  String) {
1099                        final String svalue = (String) value;
1100                        if (!svalue.startsWith("(") || !svalue.endsWith(")"))
1101                            valueString = quote(svalue);
1102                    }
1103                    if (valueString == null)
1104                        valueString = makeFieldValue(value);
1105                    buf.append("<field name=\"").append(name).append(
1106                            "\" value=\"").append(valueString).append(
1107                            "\"></field>");
1108                }
1109                buf.append("</Descriptor>");
1110                return buf.toString();
1111            }
1112
1113            private static final String[] entities = { " &#32;", "\"&quot;",
1114                    "<&lt;", ">&gt;", "&&amp;", "\r&#13;", "\t&#9;", "\n&#10;",
1115                    "\f&#12;", };
1116            private static final Map<String, Character> entityToCharMap = new HashMap<String, Character>();
1117            private static final String[] charToEntityMap;
1118
1119            static {
1120                char maxChar = 0;
1121                for (int i = 0; i < entities.length; i++) {
1122                    final char c = entities[i].charAt(0);
1123                    if (c > maxChar)
1124                        maxChar = c;
1125                }
1126                charToEntityMap = new String[maxChar + 1];
1127                for (int i = 0; i < entities.length; i++) {
1128                    final char c = entities[i].charAt(0);
1129                    final String entity = entities[i].substring(1);
1130                    charToEntityMap[c] = entity;
1131                    entityToCharMap.put(entity, new Character(c));
1132                }
1133            }
1134
1135            private static boolean isMagic(char c) {
1136                return (c < charToEntityMap.length && charToEntityMap[c] != null);
1137            }
1138
1139            /*
1140             * Quote the string so that it will be acceptable to the (String)
1141             * constructor.  Since the parsing code in that constructor is fairly
1142             * stupid, we're obliged to quote apparently innocuous characters like
1143             * space, <, and >.  In a future version, we should rewrite the parser
1144             * and only quote " plus either \ or & (depending on the quote syntax).
1145             */
1146            private static String quote(String s) {
1147                boolean found = false;
1148                for (int i = 0; i < s.length(); i++) {
1149                    if (isMagic(s.charAt(i))) {
1150                        found = true;
1151                        break;
1152                    }
1153                }
1154                if (!found)
1155                    return s;
1156                final StringBuilder buf = new StringBuilder();
1157                for (int i = 0; i < s.length(); i++) {
1158                    char c = s.charAt(i);
1159                    if (isMagic(c))
1160                        buf.append(charToEntityMap[c]);
1161                    else
1162                        buf.append(c);
1163                }
1164                return buf.toString();
1165            }
1166
1167            private static String unquote(String s) throws XMLParseException {
1168                if (!s.startsWith("\"") || !s.endsWith("\""))
1169                    throw new XMLParseException("Value must be quoted: <" + s
1170                            + ">");
1171                final StringBuilder buf = new StringBuilder();
1172                final int len = s.length() - 1;
1173                for (int i = 1; i < len; i++) {
1174                    final char c = s.charAt(i);
1175                    final int semi;
1176                    final Character quoted;
1177                    if (c == '&'
1178                            && (semi = s.indexOf(';', i + 1)) >= 0
1179                            && ((quoted = entityToCharMap.get(s.substring(i,
1180                                    semi + 1))) != null)) {
1181                        buf.append(quoted);
1182                        i = semi;
1183                    } else
1184                        buf.append(c);
1185                }
1186                return buf.toString();
1187            }
1188
1189            /**
1190             * Make the string that will go inside "..." for a value that is not
1191             * a plain String.
1192             * @throws RuntimeOperationsException if the value cannot be encoded.
1193             */
1194            private static String makeFieldValue(Object value) {
1195                if (value == null)
1196                    return "(null)";
1197
1198                Class<?> valueClass = value.getClass();
1199                try {
1200                    valueClass.getConstructor(String.class);
1201                } catch (NoSuchMethodException e) {
1202                    final String msg = "Class " + valueClass
1203                            + " does not have a public "
1204                            + "constructor with a single string arg";
1205                    final RuntimeException iae = new IllegalArgumentException(
1206                            msg);
1207                    throw new RuntimeOperationsException(iae,
1208                            "Cannot make XML descriptor");
1209                } catch (SecurityException e) {
1210                    // OK: we'll pretend the constructor is there
1211                    // too bad if it's not: we'll find out when we try to
1212                    // reconstruct the DescriptorSupport
1213                }
1214
1215                final String quotedValueString = quote(value.toString());
1216
1217                return "(" + valueClass.getName() + "/" + quotedValueString
1218                        + ")";
1219            }
1220
1221            /*
1222             * Parse a field value from the XML produced by toXMLString().
1223             * Given a descriptor XML containing <field name="nnn" value="vvv">,
1224             * the argument to this method will be "vvv" (a string including the
1225             * containing quote characters).  If vvv begins and ends with parentheses,
1226             * then it may contain:
1227             * - the characters "null", in which case the result is null;
1228             * - a value of the form "some.class.name/xxx", in which case the
1229             * result is equivalent to `new some.class.name("xxx")';
1230             * - some other string, in which case the result is that string,
1231             * without the parentheses.
1232             */
1233            private static Object parseQuotedFieldValue(String s)
1234                    throws XMLParseException {
1235                s = unquote(s);
1236                if (s.equalsIgnoreCase("(null)"))
1237                    return null;
1238                if (!s.startsWith("(") || !s.endsWith(")"))
1239                    return s;
1240                final int slash = s.indexOf('/');
1241                if (slash < 0) {
1242                    // compatibility: old code didn't include class name
1243                    return s.substring(1, s.length() - 1);
1244                }
1245                final String className = s.substring(1, slash);
1246                final Constructor<?> constr;
1247                try {
1248                    final ClassLoader contextClassLoader = Thread
1249                            .currentThread().getContextClassLoader();
1250                    if (contextClassLoader == null) {
1251                        ReflectUtil.checkPackageAccess(className);
1252                    }
1253                    final Class<?> c = Class.forName(className, false,
1254                            contextClassLoader);
1255                    constr = c.getConstructor(new Class[] { String.class });
1256                } catch (Exception e) {
1257                    throw new XMLParseException(e, "Cannot parse value: <" + s
1258                            + ">");
1259                }
1260                final String arg = s.substring(slash + 1, s.length() - 1);
1261                try {
1262                    return constr.newInstance(new Object[] { arg });
1263                } catch (Exception e) {
1264                    final String msg = "Cannot construct instance of "
1265                            + className + " with arg: <" + s + ">";
1266                    throw new XMLParseException(e, msg);
1267                }
1268            }
1269
1270            /**
1271             * Returns <pv>a human readable string representing the
1272             * descriptor</pv>.  The string will be in the format of
1273             * "fieldName=fieldValue,fieldName2=fieldValue2,..."<br>
1274             *
1275             * If there are no fields in the descriptor, then an empty String
1276             * is returned.<br>
1277             *
1278             * If a fieldValue is an object then the toString() method is
1279             * called on it and its returned value is used as the value for
1280             * the field enclosed in parenthesis.
1281             *
1282             * @exception RuntimeOperationsException for illegal value for
1283             * field Names or field Values.  If the descriptor string fails
1284             * for any reason, this exception will be thrown.
1285             */
1286            public synchronized String toString() {
1287                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
1288                    MODELMBEAN_LOGGER.logp(Level.FINEST,
1289                            DescriptorSupport.class.getName(), "toString()",
1290                            "Entry");
1291                }
1292
1293                String respStr = "";
1294                String[] fields = getFields();
1295
1296                if ((fields == null) || (fields.length == 0)) {
1297                    if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
1298                        MODELMBEAN_LOGGER.logp(Level.FINEST,
1299                                DescriptorSupport.class.getName(),
1300                                "toString()", "Empty Descriptor");
1301                    }
1302                    return respStr;
1303                }
1304
1305                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
1306                    MODELMBEAN_LOGGER.logp(Level.FINEST,
1307                            DescriptorSupport.class.getName(), "toString()",
1308                            "Printing " + fields.length + " fields");
1309                }
1310
1311                for (int i = 0; i < fields.length; i++) {
1312                    if (i == (fields.length - 1)) {
1313                        respStr = respStr.concat(fields[i]);
1314                    } else {
1315                        respStr = respStr.concat(fields[i] + ", ");
1316                    }
1317                }
1318
1319                if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
1320                    MODELMBEAN_LOGGER.logp(Level.FINEST,
1321                            DescriptorSupport.class.getName(), "toString()",
1322                            "Exit returning " + respStr);
1323                }
1324
1325                return respStr;
1326            }
1327
1328            // utility to convert to int, returns -2 if bogus.
1329
1330            private long toNumeric(String inStr) {
1331                long result = -2;
1332                try {
1333                    result = java.lang.Long.parseLong(inStr);
1334                } catch (Exception e) {
1335                    return -2;
1336                }
1337                return result;
1338            }
1339
1340            /**
1341             * Deserializes a {@link DescriptorSupport} from an {@link
1342             * ObjectInputStream}.
1343             */
1344            private void readObject(ObjectInputStream in) throws IOException,
1345                    ClassNotFoundException {
1346                ObjectInputStream.GetField fields = in.readFields();
1347                Map<String, Object> descriptor = cast(fields.get("descriptor",
1348                        null));
1349                init(null);
1350                if (descriptor != null) {
1351                    descriptorMap.putAll(descriptor);
1352                }
1353            }
1354
1355            /**
1356             * Serializes a {@link DescriptorSupport} to an {@link ObjectOutputStream}.
1357             */
1358            /* If you set jmx.serial.form to "1.2.0" or "1.2.1", then we are
1359               bug-compatible with those versions.  Specifically, field names
1360               are forced to lower-case before being written.  This
1361               contradicts the spec, which, though it does not mention
1362               serialization explicitly, does say that the case of field names
1363               is preserved.  But in 1.2.0 and 1.2.1, this requirement was not
1364               met.  Instead, field names in the descriptor map were forced to
1365               lower case.  Those versions expect this to have happened to a
1366               descriptor they deserialize and e.g. getFieldValue will not
1367               find a field whose name is spelt with a different case.
1368             */
1369            private void writeObject(ObjectOutputStream out) throws IOException {
1370                ObjectOutputStream.PutField fields = out.putFields();
1371                boolean compat = "1.0".equals(serialForm);
1372                if (compat)
1373                    fields.put("currClass", currClass);
1374
1375                /* Purge the field "targetObject" from the DescriptorSupport before
1376                 * serializing since the referenced object is typically not
1377                 * serializable.  We do this here rather than purging the "descriptor"
1378                 * variable below because that HashMap doesn't do case-insensitivity.
1379                 * See CR 6332962.
1380                 */
1381                SortedMap<String, Object> startMap = descriptorMap;
1382                if (startMap.containsKey("targetObject")) {
1383                    startMap = new TreeMap<String, Object>(descriptorMap);
1384                    startMap.remove("targetObject");
1385                }
1386
1387                final HashMap<String, Object> descriptor;
1388                if (compat || "1.2.0".equals(serialForm)
1389                        || "1.2.1".equals(serialForm)) {
1390                    descriptor = new HashMap<String, Object>();
1391                    for (Map.Entry<String, Object> entry : startMap.entrySet())
1392                        descriptor.put(entry.getKey().toLowerCase(), entry
1393                                .getValue());
1394                } else
1395                    descriptor = new HashMap<String, Object>(startMap);
1396
1397                fields.put("descriptor", descriptor);
1398                out.writeFields();
1399            }
1400
1401        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.