KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > management > MBeanInfo


1 /*
2  * @(#)MBeanInfo.java 1.44 04/06/03
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.management;
9
10 import java.lang.reflect.Method JavaDoc;
11 import java.util.Arrays JavaDoc;
12 import java.util.Map JavaDoc;
13 import java.util.WeakHashMap JavaDoc;
14 import java.security.AccessController JavaDoc;
15 import java.security.PrivilegedAction JavaDoc;
16
17 /**
18  * <p>Describes the management interface exposed by an MBean; that is,
19  * the set of attributes and operations which are available for
20  * management operations. Instances of this class are immutable.
21  * Subclasses may be mutable but this is not recommended.</p>
22  *
23  * <p>The contents of the <code>MBeanInfo</code> for a Dynamic MBean
24  * are determined by its {@link DynamicMBean#getMBeanInfo
25  * getMBeanInfo()} method. This includes Open MBeans and Model
26  * MBeans, which are kinds of Dynamic MBeans.</p>
27  *
28  * <p>The contents of the <code>MBeanInfo</code> for a Standard MBean
29  * are determined by the MBean server as follows:</p>
30  *
31  * <ul>
32  *
33  * <li>{@link #getClassName()} returns the Java class name of the MBean
34  * object;
35  *
36  * <li>{@link #getConstructors()} returns the list of all public
37  * constructors in that object;
38  *
39  * <li>{@link #getAttributes()} returns the list of all attributes
40  * whose existence is deduced from the presence in the MBean interface
41  * of a <code>get<i>Name</i></code>, <code>is<i>Name</i></code>, or
42  * <code>set<i>Name</i></code> method that conforms to the conventions
43  * for Standard MBeans;
44  *
45  * <li>{@link #getOperations()} returns the list of all methods in
46  * the MBean interface that do not represent attributes;
47  *
48  * <li>{@link #getNotifications()} returns an empty array if the MBean
49  * does not implement the {@link NotificationBroadcaster} interface,
50  * otherwise the result of calling {@link
51  * NotificationBroadcaster#getNotificationInfo()} on it.
52  *
53  * </ul>
54  *
55  * <p>The remaining details of the <code>MBeanInfo</code> for a
56  * Standard MBean are not specified. This includes the description of
57  * the <code>MBeanInfo</code> and of any contained constructors,
58  * attributes, operations, and notifications; and the names and
59  * descriptions of parameters to constructors and operations.
60  *
61  * @since 1.5
62  */

