Path: blob/master/src/java.management/share/classes/javax/management/JMX.java
41154 views
/*1* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.management;2627import com.sun.jmx.mbeanserver.Introspector;28import java.lang.reflect.InvocationHandler;29import java.lang.reflect.Modifier;30import java.lang.reflect.Proxy;31import sun.reflect.misc.ReflectUtil;3233/**34* Static methods from the JMX API. There are no instances of this class.35*36* @since 1.637*/38public class JMX {39/* Code within this package can prove that by providing this instance of40* this class.41*/42static final JMX proof = new JMX();4344private JMX() {}4546/**47* The name of the <a href="Descriptor.html#defaultValue">{@code48* defaultValue}</a> field.49*/50public static final String DEFAULT_VALUE_FIELD = "defaultValue";5152/**53* The name of the <a href="Descriptor.html#immutableInfo">{@code54* immutableInfo}</a> field.55*/56public static final String IMMUTABLE_INFO_FIELD = "immutableInfo";5758/**59* The name of the <a href="Descriptor.html#interfaceClassName">{@code60* interfaceClassName}</a> field.61*/62public static final String INTERFACE_CLASS_NAME_FIELD = "interfaceClassName";6364/**65* The name of the <a href="Descriptor.html#legalValues">{@code66* legalValues}</a> field.67*/68public static final String LEGAL_VALUES_FIELD = "legalValues";6970/**71* The name of the <a href="Descriptor.html#maxValue">{@code72* maxValue}</a> field.73*/74public static final String MAX_VALUE_FIELD = "maxValue";7576/**77* The name of the <a href="Descriptor.html#minValue">{@code78* minValue}</a> field.79*/80public static final String MIN_VALUE_FIELD = "minValue";8182/**83* The name of the <a href="Descriptor.html#mxbean">{@code84* mxbean}</a> field.85*/86public static final String MXBEAN_FIELD = "mxbean";8788/**89* The name of the <a href="Descriptor.html#openType">{@code90* openType}</a> field.91*/92public static final String OPEN_TYPE_FIELD = "openType";9394/**95* The name of the <a href="Descriptor.html#originalType">{@code96* originalType}</a> field.97*/98public static final String ORIGINAL_TYPE_FIELD = "originalType";99100/**101* <p>Make a proxy for a Standard MBean in a local or remote102* MBean Server.</p>103*104* <p>If you have an MBean Server {@code mbs} containing an MBean105* with {@link ObjectName} {@code name}, and if the MBean's106* management interface is described by the Java interface107* {@code MyMBean}, you can construct a proxy for the MBean like108* this:</p>109*110* <pre>111* MyMBean proxy = JMX.newMBeanProxy(mbs, name, MyMBean.class);112* </pre>113*114* <p>Suppose, for example, {@code MyMBean} looks like this:</p>115*116* <pre>117* public interface MyMBean {118* public String getSomeAttribute();119* public void setSomeAttribute(String value);120* public void someOperation(String param1, int param2);121* }122* </pre>123*124* <p>Then you can execute:</p>125*126* <ul>127*128* <li>{@code proxy.getSomeAttribute()} which will result in a129* call to {@code mbs.}{@link MBeanServerConnection#getAttribute130* getAttribute}{@code (name, "SomeAttribute")}.131*132* <li>{@code proxy.setSomeAttribute("whatever")} which will result133* in a call to {@code mbs.}{@link MBeanServerConnection#setAttribute134* setAttribute}{@code (name, new Attribute("SomeAttribute", "whatever"))}.135*136* <li>{@code proxy.someOperation("param1", 2)} which will be137* translated into a call to {@code mbs.}{@link138* MBeanServerConnection#invoke invoke}{@code (name, "someOperation", <etc>)}.139*140* </ul>141*142* <p>The object returned by this method is a143* {@link Proxy} whose {@code InvocationHandler} is an144* {@link MBeanServerInvocationHandler}.</p>145*146* <p>This method is equivalent to {@link147* #newMBeanProxy(MBeanServerConnection, ObjectName, Class,148* boolean) newMBeanProxy(connection, objectName, interfaceClass,149* false)}.</p>150*151* @param connection the MBean server to forward to.152* @param objectName the name of the MBean within153* {@code connection} to forward to.154* @param interfaceClass the management interface that the MBean155* exports, which will also be implemented by the returned proxy.156*157* @param <T> allows the compiler to know that if the {@code158* interfaceClass} parameter is {@code MyMBean.class}, for159* example, then the return type is {@code MyMBean}.160*161* @return the new proxy instance.162*163* @throws IllegalArgumentException if {@code interfaceClass} is not164* a <a href="package-summary.html#mgIface">compliant MBean165* interface</a>166*/167public static <T> T newMBeanProxy(MBeanServerConnection connection,168ObjectName objectName,169Class<T> interfaceClass) {170return newMBeanProxy(connection, objectName, interfaceClass, false);171}172173/**174* <p>Make a proxy for a Standard MBean in a local or remote MBean175* Server that may also support the methods of {@link176* NotificationEmitter}.</p>177*178* <p>This method behaves the same as {@link179* #newMBeanProxy(MBeanServerConnection, ObjectName, Class)}, but180* additionally, if {@code notificationEmitter} is {@code181* true}, then the MBean is assumed to be a {@link182* NotificationBroadcaster} or {@link NotificationEmitter} and the183* returned proxy will implement {@link NotificationEmitter} as184* well as {@code interfaceClass}. A call to {@link185* NotificationBroadcaster#addNotificationListener} on the proxy186* will result in a call to {@link187* MBeanServerConnection#addNotificationListener(ObjectName,188* NotificationListener, NotificationFilter, Object)}, and189* likewise for the other methods of {@link190* NotificationBroadcaster} and {@link NotificationEmitter}.</p>191*192* @param connection the MBean server to forward to.193* @param objectName the name of the MBean within194* {@code connection} to forward to.195* @param interfaceClass the management interface that the MBean196* exports, which will also be implemented by the returned proxy.197* @param notificationEmitter make the returned proxy198* implement {@link NotificationEmitter} by forwarding its methods199* via {@code connection}.200*201* @param <T> allows the compiler to know that if the {@code202* interfaceClass} parameter is {@code MyMBean.class}, for203* example, then the return type is {@code MyMBean}.204*205* @return the new proxy instance.206*207* @throws IllegalArgumentException if {@code interfaceClass} is not208* a <a href="package-summary.html#mgIface">compliant MBean209* interface</a>210*/211public static <T> T newMBeanProxy(MBeanServerConnection connection,212ObjectName objectName,213Class<T> interfaceClass,214boolean notificationEmitter) {215return createProxy(connection, objectName, interfaceClass, notificationEmitter, false);216}217218/**219* Make a proxy for an MXBean in a local or remote MBean Server.220*221* <p>If you have an MBean Server {@code mbs} containing an222* MXBean with {@link ObjectName} {@code name}, and if the223* MXBean's management interface is described by the Java224* interface {@code MyMXBean}, you can construct a proxy for225* the MXBean like this:</p>226*227* <pre>228* MyMXBean proxy = JMX.newMXBeanProxy(mbs, name, MyMXBean.class);229* </pre>230*231* <p>Suppose, for example, {@code MyMXBean} looks like this:</p>232*233* <pre>234* public interface MyMXBean {235* public String getSimpleAttribute();236* public void setSimpleAttribute(String value);237* public {@link java.lang.management.MemoryUsage} getMappedAttribute();238* public void setMappedAttribute(MemoryUsage memoryUsage);239* public MemoryUsage someOperation(String param1, MemoryUsage param2);240* }241* </pre>242*243* <p>Then:</p>244*245* <ul>246*247* <li><p>{@code proxy.getSimpleAttribute()} will result in a248* call to {@code mbs.}{@link MBeanServerConnection#getAttribute249* getAttribute}{@code (name, "SimpleAttribute")}.</p>250*251* <li><p>{@code proxy.setSimpleAttribute("whatever")} will result252* in a call to {@code mbs.}{@link253* MBeanServerConnection#setAttribute setAttribute}<code>(name,254* new Attribute("SimpleAttribute", "whatever"))</code>.</p>255*256* <p>Because {@code String} is a <em>simple type</em>, in the257* sense of {@link javax.management.openmbean.SimpleType}, it258* is not changed in the context of an MXBean. The MXBean259* proxy behaves the same as a Standard MBean proxy (see260* {@link #newMBeanProxy(MBeanServerConnection, ObjectName,261* Class) newMBeanProxy}) for the attribute {@code262* SimpleAttribute}.</p>263*264* <li><p>{@code proxy.getMappedAttribute()} will result in a call265* to {@code mbs.getAttribute("MappedAttribute")}. The MXBean266* mapping rules mean that the actual type of the attribute {@code267* MappedAttribute} will be {@link268* javax.management.openmbean.CompositeData CompositeData} and269* that is what the {@code mbs.getAttribute} call will return.270* The proxy will then convert the {@code CompositeData} back into271* the expected type {@code MemoryUsage} using the MXBean mapping272* rules.</p>273*274* <li><p>Similarly, {@code proxy.setMappedAttribute(memoryUsage)}275* will convert the {@code MemoryUsage} argument into a {@code276* CompositeData} before calling {@code mbs.setAttribute}.</p>277*278* <li><p>{@code proxy.someOperation("whatever", memoryUsage)}279* will convert the {@code MemoryUsage} argument into a {@code280* CompositeData} and call {@code mbs.invoke}. The value returned281* by {@code mbs.invoke} will be also be a {@code CompositeData},282* and the proxy will convert this into the expected type {@code283* MemoryUsage} using the MXBean mapping rules.</p>284*285* </ul>286*287* <p>The object returned by this method is a288* {@link Proxy} whose {@code InvocationHandler} is an289* {@link MBeanServerInvocationHandler}.</p>290*291* <p>This method is equivalent to {@link292* #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,293* boolean) newMXBeanProxy(connection, objectName, interfaceClass,294* false)}.</p>295*296* @param connection the MBean server to forward to.297* @param objectName the name of the MBean within298* {@code connection} to forward to.299* @param interfaceClass the MXBean interface,300* which will also be implemented by the returned proxy.301*302* @param <T> allows the compiler to know that if the {@code303* interfaceClass} parameter is {@code MyMXBean.class}, for304* example, then the return type is {@code MyMXBean}.305*306* @return the new proxy instance.307*308* @throws IllegalArgumentException if {@code interfaceClass} is not309* a {@link javax.management.MXBean compliant MXBean interface}310*/311public static <T> T newMXBeanProxy(MBeanServerConnection connection,312ObjectName objectName,313Class<T> interfaceClass) {314return newMXBeanProxy(connection, objectName, interfaceClass, false);315}316317/**318* <p>Make a proxy for an MXBean in a local or remote MBean319* Server that may also support the methods of {@link320* NotificationEmitter}.</p>321*322* <p>This method behaves the same as {@link323* #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)}, but324* additionally, if {@code notificationEmitter} is {@code325* true}, then the MXBean is assumed to be a {@link326* NotificationBroadcaster} or {@link NotificationEmitter} and the327* returned proxy will implement {@link NotificationEmitter} as328* well as {@code interfaceClass}. A call to {@link329* NotificationBroadcaster#addNotificationListener} on the proxy330* will result in a call to {@link331* MBeanServerConnection#addNotificationListener(ObjectName,332* NotificationListener, NotificationFilter, Object)}, and333* likewise for the other methods of {@link334* NotificationBroadcaster} and {@link NotificationEmitter}.</p>335*336* @param connection the MBean server to forward to.337* @param objectName the name of the MBean within338* {@code connection} to forward to.339* @param interfaceClass the MXBean interface,340* which will also be implemented by the returned proxy.341* @param notificationEmitter make the returned proxy342* implement {@link NotificationEmitter} by forwarding its methods343* via {@code connection}.344*345* @param <T> allows the compiler to know that if the {@code346* interfaceClass} parameter is {@code MyMXBean.class}, for347* example, then the return type is {@code MyMXBean}.348*349* @return the new proxy instance.350*351* @throws IllegalArgumentException if {@code interfaceClass} is not352* a {@link javax.management.MXBean compliant MXBean interface}353*/354public static <T> T newMXBeanProxy(MBeanServerConnection connection,355ObjectName objectName,356Class<T> interfaceClass,357boolean notificationEmitter) {358return createProxy(connection, objectName, interfaceClass, notificationEmitter, true);359}360361/**362* <p>Test whether an interface is an MXBean interface.363* An interface is an MXBean interface if it is public,364* annotated {@link MXBean @MXBean} or {@code @MXBean(true)}365* or if it does not have an {@code @MXBean} annotation366* and its name ends with "{@code MXBean}".</p>367*368* @param interfaceClass The candidate interface.369*370* @return true if {@code interfaceClass} is a371* {@link javax.management.MXBean compliant MXBean interface}372*373* @throws NullPointerException if {@code interfaceClass} is null.374*/375public static boolean isMXBeanInterface(Class<?> interfaceClass) {376if (!interfaceClass.isInterface())377return false;378if (!Modifier.isPublic(interfaceClass.getModifiers()) &&379!Introspector.ALLOW_NONPUBLIC_MBEAN) {380return false;381}382MXBean a = interfaceClass.getAnnotation(MXBean.class);383if (a != null)384return a.value();385return interfaceClass.getName().endsWith("MXBean");386// We don't bother excluding the case where the name is387// exactly the string "MXBean" since that would mean there388// was no package name, which is pretty unlikely in practice.389}390391/**392* Centralised M(X)Bean proxy creation code393* @param connection {@linkplain MBeanServerConnection} to use394* @param objectName M(X)Bean object name395* @param interfaceClass M(X)Bean interface class396* @param notificationEmitter Is a notification emitter?397* @param isMXBean Is an MXBean?398* @return Returns an M(X)Bean proxy generated for the provided interface class399* @throws SecurityException400* @throws IllegalArgumentException401*/402private static <T> T createProxy(MBeanServerConnection connection,403ObjectName objectName,404Class<T> interfaceClass,405boolean notificationEmitter,406boolean isMXBean) {407408try {409if (isMXBean) {410// Check interface for MXBean compliance411Introspector.testComplianceMXBeanInterface(interfaceClass);412} else {413// Check interface for MBean compliance414Introspector.testComplianceMBeanInterface(interfaceClass);415}416} catch (NotCompliantMBeanException e) {417throw new IllegalArgumentException(e);418}419420InvocationHandler handler = new MBeanServerInvocationHandler(421connection, objectName, isMXBean);422final Class<?>[] interfaces;423if (notificationEmitter) {424interfaces =425new Class<?>[] {interfaceClass, NotificationEmitter.class};426} else427interfaces = new Class<?>[] {interfaceClass};428429Object proxy = Proxy.newProxyInstance(430interfaceClass.getClassLoader(),431interfaces,432handler);433return interfaceClass.cast(proxy);434}435}436437438