/* * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.management; import com.sun.jmx.mbeanserver.Introspector; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; import sun.reflect.misc.ReflectUtil; /** * Static methods from the JMX API. There are no instances of this class. * * @since 1.6 */ public class JMX { /* Code within this package can prove that by providing this instance of * this class. */ static final JMX proof = new JMX(); private JMX() {} /** * The name of the {@code * defaultValue} field. */ public static final String DEFAULT_VALUE_FIELD = "defaultValue"; /** * The name of the {@code * immutableInfo} field. */ public static final String IMMUTABLE_INFO_FIELD = "immutableInfo"; /** * The name of the {@code * interfaceClassName} field. */ public static final String INTERFACE_CLASS_NAME_FIELD = "interfaceClassName"; /** * The name of the {@code * legalValues} field. */ public static final String LEGAL_VALUES_FIELD = "legalValues"; /** * The name of the {@code * maxValue} field. */ public static final String MAX_VALUE_FIELD = "maxValue"; /** * The name of the {@code * minValue} field. */ public static final String MIN_VALUE_FIELD = "minValue"; /** * The name of the {@code * mxbean} field. */ public static final String MXBEAN_FIELD = "mxbean"; /** * The name of the {@code * openType} field. */ public static final String OPEN_TYPE_FIELD = "openType"; /** * The name of the {@code * originalType} field. */ public static final String ORIGINAL_TYPE_FIELD = "originalType"; /** *

Make a proxy for a Standard MBean in a local or remote * MBean Server.

* *

If you have an MBean Server {@code mbs} containing an MBean * with {@link ObjectName} {@code name}, and if the MBean's * management interface is described by the Java interface * {@code MyMBean}, you can construct a proxy for the MBean like * this:

* *
     * MyMBean proxy = JMX.newMBeanProxy(mbs, name, MyMBean.class);
     * 
* *

Suppose, for example, {@code MyMBean} looks like this:

* *
     * public interface MyMBean {
     *     public String getSomeAttribute();
     *     public void setSomeAttribute(String value);
     *     public void someOperation(String param1, int param2);
     * }
     * 
* *

Then you can execute:

* * * *

The object returned by this method is a * {@link Proxy} whose {@code InvocationHandler} is an * {@link MBeanServerInvocationHandler}.

* *

This method is equivalent to {@link * #newMBeanProxy(MBeanServerConnection, ObjectName, Class, * boolean) newMBeanProxy(connection, objectName, interfaceClass, * false)}.

* * @param connection the MBean server to forward to. * @param objectName the name of the MBean within * {@code connection} to forward to. * @param interfaceClass the management interface that the MBean * exports, which will also be implemented by the returned proxy. * * @param allows the compiler to know that if the {@code * interfaceClass} parameter is {@code MyMBean.class}, for * example, then the return type is {@code MyMBean}. * * @return the new proxy instance. * * @throws IllegalArgumentException if {@code interfaceClass} is not * a compliant MBean * interface */ public static T newMBeanProxy(MBeanServerConnection connection, ObjectName objectName, Class interfaceClass) { return newMBeanProxy(connection, objectName, interfaceClass, false); } /** *

Make a proxy for a Standard MBean in a local or remote MBean * Server that may also support the methods of {@link * NotificationEmitter}.

* *

This method behaves the same as {@link * #newMBeanProxy(MBeanServerConnection, ObjectName, Class)}, but * additionally, if {@code notificationEmitter} is {@code * true}, then the MBean is assumed to be a {@link * NotificationBroadcaster} or {@link NotificationEmitter} and the * returned proxy will implement {@link NotificationEmitter} as * well as {@code interfaceClass}. A call to {@link * NotificationBroadcaster#addNotificationListener} on the proxy * will result in a call to {@link * MBeanServerConnection#addNotificationListener(ObjectName, * NotificationListener, NotificationFilter, Object)}, and * likewise for the other methods of {@link * NotificationBroadcaster} and {@link NotificationEmitter}.

* * @param connection the MBean server to forward to. * @param objectName the name of the MBean within * {@code connection} to forward to. * @param interfaceClass the management interface that the MBean * exports, which will also be implemented by the returned proxy. * @param notificationEmitter make the returned proxy * implement {@link NotificationEmitter} by forwarding its methods * via {@code connection}. * * @param allows the compiler to know that if the {@code * interfaceClass} parameter is {@code MyMBean.class}, for * example, then the return type is {@code MyMBean}. * * @return the new proxy instance. * * @throws IllegalArgumentException if {@code interfaceClass} is not * a compliant MBean * interface */ public static T newMBeanProxy(MBeanServerConnection connection, ObjectName objectName, Class interfaceClass, boolean notificationEmitter) { return createProxy(connection, objectName, interfaceClass, notificationEmitter, false); } /** * Make a proxy for an MXBean in a local or remote MBean Server. * *

If you have an MBean Server {@code mbs} containing an * MXBean with {@link ObjectName} {@code name}, and if the * MXBean's management interface is described by the Java * interface {@code MyMXBean}, you can construct a proxy for * the MXBean like this:

* *
     * MyMXBean proxy = JMX.newMXBeanProxy(mbs, name, MyMXBean.class);
     * 
* *

Suppose, for example, {@code MyMXBean} looks like this:

* *
     * public interface MyMXBean {
     *     public String getSimpleAttribute();
     *     public void setSimpleAttribute(String value);
     *     public {@link java.lang.management.MemoryUsage} getMappedAttribute();
     *     public void setMappedAttribute(MemoryUsage memoryUsage);
     *     public MemoryUsage someOperation(String param1, MemoryUsage param2);
     * }
     * 
* *

Then:

* *
    * *
  • {@code proxy.getSimpleAttribute()} will result in a * call to {@code mbs.}{@link MBeanServerConnection#getAttribute * getAttribute}{@code (name, "SimpleAttribute")}.

    * *
  • {@code proxy.setSimpleAttribute("whatever")} will result * in a call to {@code mbs.}{@link * MBeanServerConnection#setAttribute setAttribute}(name, * new Attribute("SimpleAttribute", "whatever")).

    * *

    Because {@code String} is a simple type, in the * sense of {@link javax.management.openmbean.SimpleType}, it * is not changed in the context of an MXBean. The MXBean * proxy behaves the same as a Standard MBean proxy (see * {@link #newMBeanProxy(MBeanServerConnection, ObjectName, * Class) newMBeanProxy}) for the attribute {@code * SimpleAttribute}.

    * *
  • {@code proxy.getMappedAttribute()} will result in a call * to {@code mbs.getAttribute("MappedAttribute")}. The MXBean * mapping rules mean that the actual type of the attribute {@code * MappedAttribute} will be {@link * javax.management.openmbean.CompositeData CompositeData} and * that is what the {@code mbs.getAttribute} call will return. * The proxy will then convert the {@code CompositeData} back into * the expected type {@code MemoryUsage} using the MXBean mapping * rules.

    * *
  • Similarly, {@code proxy.setMappedAttribute(memoryUsage)} * will convert the {@code MemoryUsage} argument into a {@code * CompositeData} before calling {@code mbs.setAttribute}.

    * *
  • {@code proxy.someOperation("whatever", memoryUsage)} * will convert the {@code MemoryUsage} argument into a {@code * CompositeData} and call {@code mbs.invoke}. The value returned * by {@code mbs.invoke} will be also be a {@code CompositeData}, * and the proxy will convert this into the expected type {@code * MemoryUsage} using the MXBean mapping rules.

    * *
* *

The object returned by this method is a * {@link Proxy} whose {@code InvocationHandler} is an * {@link MBeanServerInvocationHandler}.

* *

This method is equivalent to {@link * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class, * boolean) newMXBeanProxy(connection, objectName, interfaceClass, * false)}.

* * @param connection the MBean server to forward to. * @param objectName the name of the MBean within * {@code connection} to forward to. * @param interfaceClass the MXBean interface, * which will also be implemented by the returned proxy. * * @param allows the compiler to know that if the {@code * interfaceClass} parameter is {@code MyMXBean.class}, for * example, then the return type is {@code MyMXBean}. * * @return the new proxy instance. * * @throws IllegalArgumentException if {@code interfaceClass} is not * a {@link javax.management.MXBean compliant MXBean interface} */ public static T newMXBeanProxy(MBeanServerConnection connection, ObjectName objectName, Class interfaceClass) { return newMXBeanProxy(connection, objectName, interfaceClass, false); } /** *

Make a proxy for an MXBean in a local or remote MBean * Server that may also support the methods of {@link * NotificationEmitter}.

* *

This method behaves the same as {@link * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)}, but * additionally, if {@code notificationEmitter} is {@code * true}, then the MXBean is assumed to be a {@link * NotificationBroadcaster} or {@link NotificationEmitter} and the * returned proxy will implement {@link NotificationEmitter} as * well as {@code interfaceClass}. A call to {@link * NotificationBroadcaster#addNotificationListener} on the proxy * will result in a call to {@link * MBeanServerConnection#addNotificationListener(ObjectName, * NotificationListener, NotificationFilter, Object)}, and * likewise for the other methods of {@link * NotificationBroadcaster} and {@link NotificationEmitter}.

* * @param connection the MBean server to forward to. * @param objectName the name of the MBean within * {@code connection} to forward to. * @param interfaceClass the MXBean interface, * which will also be implemented by the returned proxy. * @param notificationEmitter make the returned proxy * implement {@link NotificationEmitter} by forwarding its methods * via {@code connection}. * * @param allows the compiler to know that if the {@code * interfaceClass} parameter is {@code MyMXBean.class}, for * example, then the return type is {@code MyMXBean}. * * @return the new proxy instance. * * @throws IllegalArgumentException if {@code interfaceClass} is not * a {@link javax.management.MXBean compliant MXBean interface} */ public static T newMXBeanProxy(MBeanServerConnection connection, ObjectName objectName, Class interfaceClass, boolean notificationEmitter) { return createProxy(connection, objectName, interfaceClass, notificationEmitter, true); } /** *

Test whether an interface is an MXBean interface. * An interface is an MXBean interface if it is public, * annotated {@link MXBean @MXBean} or {@code @MXBean(true)} * or if it does not have an {@code @MXBean} annotation * and its name ends with "{@code MXBean}".

* * @param interfaceClass The candidate interface. * * @return true if {@code interfaceClass} is a * {@link javax.management.MXBean compliant MXBean interface} * * @throws NullPointerException if {@code interfaceClass} is null. */ public static boolean isMXBeanInterface(Class interfaceClass) { if (!interfaceClass.isInterface()) return false; if (!Modifier.isPublic(interfaceClass.getModifiers()) && !Introspector.ALLOW_NONPUBLIC_MBEAN) { return false; } MXBean a = interfaceClass.getAnnotation(MXBean.class); if (a != null) return a.value(); return interfaceClass.getName().endsWith("MXBean"); // We don't bother excluding the case where the name is // exactly the string "MXBean" since that would mean there // was no package name, which is pretty unlikely in practice. } /** * Centralised M(X)Bean proxy creation code * @param connection {@linkplain MBeanServerConnection} to use * @param objectName M(X)Bean object name * @param interfaceClass M(X)Bean interface class * @param notificationEmitter Is a notification emitter? * @param isMXBean Is an MXBean? * @return Returns an M(X)Bean proxy generated for the provided interface class * @throws SecurityException * @throws IllegalArgumentException */ private static T createProxy(MBeanServerConnection connection, ObjectName objectName, Class interfaceClass, boolean notificationEmitter, boolean isMXBean) { try { if (isMXBean) { // Check interface for MXBean compliance Introspector.testComplianceMXBeanInterface(interfaceClass); } else { // Check interface for MBean compliance Introspector.testComplianceMBeanInterface(interfaceClass); } } catch (NotCompliantMBeanException e) { throw new IllegalArgumentException(e); } InvocationHandler handler = new MBeanServerInvocationHandler( connection, objectName, isMXBean); final Class[] interfaces; if (notificationEmitter) { interfaces = new Class[] {interfaceClass, NotificationEmitter.class}; } else interfaces = new Class[] {interfaceClass}; Object proxy = Proxy.newProxyInstance( interfaceClass.getClassLoader(), interfaces, handler); return interfaceClass.cast(proxy); } }