You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1238 lines
50 KiB
1238 lines
50 KiB
/*
|
|
* Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package javax.management;
|
|
|
|
import static com.sun.jmx.defaults.JmxProperties.MISC_LOGGER;
|
|
import com.sun.jmx.mbeanserver.DescriptorCache;
|
|
import com.sun.jmx.mbeanserver.Introspector;
|
|
import com.sun.jmx.mbeanserver.MBeanSupport;
|
|
import com.sun.jmx.mbeanserver.MXBeanSupport;
|
|
import com.sun.jmx.mbeanserver.StandardMBeanSupport;
|
|
import com.sun.jmx.mbeanserver.Util;
|
|
|
|
import java.security.AccessController;
|
|
import java.security.PrivilegedAction;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.WeakHashMap;
|
|
import java.util.logging.Level;
|
|
import javax.management.openmbean.OpenMBeanAttributeInfo;
|
|
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
|
|
import javax.management.openmbean.OpenMBeanConstructorInfo;
|
|
import javax.management.openmbean.OpenMBeanConstructorInfoSupport;
|
|
import javax.management.openmbean.OpenMBeanOperationInfo;
|
|
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
|
|
import javax.management.openmbean.OpenMBeanParameterInfo;
|
|
import javax.management.openmbean.OpenMBeanParameterInfoSupport;
|
|
|
|
/**
|
|
* <p>An MBean whose management interface is determined by reflection
|
|
* on a Java interface.</p>
|
|
*
|
|
* <p>This class brings more flexibility to the notion of Management
|
|
* Interface in the use of Standard MBeans. Straightforward use of
|
|
* the patterns for Standard MBeans described in the JMX Specification
|
|
* means that there is a fixed relationship between the implementation
|
|
* class of an MBean and its management interface (i.e., if the
|
|
* implementation class is Thing, the management interface must be
|
|
* ThingMBean). This class makes it possible to keep the convenience
|
|
* of specifying the management interface with a Java interface,
|
|
* without requiring that there be any naming relationship between the
|
|
* implementation and interface classes.</p>
|
|
*
|
|
* <p>By making a DynamicMBean out of an MBean, this class makes
|
|
* it possible to select any interface implemented by the MBean as its
|
|
* management interface, provided that it complies with JMX patterns
|
|
* (i.e., attributes defined by getter/setter etc...).</p>
|
|
*
|
|
* <p> This class also provides hooks that make it possible to supply
|
|
* custom descriptions and names for the {@link MBeanInfo} returned by
|
|
* the DynamicMBean interface.</p>
|
|
*
|
|
* <p>Using this class, an MBean can be created with any
|
|
* implementation class name <i>Impl</i> and with a management
|
|
* interface defined (as for current Standard MBeans) by any interface
|
|
* <i>Intf</i>, in one of two general ways:</p>
|
|
*
|
|
* <ul>
|
|
*
|
|
* <li>Using the public constructor
|
|
* {@link #StandardMBean(java.lang.Object, java.lang.Class, boolean)
|
|
* StandardMBean(impl,interface)}:
|
|
* <pre>
|
|
* MBeanServer mbs;
|
|
* ...
|
|
* Impl impl = new Impl(...);
|
|
* StandardMBean mbean = new StandardMBean(impl, Intf.class, false);
|
|
* mbs.registerMBean(mbean, objectName);
|
|
* </pre></li>
|
|
*
|
|
* <li>Subclassing StandardMBean:
|
|
* <pre>
|
|
* public class Impl extends StandardMBean implements Intf {
|
|
* public Impl() {
|
|
* super(Intf.class, false);
|
|
* }
|
|
* // implement methods of Intf
|
|
* }
|
|
*
|
|
* [...]
|
|
*
|
|
* MBeanServer mbs;
|
|
* ....
|
|
* Impl impl = new Impl();
|
|
* mbs.registerMBean(impl, objectName);
|
|
* </pre></li>
|
|
*
|
|
* </ul>
|
|
*
|
|
* <p>In either case, the class <i>Impl</i> must implement the
|
|
* interface <i>Intf</i>.</p>
|
|
*
|
|
* <p>Standard MBeans based on the naming relationship between
|
|
* implementation and interface classes are of course still
|
|
* available.</p>
|
|
*
|
|
* <p>This class may also be used to construct MXBeans. The usage
|
|
* is exactly the same as for Standard MBeans except that in the
|
|
* examples above, the {@code false} parameter to the constructor or
|
|
* {@code super(...)} invocation is instead {@code true}.</p>
|
|
*
|
|
* @since 1.5
|
|
*/
|
|
public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
|
|
|
private final static DescriptorCache descriptors =
|
|
DescriptorCache.getInstance(JMX.proof);
|
|
|
|
/**
|
|
* The DynamicMBean that wraps the MXBean or Standard MBean implementation.
|
|
**/
|
|
private volatile MBeanSupport<?> mbean;
|
|
|
|
/**
|
|
* The cached MBeanInfo.
|
|
**/
|
|
private volatile MBeanInfo cachedMBeanInfo;
|
|
|
|
/**
|
|
* Make a DynamicMBean out of <var>implementation</var>, using the
|
|
* specified <var>mbeanInterface</var> class.
|
|
* @param implementation The implementation of this MBean.
|
|
* If <code>null</code>, and null implementation is allowed,
|
|
* then the implementation is assumed to be <var>this</var>.
|
|
* @param mbeanInterface The Management Interface exported by this
|
|
* MBean's implementation. If <code>null</code>, then this
|
|
* object will use standard JMX design pattern to determine
|
|
* the management interface associated with the given
|
|
* implementation.
|
|
* @param nullImplementationAllowed <code>true</code> if a null
|
|
* implementation is allowed. If null implementation is allowed,
|
|
* and a null implementation is passed, then the implementation
|
|
* is assumed to be <var>this</var>.
|
|
* @exception IllegalArgumentException if the given
|
|
* <var>implementation</var> is null, and null is not allowed.
|
|
**/
|
|
private <T> void construct(T implementation, Class<T> mbeanInterface,
|
|
boolean nullImplementationAllowed,
|
|
boolean isMXBean)
|
|
throws NotCompliantMBeanException {
|
|
if (implementation == null) {
|
|
// Have to use (T)this rather than mbeanInterface.cast(this)
|
|
// because mbeanInterface might be null.
|
|
if (nullImplementationAllowed)
|
|
implementation = Util.<T>cast(this);
|
|
else throw new IllegalArgumentException("implementation is null");
|
|
}
|
|
if (isMXBean) {
|
|
if (mbeanInterface == null) {
|
|
mbeanInterface = Util.cast(Introspector.getMXBeanInterface(
|
|
implementation.getClass()));
|
|
}
|
|
this.mbean = new MXBeanSupport(implementation, mbeanInterface);
|
|
} else {
|
|
if (mbeanInterface == null) {
|
|
mbeanInterface = Util.cast(Introspector.getStandardMBeanInterface(
|
|
implementation.getClass()));
|
|
}
|
|
this.mbean =
|
|
new StandardMBeanSupport(implementation, mbeanInterface);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>Make a DynamicMBean out of the object
|
|
* <var>implementation</var>, using the specified
|
|
* <var>mbeanInterface</var> class.</p>
|
|
*
|
|
* @param implementation The implementation of this MBean.
|
|
* @param mbeanInterface The Management Interface exported by this
|
|
* MBean's implementation. If <code>null</code>, then this
|
|
* object will use standard JMX design pattern to determine
|
|
* the management interface associated with the given
|
|
* implementation.
|
|
* @param <T> Allows the compiler to check
|
|
* that {@code implementation} does indeed implement the class
|
|
* described by {@code mbeanInterface}. The compiler can only
|
|
* check this if {@code mbeanInterface} is a class literal such
|
|
* as {@code MyMBean.class}.
|
|
*
|
|
* @exception IllegalArgumentException if the given
|
|
* <var>implementation</var> is null.
|
|
* @exception NotCompliantMBeanException if the <var>mbeanInterface</var>
|
|
* does not follow JMX design patterns for Management Interfaces, or
|
|
* if the given <var>implementation</var> does not implement the
|
|
* specified interface.
|
|
**/
|
|
public <T> StandardMBean(T implementation, Class<T> mbeanInterface)
|
|
throws NotCompliantMBeanException {
|
|
construct(implementation, mbeanInterface, false, false);
|
|
}
|
|
|
|
/**
|
|
* <p>Make a DynamicMBean out of <var>this</var>, using the specified
|
|
* <var>mbeanInterface</var> class.</p>
|
|
*
|
|
* <p>Calls {@link #StandardMBean(java.lang.Object, java.lang.Class)
|
|
* this(this,mbeanInterface)}.
|
|
* This constructor is reserved to subclasses.</p>
|
|
*
|
|
* @param mbeanInterface The Management Interface exported by this
|
|
* MBean.
|
|
*
|
|
* @exception NotCompliantMBeanException if the <var>mbeanInterface</var>
|
|
* does not follow JMX design patterns for Management Interfaces, or
|
|
* if <var>this</var> does not implement the specified interface.
|
|
**/
|
|
protected StandardMBean(Class<?> mbeanInterface)
|
|
throws NotCompliantMBeanException {
|
|
construct(null, mbeanInterface, true, false);
|
|
}
|
|
|
|
/**
|
|
* <p>Make a DynamicMBean out of the object
|
|
* <var>implementation</var>, using the specified
|
|
* <var>mbeanInterface</var> class, and choosing whether the
|
|
* resultant MBean is an MXBean. This constructor can be used
|
|
* to make either Standard MBeans or MXBeans. Unlike the
|
|
* constructor {@link #StandardMBean(Object, Class)}, it
|
|
* does not throw NotCompliantMBeanException.</p>
|
|
*
|
|
* @param implementation The implementation of this MBean.
|
|
* @param mbeanInterface The Management Interface exported by this
|
|
* MBean's implementation. If <code>null</code>, then this
|
|
* object will use standard JMX design pattern to determine
|
|
* the management interface associated with the given
|
|
* implementation.
|
|
* @param isMXBean If true, the {@code mbeanInterface} parameter
|
|
* names an MXBean interface and the resultant MBean is an MXBean.
|
|
* @param <T> Allows the compiler to check
|
|
* that {@code implementation} does indeed implement the class
|
|
* described by {@code mbeanInterface}. The compiler can only
|
|
* check this if {@code mbeanInterface} is a class literal such
|
|
* as {@code MyMBean.class}.
|
|
*
|
|
* @exception IllegalArgumentException if the given
|
|
* <var>implementation</var> is null, or if the <var>mbeanInterface</var>
|
|
* does not follow JMX design patterns for Management Interfaces, or
|
|
* if the given <var>implementation</var> does not implement the
|
|
* specified interface.
|
|
*
|
|
* @since 1.6
|
|
**/
|
|
public <T> StandardMBean(T implementation, Class<T> mbeanInterface,
|
|
boolean isMXBean) {
|
|
try {
|
|
construct(implementation, mbeanInterface, false, isMXBean);
|
|
} catch (NotCompliantMBeanException e) {
|
|
throw new IllegalArgumentException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>Make a DynamicMBean out of <var>this</var>, using the specified
|
|
* <var>mbeanInterface</var> class, and choosing whether the resulting
|
|
* MBean is an MXBean. This constructor can be used
|
|
* to make either Standard MBeans or MXBeans. Unlike the
|
|
* constructor {@link #StandardMBean(Object, Class)}, it
|
|
* does not throw NotCompliantMBeanException.</p>
|
|
*
|
|
* <p>Calls {@link #StandardMBean(java.lang.Object, java.lang.Class, boolean)
|
|
* this(this, mbeanInterface, isMXBean)}.
|
|
* This constructor is reserved to subclasses.</p>
|
|
*
|
|
* @param mbeanInterface The Management Interface exported by this
|
|
* MBean.
|
|
* @param isMXBean If true, the {@code mbeanInterface} parameter
|
|
* names an MXBean interface and the resultant MBean is an MXBean.
|
|
*
|
|
* @exception IllegalArgumentException if the <var>mbeanInterface</var>
|
|
* does not follow JMX design patterns for Management Interfaces, or
|
|
* if <var>this</var> does not implement the specified interface.
|
|
*
|
|
* @since 1.6
|
|
**/
|
|
protected StandardMBean(Class<?> mbeanInterface, boolean isMXBean) {
|
|
try {
|
|
construct(null, mbeanInterface, true, isMXBean);
|
|
} catch (NotCompliantMBeanException e) {
|
|
throw new IllegalArgumentException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <p>Replace the implementation object wrapped in this object.</p>
|
|
*
|
|
* @param implementation The new implementation of this Standard MBean
|
|
* (or MXBean). The <code>implementation</code> object must implement
|
|
* the Standard MBean (or MXBean) interface that was supplied when this
|
|
* <code>StandardMBean</code> was constructed.
|
|
*
|
|
* @exception IllegalArgumentException if the given
|
|
* <var>implementation</var> is null.
|
|
*
|
|
* @exception NotCompliantMBeanException if the given
|
|
* <var>implementation</var> does not implement the
|
|
* Standard MBean (or MXBean) interface that was
|
|
* supplied at construction.
|
|
*
|
|
* @see #getImplementation
|
|
**/
|
|
public void setImplementation(Object implementation)
|
|
throws NotCompliantMBeanException {
|
|
|
|
if (implementation == null)
|
|
throw new IllegalArgumentException("implementation is null");
|
|
|
|
if (isMXBean()) {
|
|
this.mbean = new MXBeanSupport(implementation,
|
|
Util.<Class<Object>>cast(getMBeanInterface()));
|
|
} else {
|
|
this.mbean = new StandardMBeanSupport(implementation,
|
|
Util.<Class<Object>>cast(getMBeanInterface()));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the implementation of this Standard MBean (or MXBean).
|
|
* @return The implementation of this Standard MBean (or MXBean).
|
|
*
|
|
* @see #setImplementation
|
|
**/
|
|
public Object getImplementation() {
|
|
return mbean.getResource();
|
|
}
|
|
|
|
/**
|
|
* Get the Management Interface of this Standard MBean (or MXBean).
|
|
* @return The management interface of this Standard MBean (or MXBean).
|
|
**/
|
|
public final Class<?> getMBeanInterface() {
|
|
return mbean.getMBeanInterface();
|
|
}
|
|
|
|
/**
|
|
* Get the class of the implementation of this Standard MBean (or MXBean).
|
|
* @return The class of the implementation of this Standard MBean (or MXBean).
|
|
**/
|
|
public Class<?> getImplementationClass() {
|
|
return mbean.getResource().getClass();
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// From the DynamicMBean interface.
|
|
// ------------------------------------------------------------------
|
|
public Object getAttribute(String attribute)
|
|
throws AttributeNotFoundException,
|
|
MBeanException,
|
|
ReflectionException {
|
|
return mbean.getAttribute(attribute);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// From the DynamicMBean interface.
|
|
// ------------------------------------------------------------------
|
|
public void setAttribute(Attribute attribute)
|
|
throws AttributeNotFoundException,
|
|
InvalidAttributeValueException,
|
|
MBeanException,
|
|
ReflectionException {
|
|
mbean.setAttribute(attribute);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// From the DynamicMBean interface.
|
|
// ------------------------------------------------------------------
|
|
public AttributeList getAttributes(String[] attributes) {
|
|
return mbean.getAttributes(attributes);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// From the DynamicMBean interface.
|
|
// ------------------------------------------------------------------
|
|
public AttributeList setAttributes(AttributeList attributes) {
|
|
return mbean.setAttributes(attributes);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// From the DynamicMBean interface.
|
|
// ------------------------------------------------------------------
|
|
public Object invoke(String actionName, Object params[], String signature[])
|
|
throws MBeanException, ReflectionException {
|
|
return mbean.invoke(actionName, params, signature);
|
|
}
|
|
|
|
/**
|
|
* Get the {@link MBeanInfo} for this MBean.
|
|
* <p>
|
|
* This method implements
|
|
* {@link javax.management.DynamicMBean#getMBeanInfo()
|
|
* DynamicMBean.getMBeanInfo()}.
|
|
* <p>
|
|
* This method first calls {@link #getCachedMBeanInfo()} in order to
|
|
* retrieve the cached MBeanInfo for this MBean, if any. If the
|
|
* MBeanInfo returned by {@link #getCachedMBeanInfo()} is not null,
|
|
* then it is returned.<br>
|
|
* Otherwise, this method builds a default MBeanInfo for this MBean,
|
|
* using the Management Interface specified for this MBean.
|
|
* <p>
|
|
* While building the MBeanInfo, this method calls the customization
|
|
* hooks that make it possible for subclasses to supply their custom
|
|
* descriptions, parameter names, etc...<br>
|
|
* Finally, it calls {@link #cacheMBeanInfo(javax.management.MBeanInfo)
|
|
* cacheMBeanInfo()} in order to cache the new MBeanInfo.
|
|
* @return The cached MBeanInfo for that MBean, if not null, or a
|
|
* newly built MBeanInfo if none was cached.
|
|
**/
|
|
public MBeanInfo getMBeanInfo() {
|
|
try {
|
|
final MBeanInfo cached = getCachedMBeanInfo();
|
|
if (cached != null) return cached;
|
|
} catch (RuntimeException x) {
|
|
if (MISC_LOGGER.isLoggable(Level.FINEST)) {
|
|
MISC_LOGGER.logp(Level.FINEST,
|
|
MBeanServerFactory.class.getName(), "getMBeanInfo",
|
|
"Failed to get cached MBeanInfo", x);
|
|
}
|
|
}
|
|
|
|
if (MISC_LOGGER.isLoggable(Level.FINER)) {
|
|
MISC_LOGGER.logp(Level.FINER,
|
|
MBeanServerFactory.class.getName(), "getMBeanInfo",
|
|
"Building MBeanInfo for " +
|
|
getImplementationClass().getName());
|
|
}
|
|
|
|
MBeanSupport<?> msupport = mbean;
|
|
final MBeanInfo bi = msupport.getMBeanInfo();
|
|
final Object impl = msupport.getResource();
|
|
|
|
final boolean immutableInfo = immutableInfo(this.getClass());
|
|
|
|
final String cname = getClassName(bi);
|
|
final String text = getDescription(bi);
|
|
final MBeanConstructorInfo[] ctors = getConstructors(bi,impl);
|
|
final MBeanAttributeInfo[] attrs = getAttributes(bi);
|
|
final MBeanOperationInfo[] ops = getOperations(bi);
|
|
final MBeanNotificationInfo[] ntfs = getNotifications(bi);
|
|
final Descriptor desc = getDescriptor(bi, immutableInfo);
|
|
|
|
final MBeanInfo nmbi = new MBeanInfo(
|
|
cname, text, attrs, ctors, ops, ntfs, desc);
|
|
try {
|
|
cacheMBeanInfo(nmbi);
|
|
} catch (RuntimeException x) {
|
|
if (MISC_LOGGER.isLoggable(Level.FINEST)) {
|
|
MISC_LOGGER.logp(Level.FINEST,
|
|
MBeanServerFactory.class.getName(), "getMBeanInfo",
|
|
"Failed to cache MBeanInfo", x);
|
|
}
|
|
}
|
|
|
|
return nmbi;
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the className that will be used in the MBeanInfo returned by
|
|
* this MBean.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to supply their
|
|
* custom class name. The default implementation returns
|
|
* {@link MBeanInfo#getClassName() info.getClassName()}.
|
|
* @param info The default MBeanInfo derived by reflection.
|
|
* @return the class name for the new MBeanInfo.
|
|
**/
|
|
protected String getClassName(MBeanInfo info) {
|
|
if (info == null) return getImplementationClass().getName();
|
|
return info.getClassName();
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the description that will be used in the MBeanInfo returned by
|
|
* this MBean.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to supply their
|
|
* custom MBean description. The default implementation returns
|
|
* {@link MBeanInfo#getDescription() info.getDescription()}.
|
|
* @param info The default MBeanInfo derived by reflection.
|
|
* @return the description for the new MBeanInfo.
|
|
**/
|
|
protected String getDescription(MBeanInfo info) {
|
|
if (info == null) return null;
|
|
return info.getDescription();
|
|
}
|
|
|
|
/**
|
|
* <p>Customization hook:
|
|
* Get the description that will be used in the MBeanFeatureInfo
|
|
* returned by this MBean.</p>
|
|
*
|
|
* <p>Subclasses may redefine this method in order to supply
|
|
* their custom description. The default implementation returns
|
|
* {@link MBeanFeatureInfo#getDescription()
|
|
* info.getDescription()}.</p>
|
|
*
|
|
* <p>This method is called by
|
|
* {@link #getDescription(MBeanAttributeInfo)},
|
|
* {@link #getDescription(MBeanOperationInfo)},
|
|
* {@link #getDescription(MBeanConstructorInfo)}.</p>
|
|
*
|
|
* @param info The default MBeanFeatureInfo derived by reflection.
|
|
* @return the description for the given MBeanFeatureInfo.
|
|
**/
|
|
protected String getDescription(MBeanFeatureInfo info) {
|
|
if (info == null) return null;
|
|
return info.getDescription();
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the description that will be used in the MBeanAttributeInfo
|
|
* returned by this MBean.
|
|
*
|
|
* <p>Subclasses may redefine this method in order to supply their
|
|
* custom description. The default implementation returns {@link
|
|
* #getDescription(MBeanFeatureInfo)
|
|
* getDescription((MBeanFeatureInfo) info)}.
|
|
* @param info The default MBeanAttributeInfo derived by reflection.
|
|
* @return the description for the given MBeanAttributeInfo.
|
|
**/
|
|
protected String getDescription(MBeanAttributeInfo info) {
|
|
return getDescription((MBeanFeatureInfo)info);
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the description that will be used in the MBeanConstructorInfo
|
|
* returned by this MBean.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to supply their
|
|
* custom description.
|
|
* The default implementation returns {@link
|
|
* #getDescription(MBeanFeatureInfo)
|
|
* getDescription((MBeanFeatureInfo) info)}.
|
|
* @param info The default MBeanConstructorInfo derived by reflection.
|
|
* @return the description for the given MBeanConstructorInfo.
|
|
**/
|
|
protected String getDescription(MBeanConstructorInfo info) {
|
|
return getDescription((MBeanFeatureInfo)info);
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the description that will be used for the <var>sequence</var>
|
|
* MBeanParameterInfo of the MBeanConstructorInfo returned by this MBean.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to supply their
|
|
* custom description. The default implementation returns
|
|
* {@link MBeanParameterInfo#getDescription() param.getDescription()}.
|
|
*
|
|
* @param ctor The default MBeanConstructorInfo derived by reflection.
|
|
* @param param The default MBeanParameterInfo derived by reflection.
|
|
* @param sequence The sequence number of the parameter considered
|
|
* ("0" for the first parameter, "1" for the second parameter,
|
|
* etc...).
|
|
* @return the description for the given MBeanParameterInfo.
|
|
**/
|
|
protected String getDescription(MBeanConstructorInfo ctor,
|
|
MBeanParameterInfo param,
|
|
int sequence) {
|
|
if (param == null) return null;
|
|
return param.getDescription();
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the name that will be used for the <var>sequence</var>
|
|
* MBeanParameterInfo of the MBeanConstructorInfo returned by this MBean.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to supply their
|
|
* custom parameter name. The default implementation returns
|
|
* {@link MBeanParameterInfo#getName() param.getName()}.
|
|
*
|
|
* @param ctor The default MBeanConstructorInfo derived by reflection.
|
|
* @param param The default MBeanParameterInfo derived by reflection.
|
|
* @param sequence The sequence number of the parameter considered
|
|
* ("0" for the first parameter, "1" for the second parameter,
|
|
* etc...).
|
|
* @return the name for the given MBeanParameterInfo.
|
|
**/
|
|
protected String getParameterName(MBeanConstructorInfo ctor,
|
|
MBeanParameterInfo param,
|
|
int sequence) {
|
|
if (param == null) return null;
|
|
return param.getName();
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the description that will be used in the MBeanOperationInfo
|
|
* returned by this MBean.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to supply their
|
|
* custom description. The default implementation returns
|
|
* {@link #getDescription(MBeanFeatureInfo)
|
|
* getDescription((MBeanFeatureInfo) info)}.
|
|
* @param info The default MBeanOperationInfo derived by reflection.
|
|
* @return the description for the given MBeanOperationInfo.
|
|
**/
|
|
protected String getDescription(MBeanOperationInfo info) {
|
|
return getDescription((MBeanFeatureInfo)info);
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the <var>impact</var> flag of the operation that will be used in
|
|
* the MBeanOperationInfo returned by this MBean.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to supply their
|
|
* custom impact flag. The default implementation returns
|
|
* {@link MBeanOperationInfo#getImpact() info.getImpact()}.
|
|
* @param info The default MBeanOperationInfo derived by reflection.
|
|
* @return the impact flag for the given MBeanOperationInfo.
|
|
**/
|
|
protected int getImpact(MBeanOperationInfo info) {
|
|
if (info == null) return MBeanOperationInfo.UNKNOWN;
|
|
return info.getImpact();
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the name that will be used for the <var>sequence</var>
|
|
* MBeanParameterInfo of the MBeanOperationInfo returned by this MBean.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to supply their
|
|
* custom parameter name. The default implementation returns
|
|
* {@link MBeanParameterInfo#getName() param.getName()}.
|
|
*
|
|
* @param op The default MBeanOperationInfo derived by reflection.
|
|
* @param param The default MBeanParameterInfo derived by reflection.
|
|
* @param sequence The sequence number of the parameter considered
|
|
* ("0" for the first parameter, "1" for the second parameter,
|
|
* etc...).
|
|
* @return the name to use for the given MBeanParameterInfo.
|
|
**/
|
|
protected String getParameterName(MBeanOperationInfo op,
|
|
MBeanParameterInfo param,
|
|
int sequence) {
|
|
if (param == null) return null;
|
|
return param.getName();
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the description that will be used for the <var>sequence</var>
|
|
* MBeanParameterInfo of the MBeanOperationInfo returned by this MBean.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to supply their
|
|
* custom description. The default implementation returns
|
|
* {@link MBeanParameterInfo#getDescription() param.getDescription()}.
|
|
*
|
|
* @param op The default MBeanOperationInfo derived by reflection.
|
|
* @param param The default MBeanParameterInfo derived by reflection.
|
|
* @param sequence The sequence number of the parameter considered
|
|
* ("0" for the first parameter, "1" for the second parameter,
|
|
* etc...).
|
|
* @return the description for the given MBeanParameterInfo.
|
|
**/
|
|
protected String getDescription(MBeanOperationInfo op,
|
|
MBeanParameterInfo param,
|
|
int sequence) {
|
|
if (param == null) return null;
|
|
return param.getDescription();
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the MBeanConstructorInfo[] that will be used in the MBeanInfo
|
|
* returned by this MBean.
|
|
* <br>
|
|
* By default, this method returns <code>null</code> if the wrapped
|
|
* implementation is not <var>this</var>. Indeed, if the wrapped
|
|
* implementation is not this object itself, it will not be possible
|
|
* to recreate a wrapped implementation by calling the implementation
|
|
* constructors through <code>MBeanServer.createMBean(...)</code>.<br>
|
|
* Otherwise, if the wrapped implementation is <var>this</var>,
|
|
* <var>ctors</var> is returned.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to modify this
|
|
* behavior, if needed.
|
|
* @param ctors The default MBeanConstructorInfo[] derived by reflection.
|
|
* @param impl The wrapped implementation. If <code>null</code> is
|
|
* passed, the wrapped implementation is ignored and
|
|
* <var>ctors</var> is returned.
|
|
* @return the MBeanConstructorInfo[] for the new MBeanInfo.
|
|
**/
|
|
protected MBeanConstructorInfo[]
|
|
getConstructors(MBeanConstructorInfo[] ctors, Object impl) {
|
|
if (ctors == null) return null;
|
|
if (impl != null && impl != this) return null;
|
|
return ctors;
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Get the MBeanNotificationInfo[] that will be used in the MBeanInfo
|
|
* returned by this MBean.
|
|
* <br>
|
|
* Subclasses may redefine this method in order to supply their
|
|
* custom notifications.
|
|
* @param info The default MBeanInfo derived by reflection.
|
|
* @return the MBeanNotificationInfo[] for the new MBeanInfo.
|
|
**/
|
|
MBeanNotificationInfo[] getNotifications(MBeanInfo info) {
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* <p>Get the Descriptor that will be used in the MBeanInfo
|
|
* returned by this MBean.</p>
|
|
*
|
|
* <p>Subclasses may redefine this method in order to supply
|
|
* their custom descriptor.</p>
|
|
*
|
|
* <p>The default implementation of this method returns a Descriptor
|
|
* that contains at least the field {@code interfaceClassName}, with
|
|
* value {@link #getMBeanInterface()}.getName(). It may also contain
|
|
* the field {@code immutableInfo}, with a value that is the string
|
|
* {@code "true"} if the implementation can determine that the
|
|
* {@code MBeanInfo} returned by {@link #getMBeanInfo()} will always
|
|
* be the same. It may contain other fields: fields defined by the
|
|
* JMX specification must have appropriate values, and other fields
|
|
* must follow the conventions for non-standard field names.</p>
|
|
*
|
|
* @param info The default MBeanInfo derived by reflection.
|
|
* @return the Descriptor for the new MBeanInfo.
|
|
*/
|
|
Descriptor getDescriptor(MBeanInfo info, boolean immutableInfo) {
|
|
ImmutableDescriptor desc;
|
|
if (info == null ||
|
|
info.getDescriptor() == null ||
|
|
info.getDescriptor().getFieldNames().length == 0) {
|
|
final String interfaceClassNameS =
|
|
"interfaceClassName=" + getMBeanInterface().getName();
|
|
final String immutableInfoS =
|
|
"immutableInfo=" + immutableInfo;
|
|
desc = new ImmutableDescriptor(interfaceClassNameS, immutableInfoS);
|
|
desc = descriptors.get(desc);
|
|
} else {
|
|
Descriptor d = info.getDescriptor();
|
|
Map<String,Object> fields = new HashMap<String,Object>();
|
|
for (String fieldName : d.getFieldNames()) {
|
|
if (fieldName.equals("immutableInfo")) {
|
|
// Replace immutableInfo as the underlying MBean/MXBean
|
|
// could already implement NotificationBroadcaster and
|
|
// return immutableInfo=true in its MBeanInfo.
|
|
fields.put(fieldName, Boolean.toString(immutableInfo));
|
|
} else {
|
|
fields.put(fieldName, d.getFieldValue(fieldName));
|
|
}
|
|
}
|
|
desc = new ImmutableDescriptor(fields);
|
|
}
|
|
return desc;
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* Return the MBeanInfo cached for this object.
|
|
*
|
|
* <p>Subclasses may redefine this method in order to implement their
|
|
* own caching policy. The default implementation stores one
|
|
* {@link MBeanInfo} object per instance.
|
|
*
|
|
* @return The cached MBeanInfo, or null if no MBeanInfo is cached.
|
|
*
|
|
* @see #cacheMBeanInfo(MBeanInfo)
|
|
**/
|
|
protected MBeanInfo getCachedMBeanInfo() {
|
|
return cachedMBeanInfo;
|
|
}
|
|
|
|
/**
|
|
* Customization hook:
|
|
* cache the MBeanInfo built for this object.
|
|
*
|
|
* <p>Subclasses may redefine this method in order to implement
|
|
* their own caching policy. The default implementation stores
|
|
* <code>info</code> in this instance. A subclass can define
|
|
* other policies, such as not saving <code>info</code> (so it is
|
|
* reconstructed every time {@link #getMBeanInfo()} is called) or
|
|
* sharing a unique {@link MBeanInfo} object when several
|
|
* <code>StandardMBean</code> instances have equal {@link
|
|
* MBeanInfo} values.
|
|
*
|
|
* @param info the new <code>MBeanInfo</code> to cache. Any
|
|
* previously cached value is discarded. This parameter may be
|
|
* null, in which case there is no new cached value.
|
|
**/
|
|
protected void cacheMBeanInfo(MBeanInfo info) {
|
|
cachedMBeanInfo = info;
|
|
}
|
|
|
|
private boolean isMXBean() {
|
|
return mbean.isMXBean();
|
|
}
|
|
|
|
private static <T> boolean identicalArrays(T[] a, T[] b) {
|
|
if (a == b)
|
|
return true;
|
|
if (a == null || b == null || a.length != b.length)
|
|
return false;
|
|
for (int i = 0; i < a.length; i++) {
|
|
if (a[i] != b[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static <T> boolean equal(T a, T b) {
|
|
if (a == b)
|
|
return true;
|
|
if (a == null || b == null)
|
|
return false;
|
|
return a.equals(b);
|
|
}
|
|
|
|
private static MBeanParameterInfo
|
|
customize(MBeanParameterInfo pi,
|
|
String name,
|
|
String description) {
|
|
if (equal(name, pi.getName()) &&
|
|
equal(description, pi.getDescription()))
|
|
return pi;
|
|
else if (pi instanceof OpenMBeanParameterInfo) {
|
|
OpenMBeanParameterInfo opi = (OpenMBeanParameterInfo) pi;
|
|
return new OpenMBeanParameterInfoSupport(name,
|
|
description,
|
|
opi.getOpenType(),
|
|
pi.getDescriptor());
|
|
} else {
|
|
return new MBeanParameterInfo(name,
|
|
pi.getType(),
|
|
description,
|
|
pi.getDescriptor());
|
|
}
|
|
}
|
|
|
|
private static MBeanConstructorInfo
|
|
customize(MBeanConstructorInfo ci,
|
|
String description,
|
|
MBeanParameterInfo[] signature) {
|
|
if (equal(description, ci.getDescription()) &&
|
|
identicalArrays(signature, ci.getSignature()))
|
|
return ci;
|
|
if (ci instanceof OpenMBeanConstructorInfo) {
|
|
OpenMBeanParameterInfo[] oparams =
|
|
paramsToOpenParams(signature);
|
|
return new OpenMBeanConstructorInfoSupport(ci.getName(),
|
|
description,
|
|
oparams,
|
|
ci.getDescriptor());
|
|
} else {
|
|
return new MBeanConstructorInfo(ci.getName(),
|
|
description,
|
|
signature,
|
|
ci.getDescriptor());
|
|
}
|
|
}
|
|
|
|
private static MBeanOperationInfo
|
|
customize(MBeanOperationInfo oi,
|
|
String description,
|
|
MBeanParameterInfo[] signature,
|
|
int impact) {
|
|
if (equal(description, oi.getDescription()) &&
|
|
identicalArrays(signature, oi.getSignature()) &&
|
|
impact == oi.getImpact())
|
|
return oi;
|
|
if (oi instanceof OpenMBeanOperationInfo) {
|
|
OpenMBeanOperationInfo ooi = (OpenMBeanOperationInfo) oi;
|
|
OpenMBeanParameterInfo[] oparams =
|
|
paramsToOpenParams(signature);
|
|
return new OpenMBeanOperationInfoSupport(oi.getName(),
|
|
description,
|
|
oparams,
|
|
ooi.getReturnOpenType(),
|
|
impact,
|
|
oi.getDescriptor());
|
|
} else {
|
|
return new MBeanOperationInfo(oi.getName(),
|
|
description,
|
|
signature,
|
|
oi.getReturnType(),
|
|
impact,
|
|
oi.getDescriptor());
|
|
}
|
|
}
|
|
|
|
private static MBeanAttributeInfo
|
|
customize(MBeanAttributeInfo ai,
|
|
String description) {
|
|
if (equal(description, ai.getDescription()))
|
|
return ai;
|
|
if (ai instanceof OpenMBeanAttributeInfo) {
|
|
OpenMBeanAttributeInfo oai = (OpenMBeanAttributeInfo) ai;
|
|
return new OpenMBeanAttributeInfoSupport(ai.getName(),
|
|
description,
|
|
oai.getOpenType(),
|
|
ai.isReadable(),
|
|
ai.isWritable(),
|
|
ai.isIs(),
|
|
ai.getDescriptor());
|
|
} else {
|
|
return new MBeanAttributeInfo(ai.getName(),
|
|
ai.getType(),
|
|
description,
|
|
ai.isReadable(),
|
|
ai.isWritable(),
|
|
ai.isIs(),
|
|
ai.getDescriptor());
|
|
}
|
|
}
|
|
|
|
private static OpenMBeanParameterInfo[]
|
|
paramsToOpenParams(MBeanParameterInfo[] params) {
|
|
if (params instanceof OpenMBeanParameterInfo[])
|
|
return (OpenMBeanParameterInfo[]) params;
|
|
OpenMBeanParameterInfo[] oparams =
|
|
new OpenMBeanParameterInfoSupport[params.length];
|
|
System.arraycopy(params, 0, oparams, 0, params.length);
|
|
return oparams;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Build the custom MBeanConstructorInfo[]
|
|
// ------------------------------------------------------------------
|
|
private MBeanConstructorInfo[]
|
|
getConstructors(MBeanInfo info, Object impl) {
|
|
final MBeanConstructorInfo[] ctors =
|
|
getConstructors(info.getConstructors(), impl);
|
|
if (ctors == null)
|
|
return null;
|
|
final int ctorlen = ctors.length;
|
|
final MBeanConstructorInfo[] nctors = new MBeanConstructorInfo[ctorlen];
|
|
for (int i=0; i<ctorlen; i++) {
|
|
final MBeanConstructorInfo c = ctors[i];
|
|
final MBeanParameterInfo[] params = c.getSignature();
|
|
final MBeanParameterInfo[] nps;
|
|
if (params != null) {
|
|
final int plen = params.length;
|
|
nps = new MBeanParameterInfo[plen];
|
|
for (int ii=0;ii<plen;ii++) {
|
|
MBeanParameterInfo p = params[ii];
|
|
nps[ii] = customize(p,
|
|
getParameterName(c,p,ii),
|
|
getDescription(c,p,ii));
|
|
}
|
|
} else {
|
|
nps = null;
|
|
}
|
|
nctors[i] =
|
|
customize(c, getDescription(c), nps);
|
|
}
|
|
return nctors;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Build the custom MBeanOperationInfo[]
|
|
// ------------------------------------------------------------------
|
|
private MBeanOperationInfo[] getOperations(MBeanInfo info) {
|
|
final MBeanOperationInfo[] ops = info.getOperations();
|
|
if (ops == null)
|
|
return null;
|
|
final int oplen = ops.length;
|
|
final MBeanOperationInfo[] nops = new MBeanOperationInfo[oplen];
|
|
for (int i=0; i<oplen; i++) {
|
|
final MBeanOperationInfo o = ops[i];
|
|
final MBeanParameterInfo[] params = o.getSignature();
|
|
final MBeanParameterInfo[] nps;
|
|
if (params != null) {
|
|
final int plen = params.length;
|
|
nps = new MBeanParameterInfo[plen];
|
|
for (int ii=0;ii<plen;ii++) {
|
|
MBeanParameterInfo p = params[ii];
|
|
nps[ii] = customize(p,
|
|
getParameterName(o,p,ii),
|
|
getDescription(o,p,ii));
|
|
}
|
|
} else {
|
|
nps = null;
|
|
}
|
|
nops[i] = customize(o, getDescription(o), nps, getImpact(o));
|
|
}
|
|
return nops;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Build the custom MBeanAttributeInfo[]
|
|
// ------------------------------------------------------------------
|
|
private MBeanAttributeInfo[] getAttributes(MBeanInfo info) {
|
|
final MBeanAttributeInfo[] atts = info.getAttributes();
|
|
if (atts == null)
|
|
return null; // should not happen
|
|
final MBeanAttributeInfo[] natts;
|
|
final int attlen = atts.length;
|
|
natts = new MBeanAttributeInfo[attlen];
|
|
for (int i=0; i<attlen; i++) {
|
|
final MBeanAttributeInfo a = atts[i];
|
|
natts[i] = customize(a, getDescription(a));
|
|
}
|
|
return natts;
|
|
}
|
|
|
|
/**
|
|
* <p>Allows the MBean to perform any operations it needs before
|
|
* being registered in the MBean server. If the name of the MBean
|
|
* is not specified, the MBean can provide a name for its
|
|
* registration. If any exception is raised, the MBean will not be
|
|
* registered in the MBean server.</p>
|
|
*
|
|
* <p>The default implementation of this method returns the {@code name}
|
|
* parameter. It does nothing else for
|
|
* Standard MBeans. For MXBeans, it records the {@code MBeanServer}
|
|
* and {@code ObjectName} parameters so they can be used to translate
|
|
* inter-MXBean references.</p>
|
|
*
|
|
* <p>It is good practice for a subclass that overrides this method
|
|
* to call the overridden method via {@code super.preRegister(...)}.
|
|
* This is necessary if this object is an MXBean that is referenced
|
|
* by attributes or operations in other MXBeans.</p>
|
|
*
|
|
* @param server The MBean server in which the MBean will be registered.
|
|
*
|
|
* @param name The object name of the MBean. This name is null if
|
|
* the name parameter to one of the <code>createMBean</code> or
|
|
* <code>registerMBean</code> methods in the {@link MBeanServer}
|
|
* interface is null. In that case, this method must return a
|
|
* non-null ObjectName for the new MBean.
|
|
*
|
|
* @return The name under which the MBean is to be registered.
|
|
* This value must not be null. If the <code>name</code>
|
|
* parameter is not null, it will usually but not necessarily be
|
|
* the returned value.
|
|
*
|
|
* @throws IllegalArgumentException if this is an MXBean and
|
|
* {@code name} is null.
|
|
*
|
|
* @throws InstanceAlreadyExistsException if this is an MXBean and
|
|
* it has already been registered under another name (in this
|
|
* MBean Server or another).
|
|
*
|
|
* @throws Exception no other checked exceptions are thrown by
|
|
* this method but {@code Exception} is declared so that subclasses
|
|
* can override the method and throw their own exceptions.
|
|
*
|
|
* @since 1.6
|
|
*/
|
|
public ObjectName preRegister(MBeanServer server, ObjectName name)
|
|
throws Exception {
|
|
mbean.register(server, name);
|
|
return name;
|
|
}
|
|
|
|
/**
|
|
* <p>Allows the MBean to perform any operations needed after having been
|
|
* registered in the MBean server or after the registration has failed.</p>
|
|
*
|
|
* <p>The default implementation of this method does nothing for
|
|
* Standard MBeans. For MXBeans, it undoes any work done by
|
|
* {@link #preRegister preRegister} if registration fails.</p>
|
|
*
|
|
* <p>It is good practice for a subclass that overrides this method
|
|
* to call the overridden method via {@code super.postRegister(...)}.
|
|
* This is necessary if this object is an MXBean that is referenced
|
|
* by attributes or operations in other MXBeans.</p>
|
|
*
|
|
* @param registrationDone Indicates whether or not the MBean has
|
|
* been successfully registered in the MBean server. The value
|
|
* false means that the registration phase has failed.
|
|
*
|
|
* @since 1.6
|
|
*/
|
|
public void postRegister(Boolean registrationDone) {
|
|
if (!registrationDone)
|
|
mbean.unregister();
|
|
}
|
|
|
|
/**
|
|
* <p>Allows the MBean to perform any operations it needs before
|
|
* being unregistered by the MBean server.</p>
|
|
*
|
|
* <p>The default implementation of this method does nothing.</p>
|
|
*
|
|
* <p>It is good practice for a subclass that overrides this method
|
|
* to call the overridden method via {@code super.preDeregister(...)}.</p>
|
|
*
|
|
* @throws Exception no checked exceptions are throw by this method
|
|
* but {@code Exception} is declared so that subclasses can override
|
|
* this method and throw their own exceptions.
|
|
*
|
|
* @since 1.6
|
|
*/
|
|
public void preDeregister() throws Exception {
|
|
}
|
|
|
|
/**
|
|
* <p>Allows the MBean to perform any operations needed after having been
|
|
* unregistered in the MBean server.</p>
|
|
*
|
|
* <p>The default implementation of this method does nothing for
|
|
* Standard MBeans. For MXBeans, it removes any information that
|
|
* was recorded by the {@link #preRegister preRegister} method.</p>
|
|
*
|
|
* <p>It is good practice for a subclass that overrides this method
|
|
* to call the overridden method via {@code super.postRegister(...)}.
|
|
* This is necessary if this object is an MXBean that is referenced
|
|
* by attributes or operations in other MXBeans.</p>
|
|
*
|
|
* @since 1.6
|
|
*/
|
|
public void postDeregister() {
|
|
mbean.unregister();
|
|
}
|
|
|
|
//
|
|
// MBeanInfo immutability
|
|
//
|
|
|
|
/**
|
|
* Cached results of previous calls to immutableInfo. This is
|
|
* a WeakHashMap so that we don't prevent a class from being
|
|
* garbage collected just because we know whether its MBeanInfo
|
|
* is immutable.
|
|
*/
|
|
private static final Map<Class<?>, Boolean> mbeanInfoSafeMap =
|
|
new WeakHashMap<Class<?>, Boolean>();
|
|
|
|
/**
|
|
* Return true if {@code subclass} is known to preserve the immutability
|
|
* of the {@code MBeanInfo}. The {@code subclass} is considered to have
|
|
* an immutable {@code MBeanInfo} if it does not override any of the
|
|
* getMBeanInfo, getCachedMBeanInfo, cacheMBeanInfo and getNotificationInfo
|
|
* methods.
|
|
*/
|
|
static boolean immutableInfo(Class<? extends StandardMBean> subclass) {
|
|
if (subclass == StandardMBean.class ||
|
|
subclass == StandardEmitterMBean.class)
|
|
return true;
|
|
synchronized (mbeanInfoSafeMap) {
|
|
Boolean safe = mbeanInfoSafeMap.get(subclass);
|
|
if (safe == null) {
|
|
try {
|
|
MBeanInfoSafeAction action =
|
|
new MBeanInfoSafeAction(subclass);
|
|
safe = AccessController.doPrivileged(action);
|
|
} catch (Exception e) { // e.g. SecurityException
|
|
/* We don't know, so we assume it isn't. */
|
|
safe = false;
|
|
}
|
|
mbeanInfoSafeMap.put(subclass, safe);
|
|
}
|
|
return safe;
|
|
}
|
|
}
|
|
|
|
static boolean overrides(Class<?> subclass, Class<?> superclass,
|
|
String name, Class<?>... params) {
|
|
for (Class<?> c = subclass; c != superclass; c = c.getSuperclass()) {
|
|
try {
|
|
c.getDeclaredMethod(name, params);
|
|
return true;
|
|
} catch (NoSuchMethodException e) {
|
|
// OK: this class doesn't override it
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static class MBeanInfoSafeAction
|
|
implements PrivilegedAction<Boolean> {
|
|
|
|
private final Class<?> subclass;
|
|
|
|
MBeanInfoSafeAction(Class<?> subclass) {
|
|
this.subclass = subclass;
|
|
}
|
|
|
|
public Boolean run() {
|
|
// Check for "void cacheMBeanInfo(MBeanInfo)" method.
|
|
//
|
|
if (overrides(subclass, StandardMBean.class,
|
|
"cacheMBeanInfo", MBeanInfo.class))
|
|
return false;
|
|
|
|
// Check for "MBeanInfo getCachedMBeanInfo()" method.
|
|
//
|
|
if (overrides(subclass, StandardMBean.class,
|
|
"getCachedMBeanInfo", (Class<?>[]) null))
|
|
return false;
|
|
|
|
// Check for "MBeanInfo getMBeanInfo()" method.
|
|
//
|
|
if (overrides(subclass, StandardMBean.class,
|
|
"getMBeanInfo", (Class<?>[]) null))
|
|
return false;
|
|
|
|
// Check for "MBeanNotificationInfo[] getNotificationInfo()"
|
|
// method.
|
|
//
|
|
// This method is taken into account for the MBeanInfo
|
|
// immutability checks if and only if the given subclass is
|
|
// StandardEmitterMBean itself or can be assigned to
|
|
// StandardEmitterMBean.
|
|
//
|
|
if (StandardEmitterMBean.class.isAssignableFrom(subclass))
|
|
if (overrides(subclass, StandardEmitterMBean.class,
|
|
"getNotificationInfo", (Class<?>[]) null))
|
|
return false;
|
|
return true;
|
|
}
|
|
}
|
|
}
|