63 public class MBeanInfo implements Cloneable JavaDoc, java.io.Serializable JavaDoc {
64
65     /* Serial version */
66     static final long serialVersionUID = -6451021435135161911L;
67
68     /**
69      * @serial The human readable description of the class.
70      */

71     private final String JavaDoc description;
72
73     /**
74      * @serial The MBean qualified name.
75      */

76     private final String JavaDoc className;
77
78     /**
79      * @serial The MBean attribute descriptors.
80      */

81     private final MBeanAttributeInfo JavaDoc[] attributes;
82
83     /**
84      * @serial The MBean operation descriptors.
85      */

86     private final MBeanOperationInfo JavaDoc[] operations;
87
88      /**
89      * @serial The MBean constructor descriptors.
90      */

91     private final MBeanConstructorInfo JavaDoc[] constructors;
92
93     /**
94      * @serial The MBean notification descriptors.
95      */

96     private final MBeanNotificationInfo JavaDoc[] notifications;
97
98     private transient int hashCode;
99
100     /**
101      * <p>True if this class is known not to override the getters of
102      * MBeanInfo. Obviously true for MBeanInfo itself, and true
103      * for a subclass where we succeed in reflecting on the methods
104      * and discover they are not overridden.</p>
105      *
106      * <p>The purpose of this variable is to avoid cloning the arrays
107      * when doing operations like {@link #equals} where we know they
108      * will not be changed. If a subclass overrides a getter, we
109      * cannot access the corresponding array directly.</p>
110      */

111     private final transient boolean immutable;
112
113     /**
114      * Constructs an <CODE>MBeanInfo</CODE>.
115      *
116      * @param className The name of the Java class of the MBean described
117      * by this <CODE>MBeanInfo</CODE>. This value may be any
118      * syntactically legal Java class name. It does not have to be a
119      * Java class known to the MBean server or to the MBean's
120      * ClassLoader. If it is a Java class known to the MBean's
121      * ClassLoader, it is recommended but not required that the
122      * class's public methods include those that would appear in a
123      * Standard MBean implementing the attributes and operations in
124      * this MBeanInfo.
125      * @param description A human readable description of the MBean (optional).
126      * @param attributes The list of exposed attributes of the MBean.
127      * This may be null with the same effect as a zero-length array.
128      * @param constructors The list of public constructors of the
129      * MBean. This may be null with the same effect as a zero-length
130      * array.
131      * @param operations The list of operations of the MBean. This
132      * may be null with the same effect as a zero-length array.
133      * @param notifications The list of notifications emitted. This
134      * may be null with the same effect as a zero-length array.
135      */

136     public MBeanInfo(String JavaDoc className,
137              String JavaDoc description,
138              MBeanAttributeInfo JavaDoc[] attributes,
139              MBeanConstructorInfo JavaDoc[] constructors,
140              MBeanOperationInfo JavaDoc[] operations,
141              MBeanNotificationInfo JavaDoc[] notifications)
142         throws IllegalArgumentException JavaDoc {
143
144     this.className = className;
145
146     this.description = description;
147
148     if (attributes == null)
149         attributes = MBeanAttributeInfo.NO_ATTRIBUTES;
150     this.attributes = attributes;
151
152     if (operations == null)
153         operations = MBeanOperationInfo.NO_OPERATIONS;
154     this.operations = operations;
155
156     if (constructors == null)
157         constructors = MBeanConstructorInfo.NO_CONSTRUCTORS;
158     this.constructors = constructors;
159
160     if (notifications == null)
161         notifications = MBeanNotificationInfo.NO_NOTIFICATIONS;
162     this.notifications = notifications;
163
164     this.immutable = isImmutableClass(this.getClass(), MBeanInfo JavaDoc.class);
165     }
166
167     /**
168      * <p>Returns a shallow clone of this instance.
169      * The clone is obtained by simply calling <tt>super.clone()</tt>,
170      * thus calling the default native shallow cloning mechanism
171      * implemented by <tt>Object.clone()</tt>.
172      * No deeper cloning of any internal field is made.</p>
173      *
174      * <p>Since this class is immutable, the clone method is chiefly of
175      * interest to subclasses.</p>
176      */

177      public Object JavaDoc clone () {
178      try {
179          return super.clone() ;
180      } catch (CloneNotSupportedException JavaDoc e) {
181          // should not happen as this class is cloneable
182
return null;
183      }
184      }
185
186
187     /**
188      * Returns the name of the Java class of the MBean described by
189      * this <CODE>MBeanInfo</CODE>.
190      *
191      * @return the class name.
192      */

193     public String JavaDoc getClassName() {
194     return className;
195     }
196
197     /**
198      * Returns a human readable description of the MBean.
199      *
200      * @return the description.
201      */

202     public String JavaDoc getDescription() {
203     return description;
204     }
205
206     /**
207      * Returns the list of attributes exposed for management.
208      * Each attribute is described by an <CODE>MBeanAttributeInfo</CODE> object.
209      *
210      * The returned array is a shallow copy of the internal array,
211      * which means that it is a copy of the internal array of
212      * references to the <CODE>MBeanAttributeInfo</CODE> objects
213      * but that each referenced <CODE>MBeanAttributeInfo</CODE> object is not copied.
214      *
215      * @return An array of <CODE>MBeanAttributeInfo</CODE> objects.
216      */

217     public MBeanAttributeInfo JavaDoc[] getAttributes() {
218     MBeanAttributeInfo JavaDoc[] as = nonNullAttributes();
219     if (as.length == 0)
220         return as;
221     else
222         return (MBeanAttributeInfo JavaDoc[]) as.clone();
223     }
224
225     private MBeanAttributeInfo JavaDoc[] fastGetAttributes() {
226     if (immutable)
227         return nonNullAttributes();
228     else
229         return getAttributes();
230     }
231
232     /**
233      * Return the value of the attributes field, or an empty array if
234      * the field is null. This can't happen with a
235      * normally-constructed instance of this class, but can if the
236      * instance was deserialized from another implementation that
237      * allows the field to be null. It would be simpler if we enforced
238      * the class invariant that these fields cannot be null by writing
239      * a readObject() method, but that would require us to define the
240      * various array fields as non-final, which is annoying because
241      * conceptually they are indeed final.
242      */

243     private MBeanAttributeInfo JavaDoc[] nonNullAttributes() {
244     return (attributes == null) ?
245         MBeanAttributeInfo.NO_ATTRIBUTES : attributes;
246     }
247
248     /**
249      * Returns the list of operations of the MBean.
250      * Each operation is described by an <CODE>MBeanOperationInfo</CODE> object.
251      *
252      * The returned array is a shallow copy of the internal array,
253      * which means that it is a copy of the internal array of
254      * references to the <CODE>MBeanOperationInfo</CODE> objects
255      * but that each referenced <CODE>MBeanOperationInfo</CODE> object is not copied.
256      *
257      * @return An array of <CODE>MBeanOperationInfo</CODE> objects.
258      */

259     public MBeanOperationInfo JavaDoc[] getOperations() {
260     MBeanOperationInfo JavaDoc[] os = nonNullOperations();
261     if (os.length == 0)
262         return os;
263     else
264         return (MBeanOperationInfo JavaDoc[]) os.clone();
265     }
266
267     private MBeanOperationInfo JavaDoc[] fastGetOperations() {
268     if (immutable)
269         return nonNullOperations();
270     else
271         return getOperations();
272     }
273
274     private MBeanOperationInfo JavaDoc[] nonNullOperations() {
275     return (operations == null) ?
276         MBeanOperationInfo.NO_OPERATIONS : operations;
277     }
278
279     /**
280      * <p>Returns the list of the public constructors of the MBean.
281      * Each constructor is described by an
282      * <CODE>MBeanConstructorInfo</CODE> object.</p>
283      *
284      * <p>The returned array is a shallow copy of the internal array,
285      * which means that it is a copy of the internal array of
286      * references to the <CODE>MBeanConstructorInfo</CODE> objects but
287      * that each referenced <CODE>MBeanConstructorInfo</CODE> object
288      * is not copied.</p>
289      *
290      * <p>The returned list is not necessarily exhaustive. That is,
291      * the MBean may have a public constructor that is not in the
292      * list. In this case, the MBean server can construct another
293      * instance of this MBean's class using that constructor, even
294      * though it is not listed here.</p>
295      *
296      * @return An array of <CODE>MBeanConstructorInfo</CODE> objects.
297      */

298     public MBeanConstructorInfo JavaDoc[] getConstructors() {
299     MBeanConstructorInfo JavaDoc[] cs = nonNullConstructors();
300     if (cs.length == 0)
301         return cs;
302     else
303         return (MBeanConstructorInfo JavaDoc[]) cs.clone();
304     }
305
306     private MBeanConstructorInfo JavaDoc[] fastGetConstructors() {
307     if (immutable)
308         return nonNullConstructors();
309     else
310         return getConstructors();
311     }
312
313     private MBeanConstructorInfo JavaDoc[] nonNullConstructors() {
314     return (constructors == null) ?
315         MBeanConstructorInfo.NO_CONSTRUCTORS : constructors;
316     }
317
318     /**
319      * Returns the list of the notifications emitted by the MBean.
320      * Each notification is described by an <CODE>MBeanNotificationInfo</CODE> object.
321      *
322      * The returned array is a shallow copy of the internal array,
323      * which means that it is a copy of the internal array of
324      * references to the <CODE>MBeanNotificationInfo</CODE> objects
325      * but that each referenced <CODE>MBeanNotificationInfo</CODE> object is not copied.
326      *
327      * @return An array of <CODE>MBeanNotificationInfo</CODE> objects.
328      */

329     public MBeanNotificationInfo JavaDoc[] getNotifications() {
330     MBeanNotificationInfo JavaDoc[] ns = nonNullNotifications();
331     if (ns.length == 0)
332         return ns;
333     else
334         return (MBeanNotificationInfo JavaDoc[]) ns.clone();
335     }
336
337     private MBeanNotificationInfo JavaDoc[] fastGetNotifications() {
338     if (immutable)
339         return nonNullNotifications();
340     else
341         return getNotifications();
342     }
343
344     private MBeanNotificationInfo JavaDoc[] nonNullNotifications() {
345     return (notifications == null) ?
346         MBeanNotificationInfo.NO_NOTIFICATIONS : notifications;
347     }
348
349     /**
350      * <p>Compare this MBeanInfo to another. Two MBeanInfo objects
351      * are equal iff they return equal values for {@link
352      * #getClassName()} and for {@link #getDescription()}, and the
353      * arrays returned by the two objects for {@link
354      * #getAttributes()}, {@link #getOperations()}, {@link
355      * #getConstructors()}, and {@link #getNotifications()} are
356      * pairwise equal. Here "equal" means {@link
357      * Object#equals(Object)}, not identity.</p>
358      *
359      * <p>If two MBeanInfo objects return the same values in one of
360      * their arrays but in a different order then they are not equal.</p>
361      *
362      * @param o the object to compare to.
363      *
364      * @return true iff <code>o</code> is an MBeanInfo that is equal
365      * to this one according to the rules above.
366      */

367     public boolean equals(Object JavaDoc o) {
368     if (o == this)
369         return true;
370     if (!(o instanceof MBeanInfo JavaDoc))
371         return false;
372     MBeanInfo JavaDoc p = (MBeanInfo JavaDoc) o;
373     if (!p.getClassName().equals(getClassName()) ||
374         !p.getDescription().equals(getDescription()))
375         return false;
376     return
377         (Arrays.equals(p.fastGetAttributes(), fastGetAttributes()) &&
378          Arrays.equals(p.fastGetOperations(), fastGetOperations()) &&
379          Arrays.equals(p.fastGetConstructors(), fastGetConstructors()) &&
380          Arrays.equals(p.fastGetNotifications(), fastGetNotifications()));
381     }
382
383     public int hashCode() {
384     /* Since computing the hashCode is quite expensive, we cache it.
385        If by some terrible misfortune the computed value is 0, the
386        caching won't work and we will recompute it every time.
387
388        We don't bother synchronizing, because, at worst, n different
389        threads will compute the same hashCode at the same time. */

390     if (hashCode != 0)
391         return hashCode;
392
393     hashCode =
394         getClassName().hashCode() ^
395         arrayHashCode(fastGetAttributes()) ^
396         arrayHashCode(fastGetOperations()) ^
397         arrayHashCode(fastGetConstructors()) ^
398         arrayHashCode(fastGetNotifications());
399
400     return hashCode;
401     }
402
403     private static int arrayHashCode(Object JavaDoc[] array) {
404     int hash = 0;
405     for (int i = 0; i < array.length; i++)
406         hash ^= array[i].hashCode();
407     return hash;
408     }
409
410     /**
411      * Cached results of previous calls to isImmutableClass. Maps
412      * Class to Boolean. This is a WeakHashMap so that we don't
413      * prevent a class from being garbage collected just because
414      * we know whether it's immutable.
415      */

416     private static final Map JavaDoc immutability = new WeakHashMap JavaDoc();
417
418     /**
419      * Return true if <code>subclass</code> is known to preserve the
420      * immutability of <code>immutableClass</code>. The class
421      * <code>immutableClass</code> is a reference class that is known
422      * to be immutable. The subclass <code>subclass</code> is
423      * considered immutable if it does not override any public method
424      * of <code>immutableClass</code> whose name begins with "get" or
425      * "is". This is obviously not an infallible test for immutability,
426      * but it works for the public interfaces of the MBean*Info classes.
427     */

428     static boolean isImmutableClass(Class JavaDoc subclass, Class JavaDoc immutableClass) {
429     if (subclass == immutableClass)
430         return true;
431     synchronized (immutability) {
432         Boolean JavaDoc immutable = (Boolean JavaDoc) immutability.get(subclass);
433         if (immutable == null) {
434         try {
435             PrivilegedAction JavaDoc immutabilityAction =
436             new ImmutabilityAction(subclass, immutableClass);
437             immutable = (Boolean JavaDoc)
438             AccessController.doPrivileged(immutabilityAction);
439         } catch (Exception JavaDoc e) { // e.g. SecurityException
440
/* We don't know, so we assume it isn't. */
441             immutable = Boolean.FALSE;
442         }
443         immutability.put(subclass, immutable);
444         }
445         return immutable.booleanValue();
446     }
447     }
448
449     /*
450      * The PrivilegedAction stuff is probably overkill. We can be
451      * pretty sure the caller does have the required privileges -- a
452      * JMX user that can't do reflection can't even use Standard
453      * MBeans! But there's probably a performance gain by not having
454      * to check the whole call stack.
455      */

456     private static class ImmutabilityAction implements PrivilegedAction JavaDoc {
457     private final Class JavaDoc subclass;
458     private final Class JavaDoc immutableClass;
459
460     ImmutabilityAction(Class JavaDoc subclass, Class JavaDoc immutableClass) {
461         this.subclass = subclass;
462         this.immutableClass = immutableClass;
463     }
464
465     public Object JavaDoc run() {
466         Method JavaDoc[] methods = immutableClass.getMethods();
467         for (int i = 0; i < methods.length; i++) {
468         Method JavaDoc method = methods[i];
469         String JavaDoc methodName = method.getName();
470         if (methodName.startsWith("get")
471             || methodName.startsWith("is")) {
472             Class JavaDoc[] paramTypes = method.getParameterTypes();
473             try {
474             Method JavaDoc submethod =
475                 subclass.getMethod(methodName, paramTypes);
476             if (!submethod.equals(method))
477                 return Boolean.FALSE;
478             } catch (NoSuchMethodException JavaDoc e) {
479             return Boolean.FALSE;
480             }
481         }
482         }
483         return Boolean.TRUE;
484     }
485     }
486 }
487
Popular Tags