jdk/src/share/classes/javax/management/JMX.java
changeset 4156 acaa49a2768a
parent 1700 4506662fb2ee
child 5506 202f599c92aa
equal deleted inserted replaced
4155:460e37d40f12 4156:acaa49a2768a
     1 /*
     1 /*
     2  * Copyright 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
     2  * Copyright 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Sun designates this
     7  * published by the Free Software Foundation.  Sun designates this
    24  */
    24  */
    25 
    25 
    26 package javax.management;
    26 package javax.management;
    27 
    27 
    28 import com.sun.jmx.mbeanserver.Introspector;
    28 import com.sun.jmx.mbeanserver.Introspector;
    29 import com.sun.jmx.mbeanserver.MBeanInjector;
       
    30 import com.sun.jmx.remote.util.ClassLogger;
       
    31 import java.beans.BeanInfo;
       
    32 import java.beans.PropertyDescriptor;
       
    33 import java.io.IOException;
       
    34 import java.io.Serializable;
       
    35 import java.lang.reflect.InvocationHandler;
    29 import java.lang.reflect.InvocationHandler;
    36 import java.lang.reflect.InvocationTargetException;
       
    37 import java.lang.reflect.Method;
       
    38 import java.lang.reflect.Proxy;
    30 import java.lang.reflect.Proxy;
    39 import java.util.Map;
       
    40 import java.util.TreeMap;
       
    41 import javax.management.namespace.JMXNamespaces;
       
    42 import javax.management.openmbean.MXBeanMappingFactory;
       
    43 
    31 
    44 /**
    32 /**
    45  * Static methods from the JMX API.  There are no instances of this class.
    33  * Static methods from the JMX API.  There are no instances of this class.
    46  *
    34  *
    47  * @since 1.6
    35  * @since 1.6
    58      * The name of the <a href="Descriptor.html#defaultValue">{@code
    46      * The name of the <a href="Descriptor.html#defaultValue">{@code
    59      * defaultValue}</a> field.
    47      * defaultValue}</a> field.
    60      */
    48      */
    61     public static final String DEFAULT_VALUE_FIELD = "defaultValue";
    49     public static final String DEFAULT_VALUE_FIELD = "defaultValue";
    62 
    50 
    63    /**
       
    64      * The name of the <a
       
    65      * href="Descriptor.html#descriptionResourceBundleBaseName">{@code
       
    66      * descriptionResourceBundleBaseName}</a> field.
       
    67      */
       
    68     public static final String DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD =
       
    69             "descriptionResourceBundleBaseName";
       
    70 
       
    71     /**
       
    72      * The name of the <a href="Descriptor.html#descriptionResourceKey">{@code
       
    73      * descriptionResourceKey}</a> field.
       
    74      */
       
    75     public static final String DESCRIPTION_RESOURCE_KEY_FIELD =
       
    76             "descriptionResourceKey";
       
    77 
       
    78     /**
       
    79      * The name of the <a href="Descriptor.html#exceptions">{@code
       
    80      * exceptions}</a> field.
       
    81      */
       
    82     public static final String EXCEPTIONS_FIELD = "exceptions";
       
    83 
       
    84     /**
    51     /**
    85      * The name of the <a href="Descriptor.html#immutableInfo">{@code
    52      * The name of the <a href="Descriptor.html#immutableInfo">{@code
    86      * immutableInfo}</a> field.
    53      * immutableInfo}</a> field.
    87      */
    54      */
    88     public static final String IMMUTABLE_INFO_FIELD = "immutableInfo";
    55     public static final String IMMUTABLE_INFO_FIELD = "immutableInfo";
    98      * legalValues}</a> field.
    65      * legalValues}</a> field.
    99      */
    66      */
   100     public static final String LEGAL_VALUES_FIELD = "legalValues";
    67     public static final String LEGAL_VALUES_FIELD = "legalValues";
   101 
    68 
   102     /**
    69     /**
   103      * The name of the <a href="Descriptor.html#locale">{@code locale}</a>
       
   104      * field.
       
   105      */
       
   106     public static final String LOCALE_FIELD = "locale";
       
   107 
       
   108     /**
       
   109      * The name of the <a href="Descriptor.html#maxValue">{@code
    70      * The name of the <a href="Descriptor.html#maxValue">{@code
   110      * maxValue}</a> field.
    71      * maxValue}</a> field.
   111      */
    72      */
   112     public static final String MAX_VALUE_FIELD = "maxValue";
    73     public static final String MAX_VALUE_FIELD = "maxValue";
   113 
    74 
   122      * mxbean}</a> field.
    83      * mxbean}</a> field.
   123      */
    84      */
   124     public static final String MXBEAN_FIELD = "mxbean";
    85     public static final String MXBEAN_FIELD = "mxbean";
   125 
    86 
   126     /**
    87     /**
   127      * The name of the
       
   128      * <a href="Descriptor.html#mxbeanMappingFactoryClass">{@code
       
   129      * mxbeanMappingFactoryClass}</a> field.
       
   130      */
       
   131     public static final String MXBEAN_MAPPING_FACTORY_CLASS_FIELD =
       
   132             "mxbeanMappingFactoryClass";
       
   133 
       
   134     /**
       
   135      * The name of the <a href="Descriptor.html#openType">{@code
    88      * The name of the <a href="Descriptor.html#openType">{@code
   136      * openType}</a> field.
    89      * openType}</a> field.
   137      */
    90      */
   138     public static final String OPEN_TYPE_FIELD = "openType";
    91     public static final String OPEN_TYPE_FIELD = "openType";
   139 
    92 
   140     /**
    93     /**
   141      * The name of the <a href="Descriptor.html#originalType">{@code
    94      * The name of the <a href="Descriptor.html#originalType">{@code
   142      * originalType}</a> field.
    95      * originalType}</a> field.
   143      */
    96      */
   144     public static final String ORIGINAL_TYPE_FIELD = "originalType";
    97     public static final String ORIGINAL_TYPE_FIELD = "originalType";
   145 
       
   146     /**
       
   147      * The name of the <a href="Descriptor.html#setExceptions">{@code
       
   148      * setExceptions}</a> field.
       
   149      */
       
   150     public static final String SET_EXCEPTIONS_FIELD = "setExceptions";
       
   151 
       
   152     /**
       
   153      * The name of the <a href="Descriptor.html#objectNameTemplate">{@code
       
   154      * objectNameTemplate}</a> field.
       
   155      */
       
   156     public static final String OBJECT_NAME_TEMPLATE = "objectNameTemplate";
       
   157 
       
   158     /**
       
   159      * <p>Options to apply to an MBean proxy or to an instance of {@link
       
   160      * StandardMBean}.</p>
       
   161      *
       
   162      * <p>For example, to specify the "wrapped object visible" option for a
       
   163      * {@code StandardMBean}, you might write this:</p>
       
   164      *
       
   165      * <pre>
       
   166      * StandardMBean.Options opts = new StandardMBean.Options();
       
   167      * opts.setWrappedObjectVisible(true);
       
   168      * StandardMBean mbean = new StandardMBean(impl, intf, opts);
       
   169      * </pre>
       
   170      *
       
   171      * @see javax.management.JMX.ProxyOptions
       
   172      * @see javax.management.StandardMBean.Options
       
   173      */
       
   174     public static class MBeanOptions implements Serializable, Cloneable {
       
   175         private static final long serialVersionUID = -6380842449318177843L;
       
   176 
       
   177         static final MBeanOptions MXBEAN = new MBeanOptions();
       
   178         static {
       
   179             MXBEAN.setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
       
   180         }
       
   181 
       
   182         private MXBeanMappingFactory mappingFactory;
       
   183 
       
   184         /**
       
   185          * <p>Construct an {@code MBeanOptions} object where all options have
       
   186          * their default values.</p>
       
   187          */
       
   188         public MBeanOptions() {}
       
   189 
       
   190         @Override
       
   191         public MBeanOptions clone() {
       
   192             try {
       
   193                 return (MBeanOptions) super.clone();
       
   194             } catch (CloneNotSupportedException e) {
       
   195                 throw new AssertionError(e);
       
   196             }
       
   197         }
       
   198 
       
   199         /**
       
   200          * <p>True if this is an MXBean proxy or a StandardMBean instance
       
   201          * that is an MXBean.  The default value is false.</p>
       
   202          *
       
   203          * <p>This method is equivalent to {@link #getMXBeanMappingFactory()
       
   204          * this.getMXBeanMappingFactory()}{@code != null}.</p>
       
   205          *
       
   206          * @return true if this is an MXBean proxy or a StandardMBean instance
       
   207          * that is an MXBean.
       
   208          */
       
   209         public boolean isMXBean() {
       
   210             return (this.mappingFactory != null);
       
   211         }
       
   212 
       
   213         /**
       
   214          * <p>The mappings between Java types and Open Types to be used in
       
   215          * an MXBean proxy or a StandardMBean instance that is an MXBean,
       
   216          * or null if this instance is not for an MXBean.
       
   217          * The default value is null.</p>
       
   218          *
       
   219          * @return the mappings to be used in this proxy or StandardMBean,
       
   220          * or null if this instance is not for an MXBean.
       
   221          */
       
   222         public MXBeanMappingFactory getMXBeanMappingFactory() {
       
   223             return mappingFactory;
       
   224         }
       
   225 
       
   226         /**
       
   227          * <p>Set the {@link #getMXBeanMappingFactory() MXBeanMappingFactory} to
       
   228          * the given value.  The value should be null if this instance is not
       
   229          * for an MXBean.  If this instance is for an MXBean, the value should
       
   230          * usually be either a custom mapping factory, or
       
   231          * {@link MXBeanMappingFactory#forInterface
       
   232          * MXBeanMappingFactory.forInterface}{@code (mxbeanInterface)}
       
   233          * which signifies
       
   234          * that the {@linkplain MXBeanMappingFactory#DEFAULT default} mapping
       
   235          * factory should be used unless an {@code @}{@link
       
   236          * javax.management.openmbean.MXBeanMappingFactoryClass
       
   237          * MXBeanMappingFactoryClass} annotation on {@code mxbeanInterface}
       
   238          * specifies otherwise.</p>
       
   239          *
       
   240          * <p>Examples:</p>
       
   241          * <pre>
       
   242          * MBeanOptions opts = new MBeanOptions();
       
   243          * opts.setMXBeanMappingFactory(myMappingFactory);
       
   244          * MyMXBean proxy = JMX.newMBeanProxy(
       
   245          *         mbeanServerConnection, objectName, MyMXBean.class, opts);
       
   246          *
       
   247          * // ...or...
       
   248          *
       
   249          * MBeanOptions opts = new MBeanOptions();
       
   250          * MXBeanMappingFactory defaultFactoryForMyMXBean =
       
   251          *         MXBeanMappingFactory.forInterface(MyMXBean.class);
       
   252          * opts.setMXBeanMappingFactory(defaultFactoryForMyMXBean);
       
   253          * MyMXBean proxy = JMX.newMBeanProxy(
       
   254          *         mbeanServerConnection, objectName, MyMXBean.class, opts);
       
   255          * </pre>
       
   256          *
       
   257          * @param f the new value.  If null, this instance is not for an
       
   258          * MXBean.
       
   259          */
       
   260         public void setMXBeanMappingFactory(MXBeanMappingFactory f) {
       
   261             this.mappingFactory = f;
       
   262         }
       
   263 
       
   264         /* To maximise object sharing, classes in this package can replace
       
   265          * a private MBeanOptions with no MXBeanMappingFactory with one
       
   266          * of these shared instances.  But they must be EXTREMELY careful
       
   267          * never to give out the shared instances to user code, which could
       
   268          * modify them.
       
   269          */
       
   270         private static final MBeanOptions[] CANONICALS = {
       
   271             new MBeanOptions(), MXBEAN,
       
   272         };
       
   273         // Overridden in local subclasses:
       
   274         MBeanOptions[] canonicals() {
       
   275             return CANONICALS;
       
   276         }
       
   277 
       
   278         // This is only used by the logic for canonical instances.
       
   279         // Overridden in local subclasses:
       
   280         boolean same(MBeanOptions opt) {
       
   281             return (opt.mappingFactory == mappingFactory);
       
   282         }
       
   283 
       
   284         final MBeanOptions canonical() {
       
   285             for (MBeanOptions opt : canonicals()) {
       
   286                 if (opt.getClass() == this.getClass() && same(opt))
       
   287                     return opt;
       
   288             }
       
   289             return this;
       
   290         }
       
   291 
       
   292         final MBeanOptions uncanonical() {
       
   293             for (MBeanOptions opt : canonicals()) {
       
   294                 if (this == opt)
       
   295                     return clone();
       
   296             }
       
   297             return this;
       
   298         }
       
   299 
       
   300         private Map<String, Object> toMap() {
       
   301             Map<String, Object> map = new TreeMap<String, Object>();
       
   302             try {
       
   303                 BeanInfo bi = java.beans.Introspector.getBeanInfo(getClass());
       
   304                 PropertyDescriptor[] pds = bi.getPropertyDescriptors();
       
   305                 for (PropertyDescriptor pd : pds) {
       
   306                     String name = pd.getName();
       
   307                     if (name.equals("class"))
       
   308                         continue;
       
   309                     Method get = pd.getReadMethod();
       
   310                     if (get != null)
       
   311                         map.put(name, get.invoke(this));
       
   312                 }
       
   313             } catch (Exception e) {
       
   314                 Throwable t = e;
       
   315                 if (t instanceof InvocationTargetException)
       
   316                     t = t.getCause();
       
   317                 map.put("Exception", t);
       
   318             }
       
   319             return map;
       
   320         }
       
   321 
       
   322         @Override
       
   323         public String toString() {
       
   324             return getClass().getSimpleName() + toMap();
       
   325             // For example "MBeanOptions{MXBean=true, <etc>}".
       
   326         }
       
   327 
       
   328         /**
       
   329          * <p>Indicates whether some other object is "equal to" this one. The
       
   330          * result is true if and only if the other object is also an instance
       
   331          * of MBeanOptions or a subclass, and has the same properties with
       
   332          * the same values.</p>
       
   333          * @return {@inheritDoc}
       
   334          */
       
   335         @Override
       
   336         public boolean equals(Object obj) {
       
   337             if (obj == this)
       
   338                 return true;
       
   339             if (obj == null || obj.getClass() != this.getClass())
       
   340                 return false;
       
   341             return toMap().equals(((MBeanOptions) obj).toMap());
       
   342         }
       
   343 
       
   344         @Override
       
   345         public int hashCode() {
       
   346             return toMap().hashCode();
       
   347         }
       
   348     }
       
   349 
       
   350     /**
       
   351      * <p>Options to apply to an MBean proxy.</p>
       
   352      *
       
   353      * @see #newMBeanProxy
       
   354      */
       
   355     public static class ProxyOptions extends MBeanOptions {
       
   356         private static final long serialVersionUID = 7238804866098386559L;
       
   357 
       
   358         private boolean notificationEmitter;
       
   359 
       
   360         /**
       
   361          * <p>Construct a {@code ProxyOptions} object where all options have
       
   362          * their default values.</p>
       
   363          */
       
   364         public ProxyOptions() {}
       
   365 
       
   366         @Override
       
   367         public ProxyOptions clone() {
       
   368             return (ProxyOptions) super.clone();
       
   369         }
       
   370 
       
   371         /**
       
   372          * <p>Defines whether the returned proxy should
       
   373          * implement {@link NotificationEmitter}.  The default value is false.</p>
       
   374          *
       
   375          * @return true if this proxy will be a NotificationEmitter.
       
   376          *
       
   377          * @see JMX#newMBeanProxy(MBeanServerConnection, ObjectName, Class,
       
   378          * MBeanOptions)
       
   379          */
       
   380         public boolean isNotificationEmitter() {
       
   381             return this.notificationEmitter;
       
   382         }
       
   383 
       
   384         /**
       
   385          * <p>Set the {@link #isNotificationEmitter NotificationEmitter} option to
       
   386          * the given value.</p>
       
   387          * @param emitter the new value.
       
   388          */
       
   389         public void setNotificationEmitter(boolean emitter) {
       
   390             this.notificationEmitter = emitter;
       
   391         }
       
   392 
       
   393         // Canonical objects for each of (MXBean,!MXBean) x (Emitter,!Emitter)
       
   394         private static final ProxyOptions[] CANONICALS = {
       
   395             new ProxyOptions(), new ProxyOptions(),
       
   396             new ProxyOptions(), new ProxyOptions(),
       
   397         };
       
   398         static {
       
   399             CANONICALS[1].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
       
   400             CANONICALS[2].setNotificationEmitter(true);
       
   401             CANONICALS[3].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
       
   402             CANONICALS[3].setNotificationEmitter(true);
       
   403         }
       
   404         @Override
       
   405         MBeanOptions[] canonicals() {
       
   406             return CANONICALS;
       
   407         }
       
   408 
       
   409         @Override
       
   410         boolean same(MBeanOptions opt) {
       
   411             return (super.same(opt) && opt instanceof ProxyOptions &&
       
   412                     ((ProxyOptions) opt).notificationEmitter == notificationEmitter);
       
   413         }
       
   414     }
       
   415 
    98 
   416     /**
    99     /**
   417      * <p>Make a proxy for a Standard MBean in a local or remote
   100      * <p>Make a proxy for a Standard MBean in a local or remote
   418      * MBean Server.</p>
   101      * MBean Server.</p>
   419      *
   102      *
   499      * MBeanServerConnection#addNotificationListener(ObjectName,
   182      * MBeanServerConnection#addNotificationListener(ObjectName,
   500      * NotificationListener, NotificationFilter, Object)}, and
   183      * NotificationListener, NotificationFilter, Object)}, and
   501      * likewise for the other methods of {@link
   184      * likewise for the other methods of {@link
   502      * NotificationBroadcaster} and {@link NotificationEmitter}.</p>
   185      * NotificationBroadcaster} and {@link NotificationEmitter}.</p>
   503      *
   186      *
   504      * <p>This method is equivalent to {@link
       
   505      * #newMBeanProxy(MBeanServerConnection, ObjectName, Class, JMX.MBeanOptions)
       
   506      * newMBeanProxy(connection, objectName, interfaceClass, opts)}, where
       
   507      * {@code opts} is a {@link JMX.ProxyOptions} representing the
       
   508      * {@code notificationEmitter} parameter.</p>
       
   509      *
       
   510      * @param connection the MBean server to forward to.
   187      * @param connection the MBean server to forward to.
   511      * @param objectName the name of the MBean within
   188      * @param objectName the name of the MBean within
   512      * {@code connection} to forward to.
   189      * {@code connection} to forward to.
   513      * @param interfaceClass the management interface that the MBean
   190      * @param interfaceClass the management interface that the MBean
   514      * exports, which will also be implemented by the returned proxy.
   191      * exports, which will also be implemented by the returned proxy.
   515      * @param notificationEmitter make the returned proxy
   192      * @param notificationEmitter make the returned proxy
   516      * implement {@link NotificationEmitter} by forwarding its methods
   193      * implement {@link NotificationEmitter} by forwarding its methods
   517      * via {@code connection}.
   194      * via {@code connection}.
       
   195      *
   518      * @param <T> allows the compiler to know that if the {@code
   196      * @param <T> allows the compiler to know that if the {@code
   519      * interfaceClass} parameter is {@code MyMBean.class}, for
   197      * interfaceClass} parameter is {@code MyMBean.class}, for
   520      * example, then the return type is {@code MyMBean}.
   198      * example, then the return type is {@code MyMBean}.
       
   199      *
   521      * @return the new proxy instance.
   200      * @return the new proxy instance.
   522      */
   201      */
   523     public static <T> T newMBeanProxy(MBeanServerConnection connection,
   202     public static <T> T newMBeanProxy(MBeanServerConnection connection,
   524                                       ObjectName objectName,
   203                                       ObjectName objectName,
   525                                       Class<T> interfaceClass,
   204                                       Class<T> interfaceClass,
   526                                       boolean notificationEmitter) {
   205                                       boolean notificationEmitter) {
   527         ProxyOptions opts = new ProxyOptions();
   206         return MBeanServerInvocationHandler.newProxyInstance(
   528         opts.setNotificationEmitter(notificationEmitter);
   207                 connection,
   529         return newMBeanProxy(connection, objectName, interfaceClass, opts);
   208                 objectName,
       
   209                 interfaceClass,
       
   210                 notificationEmitter);
   530     }
   211     }
   531 
   212 
   532     /**
   213     /**
   533      * <p>Make a proxy for an MXBean in a local or remote
   214      * <p>Make a proxy for an MXBean in a local or remote
   534      * MBean Server.</p>
   215      * MBean Server.</p>
   596      * by {@code mbs.invoke} will be also be a {@code CompositeData},
   277      * by {@code mbs.invoke} will be also be a {@code CompositeData},
   597      * and the proxy will convert this into the expected type {@code
   278      * and the proxy will convert this into the expected type {@code
   598      * MemoryUsage} using the MXBean mapping rules.</p>
   279      * MemoryUsage} using the MXBean mapping rules.</p>
   599      *
   280      *
   600      * </ul>
   281      * </ul>
       
   282      *
       
   283      * <p>The object returned by this method is a
       
   284      * {@link Proxy} whose {@code InvocationHandler} is an
       
   285      * {@link MBeanServerInvocationHandler}.</p>
   601      *
   286      *
   602      * <p>This method is equivalent to {@link
   287      * <p>This method is equivalent to {@link
   603      * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,
   288      * #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,
   604      * boolean) newMXBeanProxy(connection, objectName, interfaceClass,
   289      * boolean) newMXBeanProxy(connection, objectName, interfaceClass,
   605      * false)}.</p>
   290      * false)}.</p>
   639      * MBeanServerConnection#addNotificationListener(ObjectName,
   324      * MBeanServerConnection#addNotificationListener(ObjectName,
   640      * NotificationListener, NotificationFilter, Object)}, and
   325      * NotificationListener, NotificationFilter, Object)}, and
   641      * likewise for the other methods of {@link
   326      * likewise for the other methods of {@link
   642      * NotificationBroadcaster} and {@link NotificationEmitter}.</p>
   327      * NotificationBroadcaster} and {@link NotificationEmitter}.</p>
   643      *
   328      *
   644      * <p>This method is equivalent to {@link
       
   645      * #newMBeanProxy(MBeanServerConnection, ObjectName, Class, JMX.MBeanOptions)
       
   646      * newMBeanProxy(connection, objectName, interfaceClass, opts)}, where
       
   647      * {@code opts} is a {@link JMX.ProxyOptions} where the {@link
       
   648      * JMX.ProxyOptions#getMXBeanMappingFactory() MXBeanMappingFactory}
       
   649      * property is
       
   650      * {@link MXBeanMappingFactory#forInterface(Class)
       
   651      * MXBeanMappingFactory.forInterface(interfaceClass)} and the {@link
       
   652      * JMX.ProxyOptions#isNotificationEmitter() notificationEmitter} property
       
   653      * is equal to the {@code notificationEmitter} parameter.</p>
       
   654      *
       
   655      * @param connection the MBean server to forward to.
   329      * @param connection the MBean server to forward to.
   656      * @param objectName the name of the MBean within
   330      * @param objectName the name of the MBean within
   657      * {@code connection} to forward to.
   331      * {@code connection} to forward to.
   658      * @param interfaceClass the MXBean interface,
   332      * @param interfaceClass the MXBean interface,
   659      * which will also be implemented by the returned proxy.
   333      * which will also be implemented by the returned proxy.
   660      * @param notificationEmitter make the returned proxy
   334      * @param notificationEmitter make the returned proxy
   661      * implement {@link NotificationEmitter} by forwarding its methods
   335      * implement {@link NotificationEmitter} by forwarding its methods
   662      * via {@code connection}.
   336      * via {@code connection}.
       
   337      *
   663      * @param <T> allows the compiler to know that if the {@code
   338      * @param <T> allows the compiler to know that if the {@code
   664      * interfaceClass} parameter is {@code MyMXBean.class}, for
   339      * interfaceClass} parameter is {@code MyMXBean.class}, for
   665      * example, then the return type is {@code MyMXBean}.
   340      * example, then the return type is {@code MyMXBean}.
       
   341      *
   666      * @return the new proxy instance.
   342      * @return the new proxy instance.
   667      */
   343      */
   668     public static <T> T newMXBeanProxy(MBeanServerConnection connection,
   344     public static <T> T newMXBeanProxy(MBeanServerConnection connection,
   669                                        ObjectName objectName,
   345                                        ObjectName objectName,
   670                                        Class<T> interfaceClass,
   346                                        Class<T> interfaceClass,
   671                                        boolean notificationEmitter) {
   347                                        boolean notificationEmitter) {
   672         ProxyOptions opts = new ProxyOptions();
   348         // Check interface for MXBean compliance
   673         MXBeanMappingFactory f = MXBeanMappingFactory.forInterface(interfaceClass);
   349         //
   674         opts.setMXBeanMappingFactory(f);
       
   675         opts.setNotificationEmitter(notificationEmitter);
       
   676         return newMBeanProxy(connection, objectName, interfaceClass, opts);
       
   677     }
       
   678 
       
   679     /**
       
   680      * <p>Make a proxy for a Standard MBean or MXBean in a local or remote MBean
       
   681      * Server that may also support the methods of {@link
       
   682      * NotificationEmitter} and (for an MXBean) that may define custom MXBean
       
   683      * type mappings.</p>
       
   684      *
       
   685      * <p>This method behaves the same as
       
   686      * {@link #newMBeanProxy(MBeanServerConnection, ObjectName, Class)} or
       
   687      * {@link #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)},
       
   688      * according as {@code opts.isMXBean()} is respectively false or true; but
       
   689      * with the following changes based on {@code opts}.</p>
       
   690      *
       
   691      * <ul>
       
   692      *     <li>If {@code opts.isNotificationEmitter()} is {@code
       
   693      *         true}, then the MBean is assumed to be a {@link
       
   694      *         NotificationBroadcaster} or {@link NotificationEmitter} and the
       
   695      *         returned proxy will implement {@link NotificationEmitter} as
       
   696      *         well as {@code interfaceClass}.  A call to {@link
       
   697      *         NotificationBroadcaster#addNotificationListener} on the proxy
       
   698      *         will result in a call to {@link
       
   699      *         MBeanServerConnection#addNotificationListener(ObjectName,
       
   700      *         NotificationListener, NotificationFilter, Object)}, and
       
   701      *         likewise for the other methods of {@link
       
   702      *     NotificationBroadcaster} and {@link NotificationEmitter}.</li>
       
   703      *
       
   704      *     <li>If {@code opts.getMXBeanMappingFactory()} is not null,
       
   705      *         then the mappings it defines will be applied to convert between
       
   706      *     arbitrary Java types and Open Types.</li>
       
   707      * </ul>
       
   708      *
       
   709      * <p>The object returned by this method is a
       
   710      * {@link Proxy} whose {@code InvocationHandler} is an
       
   711      * {@link MBeanServerInvocationHandler}.  This means that it is possible
       
   712      * to retrieve the parameters that were used to produce the proxy.  If the
       
   713      * proxy was produced as follows...</p>
       
   714      *
       
   715      * <pre>
       
   716      * FooMBean proxy =
       
   717      *     JMX.newMBeanProxy(connection, objectName, FooMBean.class, opts);
       
   718      * </pre>
       
   719      *
       
   720      * <p>...then you can get the {@code MBeanServerInvocationHandler} like
       
   721      * this...</p>
       
   722      *
       
   723      * <pre>
       
   724      * MBeanServerInvocationHandler mbsih = (MBeanServerInvocationHandler)
       
   725      *     {@link Proxy#getInvocationHandler(Object)
       
   726      *            Proxy.getInvocationHandler}(proxy);
       
   727      * </pre>
       
   728      *
       
   729      * <p>...and you can retrieve {@code connection}, {@code
       
   730      * objectName}, and {@code opts} using the {@link
       
   731      * MBeanServerInvocationHandler#getMBeanServerConnection()
       
   732      * getMBeanServerConnection()}, {@link
       
   733      * MBeanServerInvocationHandler#getObjectName() getObjectName()}, and
       
   734      * {@link MBeanServerInvocationHandler#getMBeanOptions() getMBeanOptions()}
       
   735      * methods on {@code mbsih}.  You can retrieve {@code FooMBean.class}
       
   736      * using {@code proxy.getClass().}{@link
       
   737      * Class#getInterfaces() getInterfaces()}.</p>
       
   738      *
       
   739      * @param connection the MBean server to forward to.
       
   740      * @param objectName the name of the MBean within
       
   741      * {@code connection} to forward to.
       
   742      * @param interfaceClass the Standard MBean or MXBean interface,
       
   743      * which will also be implemented by the returned proxy.
       
   744      * @param opts the options to apply for this proxy.  Can be null,
       
   745      * in which case default options are applied.
       
   746      * @param <T> allows the compiler to know that if the {@code
       
   747      * interfaceClass} parameter is {@code MyMXBean.class}, for
       
   748      * example, then the return type is {@code MyMXBean}.
       
   749      * @return the new proxy instance.
       
   750      *
       
   751      * @throws IllegalArgumentException if {@code interfaceClass} is not a
       
   752      * valid MXBean interface.
       
   753      */
       
   754     public static <T> T newMBeanProxy(MBeanServerConnection connection,
       
   755                                       ObjectName objectName,
       
   756                                       Class<T> interfaceClass,
       
   757                                       MBeanOptions opts) {
       
   758         try {
   350         try {
   759             return newMBeanProxy2(connection, objectName, interfaceClass, opts);
   351             Introspector.testComplianceMXBeanInterface(interfaceClass);
   760         } catch (NotCompliantMBeanException e) {
   352         } catch (NotCompliantMBeanException e) {
   761             throw new IllegalArgumentException(e);
   353             throw new IllegalArgumentException(e);
   762         }
   354         }
   763     }
       
   764 
       
   765     private static <T> T newMBeanProxy2(MBeanServerConnection connection,
       
   766                                         ObjectName objectName,
       
   767                                         Class<T> interfaceClass,
       
   768                                         MBeanOptions opts)
       
   769     throws NotCompliantMBeanException {
       
   770 
       
   771         if (opts == null)
       
   772             opts = new MBeanOptions();
       
   773 
       
   774         boolean notificationEmitter = opts instanceof ProxyOptions &&
       
   775                 ((ProxyOptions) opts).isNotificationEmitter();
       
   776 
       
   777         MXBeanMappingFactory mappingFactory = opts.getMXBeanMappingFactory();
       
   778 
       
   779         if (mappingFactory != null) {
       
   780             // Check interface for MXBean compliance
       
   781             Introspector.testComplianceMXBeanInterface(interfaceClass,
       
   782                     mappingFactory);
       
   783         }
       
   784 
       
   785         InvocationHandler handler = new MBeanServerInvocationHandler(
   355         InvocationHandler handler = new MBeanServerInvocationHandler(
   786                 connection, objectName, opts);
   356                 connection, objectName, true);
   787         final Class<?>[] interfaces;
   357         final Class<?>[] interfaces;
   788         if (notificationEmitter) {
   358         if (notificationEmitter) {
   789             interfaces =
   359             interfaces =
   790                 new Class<?>[] {interfaceClass, NotificationEmitter.class};
   360                 new Class<?>[] {interfaceClass, NotificationEmitter.class};
   791         } else
   361         } else
   820         return interfaceClass.getName().endsWith("MXBean");
   390         return interfaceClass.getName().endsWith("MXBean");
   821         // We don't bother excluding the case where the name is
   391         // We don't bother excluding the case where the name is
   822         // exactly the string "MXBean" since that would mean there
   392         // exactly the string "MXBean" since that would mean there
   823         // was no package name, which is pretty unlikely in practice.
   393         // was no package name, which is pretty unlikely in practice.
   824     }
   394     }
   825 
       
   826     /**
       
   827      * <p>Test if an MBean can emit notifications.  An MBean can emit
       
   828      * notifications if either it implements {@link NotificationBroadcaster}
       
   829      * (perhaps through its child interface {@link NotificationEmitter}), or
       
   830      * it uses <a href="MBeanRegistration.html#injection">resource
       
   831      * injection</a> to obtain an instance of {@link SendNotification}
       
   832      * through which it can send notifications.</p>
       
   833      *
       
   834      * @param mbean an MBean object.
       
   835      * @return true if the given object is a valid MBean that can emit
       
   836      * notifications; false if the object is a valid MBean but that
       
   837      * cannot emit notifications.
       
   838      * @throws NotCompliantMBeanException if the given object is not
       
   839      * a valid MBean.
       
   840      */
       
   841     public static boolean isNotificationSource(Object mbean)
       
   842             throws NotCompliantMBeanException {
       
   843         for (int i = 0; i < 2; i++) {
       
   844             if (mbean instanceof NotificationBroadcaster ||
       
   845                     MBeanInjector.injectsSendNotification(mbean))
       
   846                 return true;
       
   847             if (mbean instanceof DynamicWrapperMBean)
       
   848                 mbean = ((DynamicWrapperMBean) mbean).getWrappedObject();
       
   849             else
       
   850                 break;
       
   851         }
       
   852         return false;
       
   853     }
       
   854 
       
   855     /**
       
   856      * <p>Return the version of the JMX specification that a (possibly remote)
       
   857      * MBean Server is using.  The JMX specification described in this
       
   858      * documentation is version 2.0.  The earlier versions that might be
       
   859      * reported by this method are 1.0, 1.1, 1.2, and 1.4.  (There is no 1.3.)
       
   860      * All of these versions and all future versions can be compared using
       
   861      * {@link String#compareTo(String)}.  So, for example, to tell if
       
   862      * {@code mbsc} is running at least version 2.0 you can write:</p>
       
   863      *
       
   864      * <pre>
       
   865      * String version = JMX.getSpecificationVersion(mbsc, null);
       
   866      * boolean atLeast2dot0 = (version.compareTo("2.0") >= 0);
       
   867      * </pre>
       
   868      *
       
   869      * <p>A remote MBean Server might be running an earlier version of the
       
   870      * JMX API, and in that case <a href="package-summary.html#interop">certain
       
   871      * features</a> might not be available in it.</p>
       
   872      *
       
   873      * <p>The version of the MBean Server {@code mbsc} is not necessarily
       
   874      * the version of all namespaces within that MBean Server, for example
       
   875      * if some of them use {@link javax.management.namespace.JMXRemoteNamespace
       
   876      * JMXRemoteNamespace}.  To determine the version of the namespace
       
   877      * that a particular MBean is in, give its name as the {@code mbeanName}
       
   878      * parameter.</p>
       
   879      *
       
   880      * @param mbsc a connection to an MBean Server.
       
   881      *
       
   882      * @param mbeanName the name of an MBean within that MBean Server, or null.
       
   883      * If non-null, the namespace of this name, as determined by
       
   884      * {@link JMXNamespaces#getContainingNamespace
       
   885      * JMXNamespaces.getContainingNamespace}, is the one whose specification
       
   886      * version will be returned.
       
   887      *
       
   888      * @return the JMX specification version reported by that MBean Server.
       
   889      *
       
   890      * @throws IllegalArgumentException if {@code mbsc} is null, or if
       
   891      * {@code mbeanName} includes a wildcard character ({@code *} or {@code ?})
       
   892      * in its namespace.
       
   893      *
       
   894      * @throws IOException if the version cannot be obtained, either because
       
   895      * there is a communication problem or because the remote MBean Server
       
   896      * does not have the appropriate {@linkplain
       
   897      * MBeanServerDelegateMBean#getSpecificationVersion() attribute}.
       
   898      *
       
   899      * @see <a href="package-summary.html#interop">Interoperability between
       
   900      * versions of the JMX specification</a>
       
   901      * @see MBeanServerDelegateMBean#getSpecificationVersion
       
   902      */
       
   903     public static String getSpecificationVersion(
       
   904             MBeanServerConnection mbsc, ObjectName mbeanName)
       
   905             throws IOException {
       
   906         if (mbsc == null)
       
   907             throw new IllegalArgumentException("Null MBeanServerConnection");
       
   908 
       
   909         String namespace;
       
   910         if (mbeanName == null)
       
   911             namespace = "";
       
   912         else
       
   913             namespace = JMXNamespaces.getContainingNamespace(mbeanName);
       
   914         if (namespace.contains("*") || namespace.contains("?")) {
       
   915             throw new IllegalArgumentException(
       
   916                     "ObjectName contains namespace wildcard: " + mbeanName);
       
   917         }
       
   918 
       
   919         try {
       
   920             if (namespace.length() > 0)
       
   921                 mbsc = JMXNamespaces.narrowToNamespace(mbsc, namespace);
       
   922             return (String) mbsc.getAttribute(
       
   923                     MBeanServerDelegate.DELEGATE_NAME, "SpecificationVersion");
       
   924         } catch (IOException e) {
       
   925             throw e;
       
   926         } catch (Exception e) {
       
   927             throw new IOException(e);
       
   928         }
       
   929     }
       
   930 }
   395 }