1/*
2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25/*
26 * @author    IBM Corp.
27 *
28 * Copyright IBM Corp. 1999-2000.  All rights reserved.
29 */
30
31package javax.management.modelmbean;
32
33import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER;
34import com.sun.jmx.mbeanserver.GetPropertyAction;
35
36import java.io.IOException;
37import java.io.ObjectInputStream;
38import java.io.ObjectOutputStream;
39import java.io.ObjectStreamField;
40import java.security.AccessController;
41import java.lang.System.Logger.Level;
42
43import javax.management.Descriptor;
44import javax.management.MBeanAttributeInfo;
45import javax.management.MBeanConstructorInfo;
46import javax.management.MBeanException;
47import javax.management.MBeanInfo;
48import javax.management.MBeanNotificationInfo;
49import javax.management.MBeanOperationInfo;
50import javax.management.RuntimeOperationsException;
51
52/**
53 * This class represents the meta data for ModelMBeans.  Descriptors have been
54 * added on the meta data objects.
55 * <P>
56 * Java resources wishing to be manageable instantiate the ModelMBean using the
57 * MBeanServer's createMBean method.  The resource then sets the ModelMBeanInfo
58 * and Descriptors for the ModelMBean instance. The attributes and operations
59 * exposed via the ModelMBeanInfo for the ModelMBean are accessible
60 * from MBeans, connectors/adaptors like other MBeans. Through the Descriptors,
61 * values and methods in the managed application can be defined and mapped to
62 * attributes and operations of the ModelMBean.
63 * This mapping can be defined during development in a file or dynamically and
64 * programmatically at runtime.
65 * <P>
66 * Every ModelMBean which is instantiated in the MBeanServer becomes manageable:
67 * its attributes and operations
68 * become remotely accessible through the connectors/adaptors connected to that
69 * MBeanServer.
70 * A Java object cannot be registered in the MBeanServer unless it is a JMX
71 * compliant MBean.
72 * By instantiating a ModelMBean, resources are guaranteed that the MBean is
73 * valid.
74 *
75 * MBeanException and RuntimeOperationsException must be thrown on every public
76 * method.  This allows for wrapping exceptions from distributed
77 * communications (RMI, EJB, etc.)
78 *
79 * <p>The <b>serialVersionUID</b> of this class is
80 * <code>-1935722590756516193L</code>.
81 *
82 * @since 1.5
83 */
84@SuppressWarnings("serial")
85public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo {
86
87    // Serialization compatibility stuff:
88    // Two serial forms are supported in this class. The selected form depends
89    // on system property "jmx.serial.form":
90    //  - "1.0" for JMX 1.0
91    //  - any other value for JMX 1.1 and higher
92    //
93    // Serial version for old serial form
94    private static final long oldSerialVersionUID = -3944083498453227709L;
95    //
96    // Serial version for new serial form
97    private static final long newSerialVersionUID = -1935722590756516193L;
98    //
99    // Serializable fields in old serial form
100    private static final ObjectStreamField[] oldSerialPersistentFields =
101    {
102        new ObjectStreamField("modelMBeanDescriptor", Descriptor.class),
103                new ObjectStreamField("mmbAttributes", MBeanAttributeInfo[].class),
104                new ObjectStreamField("mmbConstructors", MBeanConstructorInfo[].class),
105                new ObjectStreamField("mmbNotifications", MBeanNotificationInfo[].class),
106                new ObjectStreamField("mmbOperations", MBeanOperationInfo[].class),
107                new ObjectStreamField("currClass", String.class)
108    };
109    //
110    // Serializable fields in new serial form
111    private static final ObjectStreamField[] newSerialPersistentFields =
112    {
113        new ObjectStreamField("modelMBeanDescriptor", Descriptor.class),
114                new ObjectStreamField("modelMBeanAttributes", MBeanAttributeInfo[].class),
115                new ObjectStreamField("modelMBeanConstructors", MBeanConstructorInfo[].class),
116                new ObjectStreamField("modelMBeanNotifications", MBeanNotificationInfo[].class),
117                new ObjectStreamField("modelMBeanOperations", MBeanOperationInfo[].class)
118    };
119    //
120    // Actual serial version and serial form
121    private static final long serialVersionUID;
122    /**
123     * @serialField modelMBeanDescriptor Descriptor The descriptor containing
124     *              MBean wide policy
125     * @serialField modelMBeanAttributes ModelMBeanAttributeInfo[] The array of
126     *              {@link ModelMBeanAttributeInfo} objects which
127     *              have descriptors
128     * @serialField modelMBeanConstructors MBeanConstructorInfo[] The array of
129     *              {@link ModelMBeanConstructorInfo} objects which
130     *              have descriptors
131     * @serialField modelMBeanNotifications MBeanNotificationInfo[] The array of
132     *              {@link ModelMBeanNotificationInfo} objects which
133     *              have descriptors
134     * @serialField modelMBeanOperations MBeanOperationInfo[] The array of
135     *              {@link ModelMBeanOperationInfo} objects which
136     *              have descriptors
137     */
138    private static final ObjectStreamField[] serialPersistentFields;
139    private static boolean compat = false;
140    static {
141        try {
142            GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
143            String form = AccessController.doPrivileged(act);
144            compat = (form != null && form.equals("1.0"));
145        } catch (Exception e) {
146            // OK: No compat with 1.0
147        }
148        if (compat) {
149            serialPersistentFields = oldSerialPersistentFields;
150            serialVersionUID = oldSerialVersionUID;
151        } else {
152            serialPersistentFields = newSerialPersistentFields;
153            serialVersionUID = newSerialVersionUID;
154        }
155    }
156    //
157    // END Serialization compatibility stuff
158
159    /**
160     * @serial The descriptor containing MBean wide policy
161     */
162    private Descriptor modelMBeanDescriptor = null;
163
164    /* The following fields always have the same values as the
165       fields inherited from MBeanInfo and are retained only for
166       compatibility.  By rewriting the serialization code we could
167       get rid of them.
168
169       These fields can't be final because they are assigned to by
170       readObject().  */
171
172    /**
173     * @serial The array of {@link ModelMBeanAttributeInfo} objects which
174     *         have descriptors
175     */
176    private MBeanAttributeInfo[] modelMBeanAttributes;
177
178    /**
179     * @serial The array of {@link ModelMBeanConstructorInfo} objects which
180     *         have descriptors
181     */
182    private MBeanConstructorInfo[] modelMBeanConstructors;
183
184    /**
185     * @serial The array of {@link ModelMBeanNotificationInfo} objects which
186     *         have descriptors
187     */
188    private MBeanNotificationInfo[] modelMBeanNotifications;
189
190    /**
191     * @serial The array of {@link ModelMBeanOperationInfo} objects which
192     *         have descriptors
193     */
194    private MBeanOperationInfo[] modelMBeanOperations;
195
196    private static final String ATTR = "attribute";
197    private static final String OPER = "operation";
198    private static final String NOTF = "notification";
199    private static final String CONS = "constructor";
200    private static final String MMB = "mbean";
201    private static final String ALL = "all";
202    private static final String currClass = "ModelMBeanInfoSupport";
203
204    /**
205     * Constructs a ModelMBeanInfoSupport which is a duplicate of the given
206     * ModelMBeanInfo.  The returned object is a shallow copy of the given
207     * object.  Neither the Descriptor nor the contained arrays
208     * ({@code ModelMBeanAttributeInfo[]} etc) are cloned.  This method is
209     * chiefly of interest to modify the Descriptor of the returned instance
210     * via {@link #setDescriptor setDescriptor} without affecting the
211     * Descriptor of the original object.
212     *
213     * @param mbi the ModelMBeanInfo instance from which the ModelMBeanInfo
214     * being created is initialized.
215     */
216    public ModelMBeanInfoSupport(ModelMBeanInfo  mbi) {
217        super(mbi.getClassName(),
218                mbi.getDescription(),
219                mbi.getAttributes(),
220                mbi.getConstructors(),
221                mbi.getOperations(),
222                mbi.getNotifications());
223
224        modelMBeanAttributes = mbi.getAttributes();
225        modelMBeanConstructors = mbi.getConstructors();
226        modelMBeanOperations = mbi.getOperations();
227        modelMBeanNotifications = mbi.getNotifications();
228
229        try {
230            Descriptor mbeandescriptor = mbi.getMBeanDescriptor();
231            modelMBeanDescriptor = validDescriptor(mbeandescriptor);
232        } catch (MBeanException mbe) {
233            modelMBeanDescriptor = validDescriptor(null);
234            if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
235                MODELMBEAN_LOGGER.log(Level.TRACE,
236                        "ModelMBeanInfo(ModelMBeanInfo) " +
237                        "Could not get a valid modelMBeanDescriptor, " +
238                        "setting a default Descriptor");
239            }
240        }
241
242        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
243            MODELMBEAN_LOGGER.log(Level.TRACE, "Exit");
244        }
245    }
246
247    /**
248     * Creates a ModelMBeanInfoSupport with the provided information,
249     * but the descriptor is a default.
250     * The default descriptor is: name=className, descriptorType="mbean",
251     * displayName=className, persistPolicy="never", log="F", visibility="1"
252     *
253     * @param className classname of the MBean
254     * @param description human readable description of the
255     * ModelMBean
256     * @param attributes array of ModelMBeanAttributeInfo objects
257     * which have descriptors
258     * @param constructors array of ModelMBeanConstructorInfo
259     * objects which have descriptors
260     * @param operations array of ModelMBeanOperationInfo objects
261     * which have descriptors
262     * @param notifications array of ModelMBeanNotificationInfo
263     * objects which have descriptors
264     */
265    public ModelMBeanInfoSupport(String className,
266            String description,
267            ModelMBeanAttributeInfo[] attributes,
268            ModelMBeanConstructorInfo[] constructors,
269            ModelMBeanOperationInfo[] operations,
270            ModelMBeanNotificationInfo[] notifications) {
271        this(className, description, attributes, constructors,
272                operations, notifications, null);
273    }
274
275    /**
276     * Creates a ModelMBeanInfoSupport with the provided information
277     * and the descriptor given in parameter.
278     *
279     * @param className classname of the MBean
280     * @param description human readable description of the
281     * ModelMBean
282     * @param attributes array of ModelMBeanAttributeInfo objects
283     * which have descriptors
284     * @param constructors array of ModelMBeanConstructorInfo
285     * objects which have descriptor
286     * @param operations array of ModelMBeanOperationInfo objects
287     * which have descriptor
288     * @param notifications array of ModelMBeanNotificationInfo
289     * objects which have descriptor
290     * @param mbeandescriptor descriptor to be used as the
291     * MBeanDescriptor containing MBean wide policy. If the
292     * descriptor is null, a default descriptor will be constructed.
293     * The default descriptor is:
294     * name=className, descriptorType="mbean", displayName=className,
295     * persistPolicy="never", log="F", visibility="1".  If the descriptor
296     * does not contain all of these fields, the missing ones are
297     * added with these default values.
298     *
299     * @exception RuntimeOperationsException Wraps an
300     * IllegalArgumentException for invalid descriptor passed in
301     * parameter.  (see {@link #getMBeanDescriptor
302     * getMBeanDescriptor} for the definition of a valid MBean
303     * descriptor.)
304     */
305
306    public ModelMBeanInfoSupport(String    className,
307            String description,
308            ModelMBeanAttributeInfo[] attributes,
309            ModelMBeanConstructorInfo[] constructors,
310            ModelMBeanOperationInfo[] operations,
311            ModelMBeanNotificationInfo[] notifications,
312            Descriptor mbeandescriptor) {
313        super(className,
314                description,
315                (attributes != null) ? attributes : NO_ATTRIBUTES,
316                (constructors != null) ? constructors : NO_CONSTRUCTORS,
317                (operations != null) ? operations : NO_OPERATIONS,
318                (notifications != null) ? notifications : NO_NOTIFICATIONS);
319        /* The values saved here are possibly null, but we
320           check this everywhere they are referenced.  If at
321           some stage we replace null with an empty array
322           here, as we do in the superclass constructor
323           parameters, then we must also do this in
324           readObject().  */
325        modelMBeanAttributes = attributes;
326        modelMBeanConstructors = constructors;
327        modelMBeanOperations = operations;
328        modelMBeanNotifications = notifications;
329        modelMBeanDescriptor = validDescriptor(mbeandescriptor);
330        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
331            MODELMBEAN_LOGGER.log(Level.TRACE,
332                    "ModelMBeanInfoSupport(String,String,ModelMBeanAttributeInfo[]," +
333                    "ModelMBeanConstructorInfo[],ModelMBeanOperationInfo[]," +
334                    "ModelMBeanNotificationInfo[],Descriptor) " +
335                    "Exit");
336        }
337    }
338
339    private static final ModelMBeanAttributeInfo[] NO_ATTRIBUTES =
340            new ModelMBeanAttributeInfo[0];
341    private static final ModelMBeanConstructorInfo[] NO_CONSTRUCTORS =
342            new ModelMBeanConstructorInfo[0];
343    private static final ModelMBeanNotificationInfo[] NO_NOTIFICATIONS =
344            new ModelMBeanNotificationInfo[0];
345    private static final ModelMBeanOperationInfo[] NO_OPERATIONS =
346            new ModelMBeanOperationInfo[0];
347
348    // Java doc inherited from MOdelMBeanInfo interface
349
350    /**
351     * Returns a shallow clone of this instance.  Neither the Descriptor nor
352     * the contained arrays ({@code ModelMBeanAttributeInfo[]} etc) are
353     * cloned.  This method is chiefly of interest to modify the Descriptor
354     * of the clone via {@link #setDescriptor setDescriptor} without affecting
355     * the Descriptor of the original object.
356     *
357     * @return a shallow clone of this instance.
358     */
359    public Object clone() {
360        return(new ModelMBeanInfoSupport(this));
361    }
362
363
364    public Descriptor[] getDescriptors(String inDescriptorType)
365    throws MBeanException, RuntimeOperationsException {
366        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
367            MODELMBEAN_LOGGER.log(Level.TRACE, "Entry");
368        }
369
370        if ((inDescriptorType == null) || (inDescriptorType.equals(""))) {
371            inDescriptorType = "all";
372        }
373
374        // if no descriptors of that type, will return empty array
375        //
376        final Descriptor[] retList;
377
378        if (inDescriptorType.equalsIgnoreCase(MMB)) {
379            retList = new Descriptor[] {modelMBeanDescriptor};
380        } else if (inDescriptorType.equalsIgnoreCase(ATTR)) {
381            final MBeanAttributeInfo[] attrList = modelMBeanAttributes;
382            int numAttrs = 0;
383            if (attrList != null) numAttrs = attrList.length;
384
385            retList = new Descriptor[numAttrs];
386            for (int i=0; i < numAttrs; i++) {
387                retList[i] = (((ModelMBeanAttributeInfo)
388                    attrList[i]).getDescriptor());
389            }
390        } else if (inDescriptorType.equalsIgnoreCase(OPER)) {
391            final MBeanOperationInfo[] operList = modelMBeanOperations;
392            int numOpers = 0;
393            if (operList != null) numOpers = operList.length;
394
395            retList = new Descriptor[numOpers];
396            for (int i=0; i < numOpers; i++) {
397                retList[i] = (((ModelMBeanOperationInfo)
398                    operList[i]).getDescriptor());
399            }
400        } else if (inDescriptorType.equalsIgnoreCase(CONS)) {
401            final MBeanConstructorInfo[] consList =  modelMBeanConstructors;
402            int numCons = 0;
403            if (consList != null) numCons = consList.length;
404
405            retList = new Descriptor[numCons];
406            for (int i=0; i < numCons; i++) {
407                retList[i] = (((ModelMBeanConstructorInfo)
408                    consList[i]).getDescriptor());
409            }
410        } else if (inDescriptorType.equalsIgnoreCase(NOTF)) {
411            final MBeanNotificationInfo[] notifList = modelMBeanNotifications;
412            int numNotifs = 0;
413            if (notifList != null) numNotifs = notifList.length;
414
415            retList = new Descriptor[numNotifs];
416            for (int i=0; i < numNotifs; i++) {
417                retList[i] = (((ModelMBeanNotificationInfo)
418                    notifList[i]).getDescriptor());
419            }
420        } else if (inDescriptorType.equalsIgnoreCase(ALL)) {
421
422            final MBeanAttributeInfo[] attrList = modelMBeanAttributes;
423            int numAttrs = 0;
424            if (attrList != null) numAttrs = attrList.length;
425
426            final MBeanOperationInfo[] operList = modelMBeanOperations;
427            int numOpers = 0;
428            if (operList != null) numOpers = operList.length;
429
430            final MBeanConstructorInfo[] consList = modelMBeanConstructors;
431            int numCons = 0;
432            if (consList != null) numCons = consList.length;
433
434            final MBeanNotificationInfo[] notifList = modelMBeanNotifications;
435            int numNotifs = 0;
436            if (notifList != null) numNotifs = notifList.length;
437
438            int count = numAttrs + numCons + numOpers + numNotifs + 1;
439            retList = new Descriptor[count];
440
441            retList[count-1] = modelMBeanDescriptor;
442
443            int j=0;
444            for (int i=0; i < numAttrs; i++) {
445                retList[j] = (((ModelMBeanAttributeInfo)
446                    attrList[i]).getDescriptor());
447                j++;
448            }
449            for (int i=0; i < numCons; i++) {
450                retList[j] = (((ModelMBeanConstructorInfo)
451                    consList[i]).getDescriptor());
452                j++;
453            }
454            for (int i=0; i < numOpers; i++) {
455                retList[j] = (((ModelMBeanOperationInfo)operList[i]).
456                        getDescriptor());
457                j++;
458            }
459            for (int i=0; i < numNotifs; i++) {
460                retList[j] = (((ModelMBeanNotificationInfo)notifList[i]).
461                        getDescriptor());
462                j++;
463            }
464        } else {
465            final IllegalArgumentException iae =
466                    new IllegalArgumentException("Descriptor Type is invalid");
467            final String msg = "Exception occurred trying to find"+
468                    " the descriptors of the MBean";
469            throw new RuntimeOperationsException(iae,msg);
470        }
471        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
472            MODELMBEAN_LOGGER.log(Level.TRACE, "Exit");
473        }
474
475        return retList;
476    }
477
478
479    public void setDescriptors(Descriptor[] inDescriptors)
480    throws MBeanException, RuntimeOperationsException {
481        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
482            MODELMBEAN_LOGGER.log(Level.TRACE, "Entry");
483        }
484        if (inDescriptors==null) {
485            // throw RuntimeOperationsException - invalid descriptor
486            throw new RuntimeOperationsException(
487                    new IllegalArgumentException("Descriptor list is invalid"),
488                    "Exception occurred trying to set the descriptors " +
489                    "of the MBeanInfo");
490        }
491        if (inDescriptors.length == 0) { // empty list, no-op
492            return;
493        }
494        for (int j=0; j < inDescriptors.length; j++) {
495            setDescriptor(inDescriptors[j],null);
496        }
497        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
498            MODELMBEAN_LOGGER.log(Level.TRACE, "Exit");
499        }
500
501    }
502
503
504    /**
505     * Returns a Descriptor requested by name.
506     *
507     * @param inDescriptorName The name of the descriptor.
508     *
509     * @return Descriptor containing a descriptor for the ModelMBean with the
510     *         same name. If no descriptor is found, null is returned.
511     *
512     * @exception MBeanException Wraps a distributed communication Exception.
513     * @exception RuntimeOperationsException Wraps an IllegalArgumentException
514     *            for null name.
515     *
516     * @see #setDescriptor
517     */
518
519    public Descriptor getDescriptor(String inDescriptorName)
520    throws MBeanException, RuntimeOperationsException {
521        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
522            MODELMBEAN_LOGGER.log(Level.TRACE, "Entry");
523        }
524        return(getDescriptor(inDescriptorName, null));
525    }
526
527
528    public Descriptor getDescriptor(String inDescriptorName,
529            String inDescriptorType)
530            throws MBeanException, RuntimeOperationsException {
531        if (inDescriptorName==null) {
532            // throw RuntimeOperationsException - invalid descriptor
533            throw new RuntimeOperationsException(
534                    new IllegalArgumentException("Descriptor is invalid"),
535                    "Exception occurred trying to set the descriptors of " +
536                    "the MBeanInfo");
537        }
538
539        if (MMB.equalsIgnoreCase(inDescriptorType)) {
540            return (Descriptor) modelMBeanDescriptor.clone();
541        }
542
543            /* The logic here is a bit convoluted, because we are
544               dealing with two possible cases, depending on whether
545               inDescriptorType is null.  If it's not null, then only
546               one of the following ifs will run, and it will either
547               return a descriptor or null.  If inDescriptorType is
548               null, then all of the following ifs will run until one
549               of them finds a descriptor.  */
550        if (ATTR.equalsIgnoreCase(inDescriptorType) || inDescriptorType == null) {
551            ModelMBeanAttributeInfo attr = getAttribute(inDescriptorName);
552            if (attr != null)
553                return attr.getDescriptor();
554            if (inDescriptorType != null)
555                return null;
556        }
557        if (OPER.equalsIgnoreCase(inDescriptorType) || inDescriptorType == null) {
558            ModelMBeanOperationInfo oper = getOperation(inDescriptorName);
559            if (oper != null)
560                return oper.getDescriptor();
561            if (inDescriptorType != null)
562                return null;
563        }
564        if (CONS.equalsIgnoreCase(inDescriptorType) || inDescriptorType == null) {
565            ModelMBeanConstructorInfo oper =
566                    getConstructor(inDescriptorName);
567            if (oper != null)
568                return oper.getDescriptor();
569            if (inDescriptorType != null)
570                return null;
571        }
572        if (NOTF.equalsIgnoreCase(inDescriptorType) || inDescriptorType == null) {
573            ModelMBeanNotificationInfo notif =
574                    getNotification(inDescriptorName);
575            if (notif != null)
576                return notif.getDescriptor();
577            if (inDescriptorType != null)
578                return null;
579        }
580        if (inDescriptorType == null)
581            return null;
582        throw new RuntimeOperationsException(
583                new IllegalArgumentException("Descriptor Type is invalid"),
584                "Exception occurred trying to find the descriptors of the MBean");
585
586    }
587
588
589
590    public void setDescriptor(Descriptor inDescriptor,
591            String inDescriptorType)
592            throws MBeanException, RuntimeOperationsException {
593        final String excMsg =
594                "Exception occurred trying to set the descriptors of the MBean";
595        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
596            MODELMBEAN_LOGGER.log(Level.TRACE, "Entry");
597        }
598
599        if (inDescriptor==null) {
600            inDescriptor = new DescriptorSupport();
601        }
602
603        if ((inDescriptorType == null) || (inDescriptorType.equals(""))) {
604            inDescriptorType =
605                    (String) inDescriptor.getFieldValue("descriptorType");
606
607            if (inDescriptorType == null) {
608                   MODELMBEAN_LOGGER.log(Level.TRACE,
609                                "descriptorType null in both String parameter " +
610                                "and Descriptor, defaulting to "+ MMB);
611                inDescriptorType = MMB;
612            }
613        }
614
615        String inDescriptorName =
616                (String) inDescriptor.getFieldValue("name");
617        if (inDescriptorName == null) {
618            MODELMBEAN_LOGGER.log(Level.TRACE,
619                                "descriptor name null, defaulting to " +
620                                this.getClassName());
621            inDescriptorName = this.getClassName();
622        }
623        boolean found = false;
624        if (inDescriptorType.equalsIgnoreCase(MMB)) {
625            setMBeanDescriptor(inDescriptor);
626            found = true;
627        } else if (inDescriptorType.equalsIgnoreCase(ATTR)) {
628            MBeanAttributeInfo[] attrList =  modelMBeanAttributes;
629            int numAttrs = 0;
630            if (attrList != null) numAttrs = attrList.length;
631
632            for (int i=0; i < numAttrs; i++) {
633                if (inDescriptorName.equals(attrList[i].getName())) {
634                    found = true;
635                    ModelMBeanAttributeInfo mmbai =
636                            (ModelMBeanAttributeInfo) attrList[i];
637                    mmbai.setDescriptor(inDescriptor);
638                    if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
639                        StringBuilder strb = new StringBuilder()
640                        .append("Setting descriptor to ").append(inDescriptor)
641                        .append("\t\n local: AttributeInfo descriptor is ")
642                        .append(mmbai.getDescriptor())
643                        .append("\t\n modelMBeanInfo: AttributeInfo descriptor is ")
644                        .append(this.getDescriptor(inDescriptorName,"attribute"));
645                        MODELMBEAN_LOGGER.log(Level.TRACE, strb::toString);
646                    }
647                }
648            }
649        } else if (inDescriptorType.equalsIgnoreCase(OPER)) {
650            MBeanOperationInfo[] operList =  modelMBeanOperations;
651            int numOpers = 0;
652            if (operList != null) numOpers = operList.length;
653
654            for (int i=0; i < numOpers; i++) {
655                if (inDescriptorName.equals(operList[i].getName())) {
656                    found = true;
657                    ModelMBeanOperationInfo mmboi =
658                            (ModelMBeanOperationInfo) operList[i];
659                    mmboi.setDescriptor(inDescriptor);
660                }
661            }
662        } else if (inDescriptorType.equalsIgnoreCase(CONS)) {
663            MBeanConstructorInfo[] consList =  modelMBeanConstructors;
664            int numCons = 0;
665            if (consList != null) numCons = consList.length;
666
667            for (int i=0; i < numCons; i++) {
668                if (inDescriptorName.equals(consList[i].getName())) {
669                    found = true;
670                    ModelMBeanConstructorInfo mmbci =
671                            (ModelMBeanConstructorInfo) consList[i];
672                    mmbci.setDescriptor(inDescriptor);
673                }
674            }
675        } else if (inDescriptorType.equalsIgnoreCase(NOTF)) {
676            MBeanNotificationInfo[] notifList =  modelMBeanNotifications;
677            int numNotifs = 0;
678            if (notifList != null) numNotifs = notifList.length;
679
680            for (int i=0; i < numNotifs; i++) {
681                if (inDescriptorName.equals(notifList[i].getName())) {
682                    found = true;
683                    ModelMBeanNotificationInfo mmbni =
684                            (ModelMBeanNotificationInfo) notifList[i];
685                    mmbni.setDescriptor(inDescriptor);
686                }
687            }
688        } else {
689            RuntimeException iae =
690                    new IllegalArgumentException("Invalid descriptor type: " +
691                    inDescriptorType);
692            throw new RuntimeOperationsException(iae, excMsg);
693        }
694
695        if (!found) {
696            RuntimeException iae =
697                    new IllegalArgumentException("Descriptor name is invalid: " +
698                    "type=" + inDescriptorType +
699                    "; name=" + inDescriptorName);
700            throw new RuntimeOperationsException(iae, excMsg);
701        }
702        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
703            MODELMBEAN_LOGGER.log(Level.TRACE, "Exit");
704        }
705
706    }
707
708
709    public ModelMBeanAttributeInfo getAttribute(String inName)
710    throws MBeanException, RuntimeOperationsException {
711        ModelMBeanAttributeInfo retInfo = null;
712        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
713            MODELMBEAN_LOGGER.log(Level.TRACE, "Entry");
714        }
715        if (inName == null) {
716            throw new RuntimeOperationsException(
717                    new IllegalArgumentException("Attribute Name is null"),
718                    "Exception occurred trying to get the " +
719                    "ModelMBeanAttributeInfo of the MBean");
720        }
721        MBeanAttributeInfo[] attrList = modelMBeanAttributes;
722        int numAttrs = 0;
723        if (attrList != null) numAttrs = attrList.length;
724
725        for (int i=0; (i < numAttrs) && (retInfo == null); i++) {
726            if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
727                final StringBuilder strb = new StringBuilder()
728                .append("\t\n this.getAttributes() MBeanAttributeInfo Array ")
729                .append(i).append(":")
730                .append(((ModelMBeanAttributeInfo)attrList[i]).getDescriptor())
731                .append("\t\n this.modelMBeanAttributes MBeanAttributeInfo Array ")
732                .append(i).append(":")
733                .append(((ModelMBeanAttributeInfo)modelMBeanAttributes[i]).getDescriptor());
734                MODELMBEAN_LOGGER.log(Level.TRACE, strb::toString);
735            }
736            if (inName.equals(attrList[i].getName())) {
737                retInfo = ((ModelMBeanAttributeInfo)attrList[i].clone());
738            }
739        }
740        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
741            MODELMBEAN_LOGGER.log(Level.TRACE, "Exit");
742        }
743
744        return retInfo;
745    }
746
747
748
749    public ModelMBeanOperationInfo getOperation(String inName)
750    throws MBeanException, RuntimeOperationsException {
751        ModelMBeanOperationInfo retInfo = null;
752        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
753            MODELMBEAN_LOGGER.log(Level.TRACE, "Entry");
754        }
755        if (inName == null) {
756            throw new RuntimeOperationsException(
757                    new IllegalArgumentException("inName is null"),
758                    "Exception occurred trying to get the " +
759                    "ModelMBeanOperationInfo of the MBean");
760        }
761        MBeanOperationInfo[] operList = modelMBeanOperations; //this.getOperations();
762        int numOpers = 0;
763        if (operList != null) numOpers = operList.length;
764
765        for (int i=0; (i < numOpers) && (retInfo == null); i++) {
766            if (inName.equals(operList[i].getName())) {
767                retInfo = ((ModelMBeanOperationInfo) operList[i].clone());
768            }
769        }
770        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
771            MODELMBEAN_LOGGER.log(Level.TRACE, "Exit");
772        }
773
774        return retInfo;
775    }
776
777    /**
778     * Returns the ModelMBeanConstructorInfo requested by name.
779     * If no ModelMBeanConstructorInfo exists for this name null is returned.
780     *
781     * @param inName the name of the constructor.
782     *
783     * @return the constructor info for the named constructor, or null
784     * if there is none.
785     *
786     * @exception MBeanException Wraps a distributed communication Exception.
787     * @exception RuntimeOperationsException Wraps an IllegalArgumentException
788     *            for a null constructor name.
789     */
790
791    public ModelMBeanConstructorInfo getConstructor(String inName)
792    throws MBeanException, RuntimeOperationsException {
793        ModelMBeanConstructorInfo retInfo = null;
794        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
795            MODELMBEAN_LOGGER.log(Level.TRACE, "Entry");
796        }
797        if (inName == null) {
798            throw new RuntimeOperationsException(
799                    new IllegalArgumentException("Constructor name is null"),
800                    "Exception occurred trying to get the " +
801                    "ModelMBeanConstructorInfo of the MBean");
802        }
803        MBeanConstructorInfo[] consList = modelMBeanConstructors; //this.getConstructors();
804        int numCons = 0;
805        if (consList != null) numCons = consList.length;
806
807        for (int i=0; (i < numCons) && (retInfo == null); i++) {
808            if (inName.equals(consList[i].getName())) {
809                retInfo = ((ModelMBeanConstructorInfo) consList[i].clone());
810            }
811        }
812        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
813            MODELMBEAN_LOGGER.log(Level.TRACE, "Exit");
814        }
815
816        return retInfo;
817    }
818
819
820    public ModelMBeanNotificationInfo getNotification(String inName)
821    throws MBeanException, RuntimeOperationsException {
822        ModelMBeanNotificationInfo retInfo = null;
823        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
824            MODELMBEAN_LOGGER.log(Level.TRACE, "Entry");
825        }
826        if (inName == null) {
827            throw new RuntimeOperationsException(
828                    new IllegalArgumentException("Notification name is null"),
829                    "Exception occurred trying to get the " +
830                    "ModelMBeanNotificationInfo of the MBean");
831        }
832        MBeanNotificationInfo[] notifList = modelMBeanNotifications; //this.getNotifications();
833        int numNotifs = 0;
834        if (notifList != null) numNotifs = notifList.length;
835
836        for (int i=0; (i < numNotifs) && (retInfo == null); i++) {
837            if (inName.equals(notifList[i].getName())) {
838                retInfo = ((ModelMBeanNotificationInfo) notifList[i].clone());
839            }
840        }
841        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
842            MODELMBEAN_LOGGER.log(Level.TRACE, "Exit");
843        }
844
845        return retInfo;
846    }
847
848
849    /* We override MBeanInfo.getDescriptor() to return our descriptor. */
850    /**
851     * @since 1.6
852     */
853    @Override
854    public Descriptor getDescriptor() {
855        return getMBeanDescriptorNoException();
856    }
857
858    public Descriptor getMBeanDescriptor() throws MBeanException {
859        return getMBeanDescriptorNoException();
860    }
861
862    private Descriptor getMBeanDescriptorNoException() {
863        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
864            MODELMBEAN_LOGGER.log(Level.TRACE, "Entry");
865        }
866
867        if (modelMBeanDescriptor == null)
868            modelMBeanDescriptor = validDescriptor(null);
869
870        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
871            MODELMBEAN_LOGGER.log(Level.TRACE,
872                    "Exit, returning: " + modelMBeanDescriptor);
873        }
874        return (Descriptor) modelMBeanDescriptor.clone();
875    }
876
877    public void setMBeanDescriptor(Descriptor inMBeanDescriptor)
878    throws MBeanException, RuntimeOperationsException {
879        if (MODELMBEAN_LOGGER.isLoggable(Level.TRACE)) {
880            MODELMBEAN_LOGGER.log(Level.TRACE, "Entry");
881        }
882        modelMBeanDescriptor = validDescriptor(inMBeanDescriptor);
883    }
884
885
886    /**
887     * Clones the passed in Descriptor, sets default values, and checks for validity.
888     * If the Descriptor is invalid (for instance by having the wrong "name"),
889     * this indicates programming error and a RuntimeOperationsException will be thrown.
890     *
891     * The following fields will be defaulted if they are not already set:
892     * displayName=className,name=className,descriptorType="mbean",
893     * persistPolicy="never", log="F", visibility="1"
894     *
895     * @param in Descriptor to be checked, or null which is equivalent to
896     * an empty Descriptor.
897     * @exception RuntimeOperationsException if Descriptor is invalid
898     */
899    private Descriptor validDescriptor(final Descriptor in) throws RuntimeOperationsException {
900        Descriptor clone;
901        boolean defaulted = (in == null);
902        if (defaulted) {
903            clone = new DescriptorSupport();
904            MODELMBEAN_LOGGER.log(Level.TRACE, "Null Descriptor, creating new.");
905        } else {
906            clone = (Descriptor) in.clone();
907        }
908
909        //Setting defaults.
910        if (defaulted && clone.getFieldValue("name")==null) {
911            clone.setField("name", this.getClassName());
912            MODELMBEAN_LOGGER.log(Level.TRACE, "Defaulting Descriptor name to " + this.getClassName());
913        }
914        if (defaulted && clone.getFieldValue("descriptorType")==null) {
915            clone.setField("descriptorType", MMB);
916            MODELMBEAN_LOGGER.log(Level.TRACE, "Defaulting descriptorType to \"" + MMB + "\"");
917        }
918        if (clone.getFieldValue("displayName") == null) {
919            clone.setField("displayName",this.getClassName());
920            MODELMBEAN_LOGGER.log(Level.TRACE, "Defaulting Descriptor displayName to " + this.getClassName());
921        }
922        if (clone.getFieldValue("persistPolicy") == null) {
923            clone.setField("persistPolicy","never");
924            MODELMBEAN_LOGGER.log(Level.TRACE, "Defaulting Descriptor persistPolicy to \"never\"");
925        }
926        if (clone.getFieldValue("log") == null) {
927            clone.setField("log","F");
928            MODELMBEAN_LOGGER.log(Level.TRACE, "Defaulting Descriptor \"log\" field to \"F\"");
929        }
930        if (clone.getFieldValue("visibility") == null) {
931            clone.setField("visibility","1");
932            MODELMBEAN_LOGGER.log(Level.TRACE, "Defaulting Descriptor visibility to 1");
933        }
934
935        //Checking validity
936        if (!clone.isValid()) {
937             throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"),
938                "The isValid() method of the Descriptor object itself returned false,"+
939                "one or more required fields are invalid. Descriptor:" + clone.toString());
940        }
941
942        if (! ((String)clone.getFieldValue("descriptorType")).equalsIgnoreCase(MMB)) {
943                 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"),
944                "The Descriptor \"descriptorType\" field does not match the object described. " +
945                 " Expected: "+ MMB + " , was: " + clone.getFieldValue("descriptorType"));
946        }
947
948        return clone;
949    }
950
951
952
953
954    /**
955     * Deserializes a {@link ModelMBeanInfoSupport} from an {@link ObjectInputStream}.
956     */
957    private void readObject(ObjectInputStream in)
958    throws IOException, ClassNotFoundException {
959        if (compat) {
960            // Read an object serialized in the old serial form
961            //
962            ObjectInputStream.GetField fields = in.readFields();
963            modelMBeanDescriptor =
964                    (Descriptor) fields.get("modelMBeanDescriptor", null);
965            if (fields.defaulted("modelMBeanDescriptor")) {
966                throw new NullPointerException("modelMBeanDescriptor");
967            }
968            modelMBeanAttributes =
969                    (MBeanAttributeInfo[]) fields.get("mmbAttributes", null);
970            if (fields.defaulted("mmbAttributes")) {
971                throw new NullPointerException("mmbAttributes");
972            }
973            modelMBeanConstructors =
974                    (MBeanConstructorInfo[]) fields.get("mmbConstructors", null);
975            if (fields.defaulted("mmbConstructors")) {
976                throw new NullPointerException("mmbConstructors");
977            }
978            modelMBeanNotifications =
979                    (MBeanNotificationInfo[]) fields.get("mmbNotifications", null);
980            if (fields.defaulted("mmbNotifications")) {
981                throw new NullPointerException("mmbNotifications");
982            }
983            modelMBeanOperations =
984                    (MBeanOperationInfo[]) fields.get("mmbOperations", null);
985            if (fields.defaulted("mmbOperations")) {
986                throw new NullPointerException("mmbOperations");
987            }
988        } else {
989            // Read an object serialized in the new serial form
990            //
991            in.defaultReadObject();
992        }
993    }
994
995
996    /**
997     * Serializes a {@link ModelMBeanInfoSupport} to an {@link ObjectOutputStream}.
998     */
999    private void writeObject(ObjectOutputStream out)
1000    throws IOException {
1001        if (compat) {
1002            // Serializes this instance in the old serial form
1003            //
1004            ObjectOutputStream.PutField fields = out.putFields();
1005            fields.put("modelMBeanDescriptor", modelMBeanDescriptor);
1006            fields.put("mmbAttributes", modelMBeanAttributes);
1007            fields.put("mmbConstructors", modelMBeanConstructors);
1008            fields.put("mmbNotifications", modelMBeanNotifications);
1009            fields.put("mmbOperations", modelMBeanOperations);
1010            fields.put("currClass", currClass);
1011            out.writeFields();
1012        } else {
1013            // Serializes this instance in the new serial form
1014            //
1015            out.defaultWriteObject();
1016        }
1017    }
1018
1019
1020}
1021