jdk/src/share/classes/javax/management/JMX.java
changeset 2 90ce3da70b43
child 687 874e25a9844a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/JMX.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2005-2006 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.Proxy;
+
+/**
+ * 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 <a href="Descriptor.html#defaultValue">{@code
+     * defaultValue}</a> field.
+     */
+    public static final String DEFAULT_VALUE_FIELD = "defaultValue";
+
+    /**
+     * The name of the <a href="Descriptor.html#immutableInfo">{@code
+     * immutableInfo}</a> field.
+     */
+    public static final String IMMUTABLE_INFO_FIELD = "immutableInfo";
+
+    /**
+     * The name of the <a href="Descriptor.html#interfaceClassName">{@code
+     * interfaceClassName}</a> field.
+     */
+    public static final String INTERFACE_CLASS_NAME_FIELD = "interfaceClassName";
+
+    /**
+     * The name of the <a href="Descriptor.html#legalValues">{@code
+     * legalValues}</a> field.
+     */
+    public static final String LEGAL_VALUES_FIELD = "legalValues";
+
+    /**
+     * The name of the <a href="Descriptor.html#maxValue">{@code
+     * maxValue}</a> field.
+     */
+    public static final String MAX_VALUE_FIELD = "maxValue";
+
+    /**
+     * The name of the <a href="Descriptor.html#minValue">{@code
+     * minValue}</a> field.
+     */
+    public static final String MIN_VALUE_FIELD = "minValue";
+
+    /**
+     * The name of the <a href="Descriptor.html#mxbean">{@code
+     * mxbean}</a> field.
+     */
+    public static final String MXBEAN_FIELD = "mxbean";
+
+    /**
+     * The name of the <a href="Descriptor.html#openType">{@code
+     * openType}</a> field.
+     */
+    public static final String OPEN_TYPE_FIELD = "openType";
+
+    /**
+     * The name of the <a href="Descriptor.html#originalType">{@code
+     * originalType}</a> field.
+     */
+    public static final String ORIGINAL_TYPE_FIELD = "originalType";
+
+    /**
+     * <p>Make a proxy for a Standard MBean in a local or remote
+     * MBean Server.</p>
+     *
+     * <p>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:</p>
+     *
+     * <pre>
+     * MyMBean proxy = JMX.newMBeanProxy(mbs, name, MyMBean.class);
+     * </pre>
+     *
+     * <p>Suppose, for example, {@code MyMBean} looks like this:</p>
+     *
+     * <pre>
+     * public interface MyMBean {
+     *     public String getSomeAttribute();
+     *     public void setSomeAttribute(String value);
+     *     public void someOperation(String param1, int param2);
+     * }
+     * </pre>
+     *
+     * <p>Then you can execute:</p>
+     *
+     * <ul>
+     *
+     * <li>{@code proxy.getSomeAttribute()} which will result in a
+     * call to {@code mbs.}{@link MBeanServerConnection#getAttribute
+     * getAttribute}{@code (name, "SomeAttribute")}.
+     *
+     * <li>{@code proxy.setSomeAttribute("whatever")} which will result
+     * in a call to {@code mbs.}{@link MBeanServerConnection#setAttribute
+     * setAttribute}{@code (name, new Attribute("SomeAttribute", "whatever"))}.
+     *
+     * <li>{@code proxy.someOperation("param1", 2)} which will be
+     * translated into a call to {@code mbs.}{@link
+     * MBeanServerConnection#invoke invoke}{@code (name, "someOperation", <etc>)}.
+     *
+     * </ul>
+     *
+     * <p>The object returned by this method is a
+     * {@link Proxy} whose {@code InvocationHandler} is an
+     * {@link MBeanServerInvocationHandler}.</p>
+     *
+     * <p>This method is equivalent to {@link
+     * #newMBeanProxy(MBeanServerConnection, ObjectName, Class,
+     * boolean) newMBeanProxy(connection, objectName, interfaceClass,
+     * false)}.</p>
+     *
+     * @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 <T> 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.
+     */
+    public static <T> T newMBeanProxy(MBeanServerConnection connection,
+                                      ObjectName objectName,
+                                      Class<T> interfaceClass) {
+        return newMBeanProxy(connection, objectName, interfaceClass, false);
+    }
+
+    /**
+     * <p>Make a proxy for a Standard MBean in a local or remote MBean
+     * Server that may also support the methods of {@link
+     * NotificationEmitter}.</p>
+     *
+     * <p>This method behaves the same as {@link
+     * #newMBeanProxy(MBeanServerConnection, ObjectName, Class)}, but
+     * additionally, if {@code notificationBroadcaster} 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}.</p>
+     *
+     * @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 notificationBroadcaster make the returned proxy
+     * implement {@link NotificationEmitter} by forwarding its methods
+     * via {@code connection}.
+     *
+     * @param <T> 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.
+     */
+    public static <T> T newMBeanProxy(MBeanServerConnection connection,
+                                      ObjectName objectName,
+                                      Class<T> interfaceClass,
+                                      boolean notificationBroadcaster) {
+        return MBeanServerInvocationHandler.newProxyInstance(
+                connection,
+                objectName,
+                interfaceClass,
+                notificationBroadcaster);
+    }
+
+    /**
+     * <p>Make a proxy for an MXBean in a local or remote
+     * MBean Server.</p>
+     *
+     * <p>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:</p>
+     *
+     * <pre>
+     * MyMXBean proxy = JMX.newMXBeanProxy(mbs, name, MyMXBean.class);
+     * </pre>
+     *
+     * <p>Suppose, for example, {@code MyMXBean} looks like this:</p>
+     *
+     * <pre>
+     * 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);
+     * }
+     * </pre>
+     *
+     * <p>Then:</p>
+     *
+     * <ul>
+     *
+     * <li><p>{@code proxy.getSimpleAttribute()} will result in a
+     * call to {@code mbs.}{@link MBeanServerConnection#getAttribute
+     * getAttribute}{@code (name, "SimpleAttribute")}.</p>
+     *
+     * <li><p>{@code proxy.setSimpleAttribute("whatever")} will result
+     * in a call to {@code mbs.}{@link
+     * MBeanServerConnection#setAttribute setAttribute}<code>(name,
+     * new Attribute("SimpleAttribute", "whatever"))</code>.<p>
+     *
+     *     <p>Because {@code String} is a <em>simple type</em>, 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}.</p>
+     *
+     * <li><p>{@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.</p>
+     *
+     * <li><p>Similarly, {@code proxy.setMappedAttribute(memoryUsage)}
+     * will convert the {@code MemoryUsage} argument into a {@code
+     * CompositeData} before calling {@code mbs.setAttribute}.</p>
+     *
+     * <li><p>{@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.</p>
+     *
+     * </ul>
+     *
+     * <p>The object returned by this method is a
+     * {@link Proxy} whose {@code InvocationHandler} is an
+     * {@link MBeanServerInvocationHandler}.</p>
+     *
+     * <p>This method is equivalent to {@link
+     * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,
+     * boolean) newMXBeanProxy(connection, objectName, interfaceClass,
+     * false)}.</p>
+     *
+     * @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 <T> 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.
+     */
+    public static <T> T newMXBeanProxy(MBeanServerConnection connection,
+                                       ObjectName objectName,
+                                       Class<T> interfaceClass) {
+        return newMXBeanProxy(connection, objectName, interfaceClass, false);
+    }
+
+    /**
+     * <p>Make a proxy for an MXBean in a local or remote MBean
+     * Server that may also support the methods of {@link
+     * NotificationEmitter}.</p>
+     *
+     * <p>This method behaves the same as {@link
+     * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)}, but
+     * additionally, if {@code notificationBroadcaster} 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}.</p>
+     *
+     * @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 notificationBroadcaster make the returned proxy
+     * implement {@link NotificationEmitter} by forwarding its methods
+     * via {@code connection}.
+     *
+     * @param <T> 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.
+     */
+    public static <T> T newMXBeanProxy(MBeanServerConnection connection,
+                                       ObjectName objectName,
+                                       Class<T> interfaceClass,
+                                       boolean notificationBroadcaster) {
+        // Check interface for MXBean compliance
+        //
+        try {
+            Introspector.testComplianceMXBeanInterface(interfaceClass);
+        } catch (NotCompliantMBeanException e) {
+            throw new IllegalArgumentException(e);
+        }
+        InvocationHandler handler = new MBeanServerInvocationHandler(
+                connection, objectName, true);
+        final Class[] interfaces;
+        if (notificationBroadcaster) {
+            interfaces =
+                new Class<?>[] {interfaceClass, NotificationEmitter.class};
+        } else
+            interfaces = new Class[] {interfaceClass};
+        Object proxy = Proxy.newProxyInstance(
+                interfaceClass.getClassLoader(),
+                interfaces,
+                handler);
+        return interfaceClass.cast(proxy);
+    }
+
+    /**
+     * <p>Test whether an interface is an MXBean interface.
+     * An interface is an MXBean interface if it is annotated
+     * {@link MXBean &#64;MXBean} or {@code @MXBean(true)}
+     * or if it does not have an {@code @MXBean} annotation
+     * and its name ends with "{@code MXBean}".</p>
+     *
+     * @param interfaceClass The candidate interface.
+     *
+     * @return true if {@code interfaceClass} is an interface and
+     * meets the conditions described.
+     *
+     * @throws NullPointerException if {@code interfaceClass} is null.
+     */
+    public static boolean isMXBeanInterface(Class<?> interfaceClass) {
+        if (!interfaceClass.isInterface())
+            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.
+    }
+}