1 /*
2  * Copyright (c) 2005, 2013, 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 package javax.management;
27
28 import com.sun.jmx.mbeanserver.Introspector;
29 import java.lang.reflect.InvocationHandler;
30 import java.lang.reflect.Modifier;
31 import java.lang.reflect.Proxy;
32 import sun.reflect.misc.ReflectUtil;
33
34 /**
35  * Static methods from the JMX API.  There are no instances of this class.
36  *
37  * @since 1.6
38  */

39 public class JMX {
40     /* Code within this package can prove that by providing this instance of
41      * this class.
42      */

43     static final JMX proof = new JMX();
44
45     private JMX() {}
46
47     /**
48      * The name of the <a href="Descriptor.html#defaultValue">{@code
49      * defaultValue}</a> field.
50      */

51     public static final String DEFAULT_VALUE_FIELD = "defaultValue";
52
53     /**
54      * The name of the <a href="Descriptor.html#immutableInfo">{@code
55      * immutableInfo}</a> field.
56      */

57     public static final String IMMUTABLE_INFO_FIELD = "immutableInfo";
58
59     /**
60      * The name of the <a href="Descriptor.html#interfaceClassName">{@code
61      * interfaceClassName}</a> field.
62      */

63     public static final String INTERFACE_CLASS_NAME_FIELD = "interfaceClassName";
64
65     /**
66      * The name of the <a href="Descriptor.html#legalValues">{@code
67      * legalValues}</a> field.
68      */

69     public static final String LEGAL_VALUES_FIELD = "legalValues";
70
71     /**
72      * The name of the <a href="Descriptor.html#maxValue">{@code
73      * maxValue}</a> field.
74      */

75     public static final String MAX_VALUE_FIELD = "maxValue";
76
77     /**
78      * The name of the <a href="Descriptor.html#minValue">{@code
79      * minValue}</a> field.
80      */

81     public static final String MIN_VALUE_FIELD = "minValue";
82
83     /**
84      * The name of the <a href="Descriptor.html#mxbean">{@code
85      * mxbean}</a> field.
86      */

87     public static final String MXBEAN_FIELD = "mxbean";
88
89     /**
90      * The name of the <a href="Descriptor.html#openType">{@code
91      * openType}</a> field.
92      */

93     public static final String OPEN_TYPE_FIELD = "openType";
94
95     /**
96      * The name of the <a href="Descriptor.html#originalType">{@code
97      * originalType}</a> field.
98      */

99     public static final String ORIGINAL_TYPE_FIELD = "originalType";
100
101     /**
102      * <p>Make a proxy for a Standard MBean in a local or remote
103      * MBean Server.</p>
104      *
105      * <p>If you have an MBean Server {@code mbs} containing an MBean
106      * with {@link ObjectName} {@code name}, and if the MBean's
107      * management interface is described by the Java interface
108      * {@code MyMBean}, you can construct a proxy for the MBean like
109      * this:</p>
110      *
111      * <pre>
112      * MyMBean proxy = JMX.newMBeanProxy(mbs, name, MyMBean.class);
113      * </pre>
114      *
115      * <p>Suppose, for example, {@code MyMBean} looks like this:</p>
116      *
117      * <pre>
118      * public interface MyMBean {
119      *     public String getSomeAttribute();
120      *     public void setSomeAttribute(String value);
121      *     public void someOperation(String param1, int param2);
122      * }
123      * </pre>
124      *
125      * <p>Then you can execute:</p>
126      *
127      * <ul>
128      *
129      * <li>{@code proxy.getSomeAttribute()} which will result in a
130      * call to {@code mbs.}{@link MBeanServerConnection#getAttribute
131      * getAttribute}{@code (name, "SomeAttribute")}.
132      *
133      * <li>{@code proxy.setSomeAttribute("whatever")} which will result
134      * in a call to {@code mbs.}{@link MBeanServerConnection#setAttribute
135      * setAttribute}{@code (name, new Attribute("SomeAttribute""whatever"))}.
136      *
137      * <li>{@code proxy.someOperation("param1", 2)} which will be
138      * translated into a call to {@code mbs.}{@link
139      * MBeanServerConnection#invoke invoke}{@code (name, "someOperation", <etc>)}.
140      *
141      * </ul>
142      *
143      * <p>The object returned by this method is a
144      * {@link Proxy} whose {@code InvocationHandler} is an
145      * {@link MBeanServerInvocationHandler}.</p>
146      *
147      * <p>This method is equivalent to {@link
148      * #newMBeanProxy(MBeanServerConnection, ObjectName, Class,
149      * boolean) newMBeanProxy(connection, objectName, interfaceClass,
150      * false)}.</p>
151      *
152      * @param connection the MBean server to forward to.
153      * @param objectName the name of the MBean within
154      * {@code connection} to forward to.
155      * @param interfaceClass the management interface that the MBean
156      * exports, which will also be implemented by the returned proxy.
157      *
158      * @param <T> allows the compiler to know that if the {@code
159      * interfaceClass} parameter is {@code MyMBean.class}, for
160      * example, then the return type is {@code MyMBean}.
161      *
162      * @return the new proxy instance.
163      *
164      * @throws IllegalArgumentException if {@code interfaceClass} is not
165      * a <a href="package-summary.html#mgIface">compliant MBean
166      * interface</a>
167      */

168     public static <T> T newMBeanProxy(MBeanServerConnection connection,
169                                       ObjectName objectName,
170                                       Class<T> interfaceClass) {
171         return newMBeanProxy(connection, objectName, interfaceClass, false);
172     }
173
174     /**
175      * <p>Make a proxy for a Standard MBean in a local or remote MBean
176      * Server that may also support the methods of {@link
177      * NotificationEmitter}.</p>
178      *
179      * <p>This method behaves the same as {@link
180      * #newMBeanProxy(MBeanServerConnection, ObjectName, Class)}, but
181      * additionally, if {@code notificationEmitter} is {@code
182      * true}, then the MBean is assumed to be a {@link
183      * NotificationBroadcaster} or {@link NotificationEmitter} and the
184      * returned proxy will implement {@link NotificationEmitter} as
185      * well as {@code interfaceClass}.  A call to {@link
186      * NotificationBroadcaster#addNotificationListener} on the proxy
187      * will result in a call to {@link
188      * MBeanServerConnection#addNotificationListener(ObjectName,
189      * NotificationListener, NotificationFilter, Object)}, and
190      * likewise for the other methods of {@link
191      * NotificationBroadcaster} and {@link NotificationEmitter}.</p>
192      *
193      * @param connection the MBean server to forward to.
194      * @param objectName the name of the MBean within
195      * {@code connection} to forward to.
196      * @param interfaceClass the management interface that the MBean
197      * exports, which will also be implemented by the returned proxy.
198      * @param notificationEmitter make the returned proxy
199      * implement {@link NotificationEmitter} by forwarding its methods
200      * via {@code connection}.
201      *
202      * @param <T> allows the compiler to know that if the {@code
203      * interfaceClass} parameter is {@code MyMBean.class}, for
204      * example, then the return type is {@code MyMBean}.
205      *
206      * @return the new proxy instance.
207      *
208      * @throws IllegalArgumentException if {@code interfaceClass} is not
209      * a <a href="package-summary.html#mgIface">compliant MBean
210      * interface</a>
211      */

212     public static <T> T newMBeanProxy(MBeanServerConnection connection,
213                                       ObjectName objectName,
214                                       Class<T> interfaceClass,
215                                       boolean notificationEmitter) {
216         return createProxy(connection, objectName, interfaceClass, notificationEmitter, false);
217     }
218
219     /**
220      * Make a proxy for an MXBean in a local or remote MBean Server.
221      *
222      * <p>If you have an MBean Server {@code mbs} containing an
223      * MXBean with {@link ObjectName} {@code name}, and if the
224      * MXBean's management interface is described by the Java
225      * interface {@code MyMXBean}, you can construct a proxy for
226      * the MXBean like this:</p>
227      *
228      * <pre>
229      * MyMXBean proxy = JMX.newMXBeanProxy(mbs, name, MyMXBean.class);
230      * </pre>
231      *
232      * <p>Suppose, for example, {@code MyMXBean} looks like this:</p>
233      *
234      * <pre>
235      * public interface MyMXBean {
236      *     public String getSimpleAttribute();
237      *     public void setSimpleAttribute(String value);
238      *     public {@link java.lang.management.MemoryUsage} getMappedAttribute();
239      *     public void setMappedAttribute(MemoryUsage memoryUsage);
240      *     public MemoryUsage someOperation(String param1, MemoryUsage param2);
241      * }
242      * </pre>
243      *
244      * <p>Then:</p>
245      *
246      * <ul>
247      *
248      * <li><p>{@code proxy.getSimpleAttribute()} will result in a
249      * call to {@code mbs.}{@link MBeanServerConnection#getAttribute
250      * getAttribute}{@code (name, "SimpleAttribute")}.</p>
251      *
252      * <li><p>{@code proxy.setSimpleAttribute("whatever")} will result
253      * in a call to {@code mbs.}{@link
254      * MBeanServerConnection#setAttribute setAttribute}<code>(name,
255      * new Attribute("SimpleAttribute""whatever"))</code>.</p>
256      *
257      *     <p>Because {@code String} is a <em>simple type</em>, in the
258      *     sense of {@link javax.management.openmbean.SimpleType}, it
259      *     is not changed in the context of an MXBean.  The MXBean
260      *     proxy behaves the same as a Standard MBean proxy (see
261      *     {@link #newMBeanProxy(MBeanServerConnection, ObjectName,
262      *     Class) newMBeanProxy}) for the attribute {@code
263      *     SimpleAttribute}.</p>
264      *
265      * <li><p>{@code proxy.getMappedAttribute()} will result in a call
266      * to {@code mbs.getAttribute("MappedAttribute")}.  The MXBean
267      * mapping rules mean that the actual type of the attribute {@code
268      * MappedAttribute} will be {@link
269      * javax.management.openmbean.CompositeData CompositeData} and
270      * that is what the {@code mbs.getAttribute} call will return.
271      * The proxy will then convert the {@code CompositeData} back into
272      * the expected type {@code MemoryUsage} using the MXBean mapping
273      * rules.</p>
274      *
275      * <li><p>Similarly, {@code proxy.setMappedAttribute(memoryUsage)}
276      * will convert the {@code MemoryUsage} argument into a {@code
277      * CompositeData} before calling {@code mbs.setAttribute}.</p>
278      *
279      * <li><p>{@code proxy.someOperation("whatever", memoryUsage)}
280      * will convert the {@code MemoryUsage} argument into a {@code
281      * CompositeData} and call {@code mbs.invoke}.  The value returned
282      * by {@code mbs.invoke} will be also be a {@code CompositeData},
283      * and the proxy will convert this into the expected type {@code
284      * MemoryUsage} using the MXBean mapping rules.</p>
285      *
286      * </ul>
287      *
288      * <p>The object returned by this method is a
289      * {@link Proxy} whose {@code InvocationHandler} is an
290      * {@link MBeanServerInvocationHandler}.</p>
291      *
292      * <p>This method is equivalent to {@link
293      * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,
294      * boolean) newMXBeanProxy(connection, objectName, interfaceClass,
295      * false)}.</p>
296      *
297      * @param connection the MBean server to forward to.
298      * @param objectName the name of the MBean within
299      * {@code connection} to forward to.
300      * @param interfaceClass the MXBean interface,
301      * which will also be implemented by the returned proxy.
302      *
303      * @param <T> allows the compiler to know that if the {@code
304      * interfaceClass} parameter is {@code MyMXBean.class}, for
305      * example, then the return type is {@code MyMXBean}.
306      *
307      * @return the new proxy instance.
308      *
309      * @throws IllegalArgumentException if {@code interfaceClass} is not
310      * a {@link javax.management.MXBean compliant MXBean interface}
311      */

312     public static <T> T newMXBeanProxy(MBeanServerConnection connection,
313                                        ObjectName objectName,
314                                        Class<T> interfaceClass) {
315         return newMXBeanProxy(connection, objectName, interfaceClass, false);
316     }
317
318     /**
319      * <p>Make a proxy for an MXBean in a local or remote MBean
320      * Server that may also support the methods of {@link
321      * NotificationEmitter}.</p>
322      *
323      * <p>This method behaves the same as {@link
324      * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)}, but
325      * additionally, if {@code notificationEmitter} is {@code
326      * true}, then the MXBean is assumed to be a {@link
327      * NotificationBroadcaster} or {@link NotificationEmitter} and the
328      * returned proxy will implement {@link NotificationEmitter} as
329      * well as {@code interfaceClass}.  A call to {@link
330      * NotificationBroadcaster#addNotificationListener} on the proxy
331      * will result in a call to {@link
332      * MBeanServerConnection#addNotificationListener(ObjectName,
333      * NotificationListener, NotificationFilter, Object)}, and
334      * likewise for the other methods of {@link
335      * NotificationBroadcaster} and {@link NotificationEmitter}.</p>
336      *
337      * @param connection the MBean server to forward to.
338      * @param objectName the name of the MBean within
339      * {@code connection} to forward to.
340      * @param interfaceClass the MXBean interface,
341      * which will also be implemented by the returned proxy.
342      * @param notificationEmitter make the returned proxy
343      * implement {@link NotificationEmitter} by forwarding its methods
344      * via {@code connection}.
345      *
346      * @param <T> allows the compiler to know that if the {@code
347      * interfaceClass} parameter is {@code MyMXBean.class}, for
348      * example, then the return type is {@code MyMXBean}.
349      *
350      * @return the new proxy instance.
351      *
352      * @throws IllegalArgumentException if {@code interfaceClass} is not
353      * a {@link javax.management.MXBean compliant MXBean interface}
354      */

355     public static <T> T newMXBeanProxy(MBeanServerConnection connection,
356                                        ObjectName objectName,
357                                        Class<T> interfaceClass,
358                                        boolean notificationEmitter) {
359         return createProxy(connection, objectName, interfaceClass, notificationEmitter, true);
360     }
361
362     /**
363      * <p>Test whether an interface is an MXBean interface.
364      * An interface is an MXBean interface if it is public,
365      * annotated {@link MXBean &#64;MXBean} or {@code @MXBean(true)}
366      * or if it does not have an {@code @MXBean} annotation
367      * and its name ends with "{@code MXBean}".</p>
368      *
369      * @param interfaceClass The candidate interface.
370      *
371      * @return true if {@code interfaceClass} is a
372      * {@link javax.management.MXBean compliant MXBean interface}
373      *
374      * @throws NullPointerException if {@code interfaceClass} is null.
375      */

376     public static boolean isMXBeanInterface(Class<?> interfaceClass) {
377         if (!interfaceClass.isInterface())
378             return false;
379         if (!Modifier.isPublic(interfaceClass.getModifiers()) &&
380             !Introspector.ALLOW_NONPUBLIC_MBEAN) {
381             return false;
382         }
383         MXBean a = interfaceClass.getAnnotation(MXBean.class);
384         if (a != null)
385             return a.value();
386         return interfaceClass.getName().endsWith("MXBean");
387         // We don't bother excluding the case where the name is
388         // exactly the string "MXBean" since that would mean there
389         // was no package name, which is pretty unlikely in practice.
390     }
391
392     /**
393      * Centralised M(X)Bean proxy creation code
394      * @param connection {@linkplain MBeanServerConnection} to use
395      * @param objectName M(X)Bean object name
396      * @param interfaceClass M(X)Bean interface class
397      * @param notificationEmitter Is a notification emitter?
398      * @param isMXBean Is an MXBean?
399      * @return Returns an M(X)Bean proxy generated for the provided interface class
400      * @throws SecurityException
401      * @throws IllegalArgumentException
402      */

403     private static <T> T createProxy(MBeanServerConnection connection,
404                                      ObjectName objectName,
405                                      Class<T> interfaceClass,
406                                      boolean notificationEmitter,
407                                      boolean isMXBean) {
408
409         try {
410             if (isMXBean) {
411                 // Check interface for MXBean compliance
412                 Introspector.testComplianceMXBeanInterface(interfaceClass);
413             } else {
414                 // Check interface for MBean compliance
415                 Introspector.testComplianceMBeanInterface(interfaceClass);
416             }
417         } catch (NotCompliantMBeanException e) {
418             throw new IllegalArgumentException(e);
419         }
420
421         InvocationHandler handler = new MBeanServerInvocationHandler(
422                 connection, objectName, isMXBean);
423         final Class<?>[] interfaces;
424         if (notificationEmitter) {
425             interfaces =
426                 new Class<?>[] {interfaceClass, NotificationEmitter.class};
427         } else
428             interfaces = new Class<?>[] {interfaceClass};
429
430         Object proxy = Proxy.newProxyInstance(
431                 interfaceClass.getClassLoader(),
432                 interfaces,
433                 handler);
434         return interfaceClass.cast(proxy);
435     }
436 }
437