jdk/src/share/classes/javax/management/MBeanInfo.java
changeset 2 90ce3da70b43
child 1510 e747d3193ef2
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1999-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package javax.management;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.io.StreamCorruptedException;
       
    30 import java.io.Serializable;
       
    31 import java.io.ObjectOutputStream;
       
    32 import java.io.ObjectInputStream;
       
    33 import java.lang.reflect.Method;
       
    34 import java.util.Arrays;
       
    35 import java.util.Map;
       
    36 import java.util.WeakHashMap;
       
    37 import java.security.AccessController;
       
    38 import java.security.PrivilegedAction;
       
    39 
       
    40 import static javax.management.ImmutableDescriptor.nonNullDescriptor;
       
    41 
       
    42 /**
       
    43  * <p>Describes the management interface exposed by an MBean; that is,
       
    44  * the set of attributes and operations which are available for
       
    45  * management operations.  Instances of this class are immutable.
       
    46  * Subclasses may be mutable but this is not recommended.</p>
       
    47  *
       
    48  * <p>The contents of the <code>MBeanInfo</code> for a Dynamic MBean
       
    49  * are determined by its {@link DynamicMBean#getMBeanInfo
       
    50  * getMBeanInfo()} method.  This includes Open MBeans and Model
       
    51  * MBeans, which are kinds of Dynamic MBeans.</p>
       
    52  *
       
    53  * <p>The contents of the <code>MBeanInfo</code> for a Standard MBean
       
    54  * are determined by the MBean server as follows:</p>
       
    55  *
       
    56  * <ul>
       
    57  *
       
    58  * <li>{@link #getClassName()} returns the Java class name of the MBean
       
    59  * object;
       
    60  *
       
    61  * <li>{@link #getConstructors()} returns the list of all public
       
    62  * constructors in that object;
       
    63  *
       
    64  * <li>{@link #getAttributes()} returns the list of all attributes
       
    65  * whose existence is deduced from the presence in the MBean interface
       
    66  * of a <code>get<i>Name</i></code>, <code>is<i>Name</i></code>, or
       
    67  * <code>set<i>Name</i></code> method that conforms to the conventions
       
    68  * for Standard MBeans;
       
    69  *
       
    70  * <li>{@link #getOperations()} returns the list of all methods in
       
    71  * the MBean interface that do not represent attributes;
       
    72  *
       
    73  * <li>{@link #getNotifications()} returns an empty array if the MBean
       
    74  * does not implement the {@link NotificationBroadcaster} interface,
       
    75  * otherwise the result of calling {@link
       
    76  * NotificationBroadcaster#getNotificationInfo()} on it;
       
    77  *
       
    78  * <li>{@link #getDescriptor()} returns a descriptor containing the contents
       
    79  * of any descriptor annotations in the MBean interface.
       
    80  *
       
    81  * </ul>
       
    82  *
       
    83  * <p>The description returned by {@link #getDescription()} and the
       
    84  * descriptions of the contained attributes and operations are determined
       
    85  * by the corresponding <!-- link here --> Description annotations if any;
       
    86  * otherwise their contents are not specified.</p>
       
    87  *
       
    88  * <p>The remaining details of the <code>MBeanInfo</code> for a
       
    89  * Standard MBean are not specified.  This includes the description of
       
    90  * any contained constructors, and notifications; the names
       
    91  * of parameters to constructors and operations; and the descriptions of
       
    92  * constructor parameters.</p>
       
    93  *
       
    94  * @since 1.5
       
    95  */
       
    96 public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
       
    97 
       
    98     /* Serial version */
       
    99     static final long serialVersionUID = -6451021435135161911L;
       
   100 
       
   101     /**
       
   102      * @serial The Descriptor for the MBean.  This field
       
   103      * can be null, which is equivalent to an empty Descriptor.
       
   104      */
       
   105     private transient Descriptor descriptor;
       
   106 
       
   107     /**
       
   108      * @serial The human readable description of the class.
       
   109      */
       
   110     private final String description;
       
   111 
       
   112     /**
       
   113      * @serial The MBean qualified name.
       
   114      */
       
   115     private final String className;
       
   116 
       
   117     /**
       
   118      * @serial The MBean attribute descriptors.
       
   119      */
       
   120     private final MBeanAttributeInfo[] attributes;
       
   121 
       
   122     /**
       
   123      * @serial The MBean operation descriptors.
       
   124      */
       
   125     private final MBeanOperationInfo[] operations;
       
   126 
       
   127      /**
       
   128      * @serial The MBean constructor descriptors.
       
   129      */
       
   130     private final MBeanConstructorInfo[] constructors;
       
   131 
       
   132     /**
       
   133      * @serial The MBean notification descriptors.
       
   134      */
       
   135     private final MBeanNotificationInfo[] notifications;
       
   136 
       
   137     private transient int hashCode;
       
   138 
       
   139     /**
       
   140      * <p>True if this class is known not to override the array-valued
       
   141      * getters of MBeanInfo.  Obviously true for MBeanInfo itself, and true
       
   142      * for a subclass where we succeed in reflecting on the methods
       
   143      * and discover they are not overridden.</p>
       
   144      *
       
   145      * <p>The purpose of this variable is to avoid cloning the arrays
       
   146      * when doing operations like {@link #equals} where we know they
       
   147      * will not be changed.  If a subclass overrides a getter, we
       
   148      * cannot access the corresponding array directly.</p>
       
   149      */
       
   150     private final transient boolean arrayGettersSafe;
       
   151 
       
   152     /**
       
   153      * Constructs an <CODE>MBeanInfo</CODE>.
       
   154      *
       
   155      * @param className The name of the Java class of the MBean described
       
   156      * by this <CODE>MBeanInfo</CODE>.  This value may be any
       
   157      * syntactically legal Java class name.  It does not have to be a
       
   158      * Java class known to the MBean server or to the MBean's
       
   159      * ClassLoader.  If it is a Java class known to the MBean's
       
   160      * ClassLoader, it is recommended but not required that the
       
   161      * class's public methods include those that would appear in a
       
   162      * Standard MBean implementing the attributes and operations in
       
   163      * this MBeanInfo.
       
   164      * @param description A human readable description of the MBean (optional).
       
   165      * @param attributes The list of exposed attributes of the MBean.
       
   166      * This may be null with the same effect as a zero-length array.
       
   167      * @param constructors The list of public constructors of the
       
   168      * MBean.  This may be null with the same effect as a zero-length
       
   169      * array.
       
   170      * @param operations The list of operations of the MBean.  This
       
   171      * may be null with the same effect as a zero-length array.
       
   172      * @param notifications The list of notifications emitted.  This
       
   173      * may be null with the same effect as a zero-length array.
       
   174      */
       
   175     public MBeanInfo(String className,
       
   176                      String description,
       
   177                      MBeanAttributeInfo[] attributes,
       
   178                      MBeanConstructorInfo[] constructors,
       
   179                      MBeanOperationInfo[] operations,
       
   180                      MBeanNotificationInfo[] notifications)
       
   181             throws IllegalArgumentException {
       
   182         this(className, description, attributes, constructors, operations,
       
   183              notifications, null);
       
   184     }
       
   185 
       
   186     /**
       
   187      * Constructs an <CODE>MBeanInfo</CODE>.
       
   188      *
       
   189      * @param className The name of the Java class of the MBean described
       
   190      * by this <CODE>MBeanInfo</CODE>.  This value may be any
       
   191      * syntactically legal Java class name.  It does not have to be a
       
   192      * Java class known to the MBean server or to the MBean's
       
   193      * ClassLoader.  If it is a Java class known to the MBean's
       
   194      * ClassLoader, it is recommended but not required that the
       
   195      * class's public methods include those that would appear in a
       
   196      * Standard MBean implementing the attributes and operations in
       
   197      * this MBeanInfo.
       
   198      * @param description A human readable description of the MBean (optional).
       
   199      * @param attributes The list of exposed attributes of the MBean.
       
   200      * This may be null with the same effect as a zero-length array.
       
   201      * @param constructors The list of public constructors of the
       
   202      * MBean.  This may be null with the same effect as a zero-length
       
   203      * array.
       
   204      * @param operations The list of operations of the MBean.  This
       
   205      * may be null with the same effect as a zero-length array.
       
   206      * @param notifications The list of notifications emitted.  This
       
   207      * may be null with the same effect as a zero-length array.
       
   208      * @param descriptor The descriptor for the MBean.  This may be null
       
   209      * which is equivalent to an empty descriptor.
       
   210      *
       
   211      * @since 1.6
       
   212      */
       
   213     public MBeanInfo(String className,
       
   214                      String description,
       
   215                      MBeanAttributeInfo[] attributes,
       
   216                      MBeanConstructorInfo[] constructors,
       
   217                      MBeanOperationInfo[] operations,
       
   218                      MBeanNotificationInfo[] notifications,
       
   219                      Descriptor descriptor)
       
   220             throws IllegalArgumentException {
       
   221 
       
   222         this.className = className;
       
   223 
       
   224         this.description = description;
       
   225 
       
   226         if (attributes == null)
       
   227             attributes = MBeanAttributeInfo.NO_ATTRIBUTES;
       
   228         this.attributes = attributes;
       
   229 
       
   230         if (operations == null)
       
   231             operations = MBeanOperationInfo.NO_OPERATIONS;
       
   232         this.operations = operations;
       
   233 
       
   234         if (constructors == null)
       
   235             constructors = MBeanConstructorInfo.NO_CONSTRUCTORS;
       
   236         this.constructors = constructors;
       
   237 
       
   238         if (notifications == null)
       
   239             notifications = MBeanNotificationInfo.NO_NOTIFICATIONS;
       
   240         this.notifications = notifications;
       
   241 
       
   242         if (descriptor == null)
       
   243             descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
       
   244         this.descriptor = descriptor;
       
   245 
       
   246         this.arrayGettersSafe =
       
   247                 arrayGettersSafe(this.getClass(), MBeanInfo.class);
       
   248     }
       
   249 
       
   250     /**
       
   251      * <p>Returns a shallow clone of this instance.
       
   252      * The clone is obtained by simply calling <tt>super.clone()</tt>,
       
   253      * thus calling the default native shallow cloning mechanism
       
   254      * implemented by <tt>Object.clone()</tt>.
       
   255      * No deeper cloning of any internal field is made.</p>
       
   256      *
       
   257      * <p>Since this class is immutable, the clone method is chiefly of
       
   258      * interest to subclasses.</p>
       
   259      */
       
   260      public Object clone () {
       
   261          try {
       
   262              return super.clone() ;
       
   263          } catch (CloneNotSupportedException e) {
       
   264              // should not happen as this class is cloneable
       
   265              return null;
       
   266          }
       
   267      }
       
   268 
       
   269 
       
   270     /**
       
   271      * Returns the name of the Java class of the MBean described by
       
   272      * this <CODE>MBeanInfo</CODE>.
       
   273      *
       
   274      * @return the class name.
       
   275      */
       
   276     public String getClassName()  {
       
   277         return className;
       
   278     }
       
   279 
       
   280     /**
       
   281      * Returns a human readable description of the MBean.
       
   282      *
       
   283      * @return the description.
       
   284      */
       
   285     public String getDescription()  {
       
   286         return description;
       
   287     }
       
   288 
       
   289     /**
       
   290      * Returns the list of attributes exposed for management.
       
   291      * Each attribute is described by an <CODE>MBeanAttributeInfo</CODE> object.
       
   292      *
       
   293      * The returned array is a shallow copy of the internal array,
       
   294      * which means that it is a copy of the internal array of
       
   295      * references to the <CODE>MBeanAttributeInfo</CODE> objects
       
   296      * but that each referenced <CODE>MBeanAttributeInfo</CODE> object is not copied.
       
   297      *
       
   298      * @return  An array of <CODE>MBeanAttributeInfo</CODE> objects.
       
   299      */
       
   300     public MBeanAttributeInfo[] getAttributes()   {
       
   301         MBeanAttributeInfo[] as = nonNullAttributes();
       
   302         if (as.length == 0)
       
   303             return as;
       
   304         else
       
   305             return as.clone();
       
   306     }
       
   307 
       
   308     private MBeanAttributeInfo[] fastGetAttributes() {
       
   309         if (arrayGettersSafe)
       
   310             return nonNullAttributes();
       
   311         else
       
   312             return getAttributes();
       
   313     }
       
   314 
       
   315     /**
       
   316      * Return the value of the attributes field, or an empty array if
       
   317      * the field is null.  This can't happen with a
       
   318      * normally-constructed instance of this class, but can if the
       
   319      * instance was deserialized from another implementation that
       
   320      * allows the field to be null.  It would be simpler if we enforced
       
   321      * the class invariant that these fields cannot be null by writing
       
   322      * a readObject() method, but that would require us to define the
       
   323      * various array fields as non-final, which is annoying because
       
   324      * conceptually they are indeed final.
       
   325      */
       
   326     private MBeanAttributeInfo[] nonNullAttributes() {
       
   327         return (attributes == null) ?
       
   328             MBeanAttributeInfo.NO_ATTRIBUTES : attributes;
       
   329     }
       
   330 
       
   331     /**
       
   332      * Returns the list of operations  of the MBean.
       
   333      * Each operation is described by an <CODE>MBeanOperationInfo</CODE> object.
       
   334      *
       
   335      * The returned array is a shallow copy of the internal array,
       
   336      * which means that it is a copy of the internal array of
       
   337      * references to the <CODE>MBeanOperationInfo</CODE> objects
       
   338      * but that each referenced <CODE>MBeanOperationInfo</CODE> object is not copied.
       
   339      *
       
   340      * @return  An array of <CODE>MBeanOperationInfo</CODE> objects.
       
   341      */
       
   342     public MBeanOperationInfo[] getOperations()  {
       
   343         MBeanOperationInfo[] os = nonNullOperations();
       
   344         if (os.length == 0)
       
   345             return os;
       
   346         else
       
   347             return os.clone();
       
   348     }
       
   349 
       
   350     private MBeanOperationInfo[] fastGetOperations() {
       
   351         if (arrayGettersSafe)
       
   352             return nonNullOperations();
       
   353         else
       
   354             return getOperations();
       
   355     }
       
   356 
       
   357     private MBeanOperationInfo[] nonNullOperations() {
       
   358         return (operations == null) ?
       
   359             MBeanOperationInfo.NO_OPERATIONS : operations;
       
   360     }
       
   361 
       
   362     /**
       
   363      * <p>Returns the list of the public constructors of the MBean.
       
   364      * Each constructor is described by an
       
   365      * <CODE>MBeanConstructorInfo</CODE> object.</p>
       
   366      *
       
   367      * <p>The returned array is a shallow copy of the internal array,
       
   368      * which means that it is a copy of the internal array of
       
   369      * references to the <CODE>MBeanConstructorInfo</CODE> objects but
       
   370      * that each referenced <CODE>MBeanConstructorInfo</CODE> object
       
   371      * is not copied.</p>
       
   372      *
       
   373      * <p>The returned list is not necessarily exhaustive.  That is,
       
   374      * the MBean may have a public constructor that is not in the
       
   375      * list.  In this case, the MBean server can construct another
       
   376      * instance of this MBean's class using that constructor, even
       
   377      * though it is not listed here.</p>
       
   378      *
       
   379      * @return  An array of <CODE>MBeanConstructorInfo</CODE> objects.
       
   380      */
       
   381     public MBeanConstructorInfo[] getConstructors()  {
       
   382         MBeanConstructorInfo[] cs = nonNullConstructors();
       
   383         if (cs.length == 0)
       
   384             return cs;
       
   385         else
       
   386             return cs.clone();
       
   387     }
       
   388 
       
   389     private MBeanConstructorInfo[] fastGetConstructors() {
       
   390         if (arrayGettersSafe)
       
   391             return nonNullConstructors();
       
   392         else
       
   393             return getConstructors();
       
   394     }
       
   395 
       
   396     private MBeanConstructorInfo[] nonNullConstructors() {
       
   397         return (constructors == null) ?
       
   398             MBeanConstructorInfo.NO_CONSTRUCTORS : constructors;
       
   399     }
       
   400 
       
   401     /**
       
   402      * Returns the list of the notifications emitted by the MBean.
       
   403      * Each notification is described by an <CODE>MBeanNotificationInfo</CODE> object.
       
   404      *
       
   405      * The returned array is a shallow copy of the internal array,
       
   406      * which means that it is a copy of the internal array of
       
   407      * references to the <CODE>MBeanNotificationInfo</CODE> objects
       
   408      * but that each referenced <CODE>MBeanNotificationInfo</CODE> object is not copied.
       
   409      *
       
   410      * @return  An array of <CODE>MBeanNotificationInfo</CODE> objects.
       
   411      */
       
   412     public MBeanNotificationInfo[] getNotifications()  {
       
   413         MBeanNotificationInfo[] ns = nonNullNotifications();
       
   414         if (ns.length == 0)
       
   415             return ns;
       
   416         else
       
   417             return ns.clone();
       
   418     }
       
   419 
       
   420     private MBeanNotificationInfo[] fastGetNotifications() {
       
   421         if (arrayGettersSafe)
       
   422             return nonNullNotifications();
       
   423         else
       
   424             return getNotifications();
       
   425     }
       
   426 
       
   427     private MBeanNotificationInfo[] nonNullNotifications() {
       
   428         return (notifications == null) ?
       
   429             MBeanNotificationInfo.NO_NOTIFICATIONS : notifications;
       
   430     }
       
   431 
       
   432     /**
       
   433      * Get the descriptor of this MBeanInfo.  Changing the returned value
       
   434      * will have no affect on the original descriptor.
       
   435      *
       
   436      * @return a descriptor that is either immutable or a copy of the original.
       
   437      *
       
   438      * @since 1.6
       
   439      */
       
   440     public Descriptor getDescriptor() {
       
   441         return (Descriptor) nonNullDescriptor(descriptor).clone();
       
   442     }
       
   443 
       
   444     public String toString() {
       
   445         return
       
   446             getClass().getName() + "[" +
       
   447             "description=" + getDescription() + ", " +
       
   448             "attributes=" + Arrays.asList(fastGetAttributes()) + ", " +
       
   449             "constructors=" + Arrays.asList(fastGetConstructors()) + ", " +
       
   450             "operations=" + Arrays.asList(fastGetOperations()) + ", " +
       
   451             "notifications=" + Arrays.asList(fastGetNotifications()) + ", " +
       
   452             "descriptor=" + getDescriptor() +
       
   453             "]";
       
   454     }
       
   455 
       
   456     /**
       
   457      * <p>Compare this MBeanInfo to another.  Two MBeanInfo objects
       
   458      * are equal if and only if they return equal values for {@link
       
   459      * #getClassName()}, for {@link #getDescription()}, and for
       
   460      * {@link #getDescriptor()}, and the
       
   461      * arrays returned by the two objects for {@link
       
   462      * #getAttributes()}, {@link #getOperations()}, {@link
       
   463      * #getConstructors()}, and {@link #getNotifications()} are
       
   464      * pairwise equal.  Here "equal" means {@link
       
   465      * Object#equals(Object)}, not identity.</p>
       
   466      *
       
   467      * <p>If two MBeanInfo objects return the same values in one of
       
   468      * their arrays but in a different order then they are not equal.</p>
       
   469      *
       
   470      * @param o the object to compare to.
       
   471      *
       
   472      * @return true if and only if <code>o</code> is an MBeanInfo that is equal
       
   473      * to this one according to the rules above.
       
   474      */
       
   475     public boolean equals(Object o) {
       
   476         if (o == this)
       
   477             return true;
       
   478         if (!(o instanceof MBeanInfo))
       
   479             return false;
       
   480         MBeanInfo p = (MBeanInfo) o;
       
   481         if (!isEqual(getClassName(),  p.getClassName()) ||
       
   482                 !isEqual(getDescription(), p.getDescription()) ||
       
   483                 !getDescriptor().equals(p.getDescriptor())) {
       
   484             return false;
       
   485         }
       
   486 
       
   487         return
       
   488             (Arrays.equals(p.fastGetAttributes(), fastGetAttributes()) &&
       
   489              Arrays.equals(p.fastGetOperations(), fastGetOperations()) &&
       
   490              Arrays.equals(p.fastGetConstructors(), fastGetConstructors()) &&
       
   491              Arrays.equals(p.fastGetNotifications(), fastGetNotifications()));
       
   492     }
       
   493 
       
   494     public int hashCode() {
       
   495         /* Since computing the hashCode is quite expensive, we cache it.
       
   496            If by some terrible misfortune the computed value is 0, the
       
   497            caching won't work and we will recompute it every time.
       
   498 
       
   499            We don't bother synchronizing, because, at worst, n different
       
   500            threads will compute the same hashCode at the same time.  */
       
   501         if (hashCode != 0)
       
   502             return hashCode;
       
   503 
       
   504         hashCode =
       
   505             getClassName().hashCode() ^
       
   506             getDescriptor().hashCode() ^
       
   507             arrayHashCode(fastGetAttributes()) ^
       
   508             arrayHashCode(fastGetOperations()) ^
       
   509             arrayHashCode(fastGetConstructors()) ^
       
   510             arrayHashCode(fastGetNotifications());
       
   511 
       
   512         return hashCode;
       
   513     }
       
   514 
       
   515     private static int arrayHashCode(Object[] array) {
       
   516         int hash = 0;
       
   517         for (int i = 0; i < array.length; i++)
       
   518             hash ^= array[i].hashCode();
       
   519         return hash;
       
   520     }
       
   521 
       
   522     /**
       
   523      * Cached results of previous calls to arrayGettersSafe.  This is
       
   524      * a WeakHashMap so that we don't prevent a class from being
       
   525      * garbage collected just because we know whether it's immutable.
       
   526      */
       
   527     private static final Map<Class, Boolean> arrayGettersSafeMap =
       
   528         new WeakHashMap<Class, Boolean>();
       
   529 
       
   530     /**
       
   531      * Return true if <code>subclass</code> is known to preserve the
       
   532      * immutability of <code>immutableClass</code>.  The class
       
   533      * <code>immutableClass</code> is a reference class that is known
       
   534      * to be immutable.  The subclass <code>subclass</code> is
       
   535      * considered immutable if it does not override any public method
       
   536      * of <code>immutableClass</code> whose name begins with "get".
       
   537      * This is obviously not an infallible test for immutability,
       
   538      * but it works for the public interfaces of the MBean*Info classes.
       
   539     */
       
   540     static boolean arrayGettersSafe(Class subclass, Class immutableClass) {
       
   541         if (subclass == immutableClass)
       
   542             return true;
       
   543         synchronized (arrayGettersSafeMap) {
       
   544             Boolean safe = arrayGettersSafeMap.get(subclass);
       
   545             if (safe == null) {
       
   546                 try {
       
   547                     ArrayGettersSafeAction action =
       
   548                         new ArrayGettersSafeAction(subclass, immutableClass);
       
   549                     safe = AccessController.doPrivileged(action);
       
   550                 } catch (Exception e) { // e.g. SecurityException
       
   551                     /* We don't know, so we assume it isn't.  */
       
   552                     safe = false;
       
   553                 }
       
   554                 arrayGettersSafeMap.put(subclass, safe);
       
   555             }
       
   556             return safe;
       
   557         }
       
   558     }
       
   559 
       
   560     /*
       
   561      * The PrivilegedAction stuff is probably overkill.  We can be
       
   562      * pretty sure the caller does have the required privileges -- a
       
   563      * JMX user that can't do reflection can't even use Standard
       
   564      * MBeans!  But there's probably a performance gain by not having
       
   565      * to check the whole call stack.
       
   566      */
       
   567     private static class ArrayGettersSafeAction
       
   568             implements PrivilegedAction<Boolean> {
       
   569 
       
   570         private final Class<?> subclass;
       
   571         private final Class<?> immutableClass;
       
   572 
       
   573         ArrayGettersSafeAction(Class<?> subclass, Class<?> immutableClass) {
       
   574             this.subclass = subclass;
       
   575             this.immutableClass = immutableClass;
       
   576         }
       
   577 
       
   578         public Boolean run() {
       
   579             Method[] methods = immutableClass.getMethods();
       
   580             for (int i = 0; i < methods.length; i++) {
       
   581                 Method method = methods[i];
       
   582                 String methodName = method.getName();
       
   583                 if (methodName.startsWith("get") &&
       
   584                         method.getParameterTypes().length == 0 &&
       
   585                         method.getReturnType().isArray()) {
       
   586                     try {
       
   587                         Method submethod =
       
   588                             subclass.getMethod(methodName);
       
   589                         if (!submethod.equals(method))
       
   590                             return false;
       
   591                     } catch (NoSuchMethodException e) {
       
   592                         return false;
       
   593                     }
       
   594                 }
       
   595             }
       
   596             return true;
       
   597         }
       
   598     }
       
   599 
       
   600     private static boolean isEqual(String s1, String s2) {
       
   601         boolean ret;
       
   602 
       
   603         if (s1 == null) {
       
   604             ret = (s2 == null);
       
   605         } else {
       
   606             ret = s1.equals(s2);
       
   607         }
       
   608 
       
   609         return ret;
       
   610     }
       
   611 
       
   612     /**
       
   613      * Serializes an {@link MBeanInfo} to an {@link ObjectOutputStream}.
       
   614      * @serialData
       
   615      * For compatibility reasons, an object of this class is serialized as follows.
       
   616      * <ul>
       
   617      * The method {@link ObjectOutputStream#defaultWriteObject defaultWriteObject()}
       
   618      * is called first to serialize the object except the field {@code descriptor}
       
   619      * which is declared as transient. The field {@code descriptor} is serialized
       
   620      * as follows:
       
   621      *     <ul>
       
   622      *     <li> If {@code descriptor} is an instance of the class
       
   623      *        {@link ImmutableDescriptor}, the method {@link ObjectOutputStream#write
       
   624      *        write(int val)} is called to write a byte with the value {@code 1},
       
   625      *        then the method {@link ObjectOutputStream#writeObject writeObject(Object obj)}
       
   626      *        is called twice to serialize the field names and the field values of the
       
   627      *        {@code descriptor}, respectively as a {@code String[]} and an
       
   628      *        {@code Object[]};</li>
       
   629      *     <li> Otherwise, the method {@link ObjectOutputStream#write write(int val)}
       
   630      *        is called to write a byte with the value {@code 0}, then the method
       
   631      *        {@link ObjectOutputStream#writeObject writeObject(Object obj)} is called
       
   632      *        to serialize the field {@code descriptor} directly.
       
   633      *     </ul>
       
   634      * </ul>
       
   635      * @since 1.6
       
   636      */
       
   637     private void writeObject(ObjectOutputStream out) throws IOException {
       
   638         out.defaultWriteObject();
       
   639 
       
   640         if (descriptor.getClass() == ImmutableDescriptor.class) {
       
   641             out.write(1);
       
   642 
       
   643             final String[] names = descriptor.getFieldNames();
       
   644 
       
   645             out.writeObject(names);
       
   646             out.writeObject(descriptor.getFieldValues(names));
       
   647         } else {
       
   648             out.write(0);
       
   649 
       
   650             out.writeObject(descriptor);
       
   651         }
       
   652     }
       
   653 
       
   654     /**
       
   655      * Deserializes an {@link MBeanInfo} from an {@link ObjectInputStream}.
       
   656      * @serialData
       
   657      * For compatibility reasons, an object of this class is deserialized as follows.
       
   658      * <ul>
       
   659      * The method {@link ObjectInputStream#defaultReadObject defaultReadObject()}
       
   660      * is called first to deserialize the object except the field
       
   661      * {@code descriptor}, which is not serialized in the default way. Then the method
       
   662      * {@link ObjectInputStream#read read()} is called to read a byte, the field
       
   663      * {@code descriptor} is deserialized according to the value of the byte value:
       
   664      *    <ul>
       
   665      *    <li>1. The method {@link ObjectInputStream#readObject readObject()}
       
   666      *       is called twice to obtain the field names (a {@code String[]}) and
       
   667      *       the field values (a {@code Object[]}) of the {@code descriptor}.
       
   668      *       The two obtained values then are used to construct
       
   669      *       an {@link ImmutableDescriptor} instance for the field
       
   670      *       {@code descriptor};</li>
       
   671      *    <li>0. The value for the field {@code descriptor} is obtained directly
       
   672      *       by calling the method {@link ObjectInputStream#readObject readObject()}.
       
   673      *       If the obtained value is null, the field {@code descriptor} is set to
       
   674      *       {@link ImmutableDescriptor#EMPTY_DESCRIPTOR EMPTY_DESCRIPTOR};</li>
       
   675      *    <li>-1. This means that there is no byte to read and that the object is from
       
   676      *       an earlier version of the JMX API. The field {@code descriptor} is set to
       
   677      *       {@link ImmutableDescriptor#EMPTY_DESCRIPTOR EMPTY_DESCRIPTOR}.</li>
       
   678      *    <li>Any other value. A {@link StreamCorruptedException} is thrown.</li>
       
   679      *    </ul>
       
   680      * </ul>
       
   681      * @since 1.6
       
   682      */
       
   683 
       
   684     private void readObject(ObjectInputStream in)
       
   685         throws IOException, ClassNotFoundException {
       
   686 
       
   687         in.defaultReadObject();
       
   688 
       
   689         switch (in.read()) {
       
   690         case 1:
       
   691             final String[] names = (String[])in.readObject();
       
   692 
       
   693             if (names.length == 0) {
       
   694                 descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
       
   695             } else {
       
   696                 final Object[] values = (Object[])in.readObject();
       
   697                 descriptor = new ImmutableDescriptor(names, values);
       
   698             }
       
   699 
       
   700             break;
       
   701         case 0:
       
   702             descriptor = (Descriptor)in.readObject();
       
   703 
       
   704             if (descriptor == null) {
       
   705                 descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
       
   706             }
       
   707 
       
   708             break;
       
   709         case -1: // from an earlier version of the JMX API
       
   710             descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR;
       
   711 
       
   712             break;
       
   713         default:
       
   714             throw new StreamCorruptedException("Got unexpected byte.");
       
   715         }
       
   716     }
       
   717 }