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 
  31 package javax.management.modelmbean;
  32 
  33 import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER;
  34 import com.sun.jmx.mbeanserver.GetPropertyAction;
  35 
  36 import java.io.IOException;
  37 import java.io.ObjectInputStream;
  38 import java.io.ObjectOutputStream;
  39 import java.io.ObjectStreamField;
  40 import java.security.AccessController;
  41 import java.lang.System.Logger.Level;
  42 
  43 import javax.management.Descriptor;
  44 import javax.management.MBeanAttributeInfo;
  45 import javax.management.MBeanConstructorInfo;
  46 import javax.management.MBeanException;
  47 import javax.management.MBeanInfo;
  48 import javax.management.MBeanNotificationInfo;
  49 import javax.management.MBeanOperationInfo;
  50 import 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")
  85 public 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 }