/* * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.management; import 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; /** *
An MBean whose management interface is determined by reflection * on a Java interface.
* *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.
* *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...).
* *This class also provides hooks that make it possible to supply * custom descriptions and names for the {@link MBeanInfo} returned by * the DynamicMBean interface.
* *Using this class, an MBean can be created with any * implementation class name Impl and with a management * interface defined (as for current Standard MBeans) by any interface * Intf, in one of two general ways:
* ** MBeanServer mbs; * ... * Impl impl = new Impl(...); * StandardMBean mbean = new StandardMBean(impl, Intf.class, false); * mbs.registerMBean(mbean, objectName); *
* 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); *
In either case, the class Impl must implement the * interface Intf.
* *Standard MBeans based on the naming relationship between * implementation and interface classes are of course still * available.
* *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}.
* * @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 implementation, using the * specified mbeanInterface class. * @param implementation The implementation of this MBean. * Ifnull
, and null implementation is allowed,
* then the implementation is assumed to be this.
* @param mbeanInterface The Management Interface exported by this
* MBean's implementation. If null
, then this
* object will use standard JMX design pattern to determine
* the management interface associated with the given
* implementation.
* @param nullImplementationAllowed true
if a null
* implementation is allowed. If null implementation is allowed,
* and a null implementation is passed, then the implementation
* is assumed to be this.
* @exception IllegalArgumentException if the given
* implementation is null, and null is not allowed.
**/
private Make a DynamicMBean out of the object * implementation, using the specified * mbeanInterface class.
* * @param implementation The implementation of this MBean. * @param mbeanInterface The Management Interface exported by this * MBean's implementation. Ifnull
, then this
* object will use standard JMX design pattern to determine
* the management interface associated with the given
* implementation.
* @param Make a DynamicMBean out of this, using the specified * mbeanInterface class.
* *Calls {@link #StandardMBean(java.lang.Object, java.lang.Class) * this(this,mbeanInterface)}. * This constructor is reserved to subclasses.
* * @param mbeanInterface The Management Interface exported by this * MBean. * * @exception NotCompliantMBeanException if the mbeanInterface * does not follow JMX design patterns for Management Interfaces, or * if this does not implement the specified interface. **/ protected StandardMBean(Class> mbeanInterface) throws NotCompliantMBeanException { construct(null, mbeanInterface, true, false); } /** *Make a DynamicMBean out of the object * implementation, using the specified * mbeanInterface 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.
* * @param implementation The implementation of this MBean. * @param mbeanInterface The Management Interface exported by this * MBean's implementation. Ifnull
, 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 Make a DynamicMBean out of this, using the specified * mbeanInterface 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.
* *Calls {@link #StandardMBean(java.lang.Object, java.lang.Class, boolean) * this(this, mbeanInterface, isMXBean)}. * This constructor is reserved to subclasses.
* * @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 mbeanInterface * does not follow JMX design patterns for Management Interfaces, or * if this 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); } } /** *Replace the implementation object wrapped in this object.
* * @param implementation The new implementation of this Standard MBean * (or MXBean). Theimplementation
object must implement
* the Standard MBean (or MXBean) interface that was supplied when this
* StandardMBean
was constructed.
*
* @exception IllegalArgumentException if the given
* implementation is null.
*
* @exception NotCompliantMBeanException if the given
* implementation 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.* This method implements * {@link javax.management.DynamicMBean#getMBeanInfo() * DynamicMBean.getMBeanInfo()}. *
* 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.
* Otherwise, this method builds a default MBeanInfo for this MBean,
* using the Management Interface specified for this MBean.
*
* While building the MBeanInfo, this method calls the customization
* hooks that make it possible for subclasses to supply their custom
* descriptions, parameter names, etc...
* 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.
*
* 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.
*
* 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();
}
/**
*
Customization hook: * Get the description that will be used in the MBeanFeatureInfo * returned by this MBean.
* *Subclasses may redefine this method in order to supply * their custom description. The default implementation returns * {@link MBeanFeatureInfo#getDescription() * info.getDescription()}.
* *This method is called by * {@link #getDescription(MBeanAttributeInfo)}, * {@link #getDescription(MBeanOperationInfo)}, * {@link #getDescription(MBeanConstructorInfo)}.
* * @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. * *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.
*
* 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 sequence
* MBeanParameterInfo of the MBeanConstructorInfo returned by this MBean.
*
* 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 sequence
* MBeanParameterInfo of the MBeanConstructorInfo returned by this MBean.
*
* 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.
*
* 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 impact flag of the operation that will be used in
* the MBeanOperationInfo returned by this MBean.
*
* 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 sequence
* MBeanParameterInfo of the MBeanOperationInfo returned by this MBean.
*
* 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 sequence
* MBeanParameterInfo of the MBeanOperationInfo returned by this MBean.
*
* 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.
*
* By default, this method returns null
if the wrapped
* implementation is not this. 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 MBeanServer.createMBean(...)
.
* Otherwise, if the wrapped implementation is this,
* ctors is returned.
*
* 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 null
is
* passed, the wrapped implementation is ignored and
* ctors 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.
*
* 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;
}
/**
*
Get the Descriptor that will be used in the MBeanInfo * returned by this MBean.
* *Subclasses may redefine this method in order to supply * their custom descriptor.
* *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.
* * @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(); MapSubclasses 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. * *
Subclasses may redefine this method in order to implement
* their own caching policy. The default implementation stores
* info
in this instance. A subclass can define
* other policies, such as not saving info
(so it is
* reconstructed every time {@link #getMBeanInfo()} is called) or
* sharing a unique {@link MBeanInfo} object when several
* StandardMBean
instances have equal {@link
* MBeanInfo} values.
*
* @param info the new MBeanInfo
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
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.
* *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.
* * @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 thecreateMBean
or
* registerMBean
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 name
* 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;
}
/**
* Allows the MBean to perform any operations needed after having been * registered in the MBean server or after the registration has failed.
* *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.
* *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.
* * @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(); } /** *Allows the MBean to perform any operations it needs before * being unregistered by the MBean server.
* *The default implementation of this method does nothing.
* *It is good practice for a subclass that overrides this method * to call the overridden method via {@code super.preDeregister(...)}.
* * @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 { } /** *Allows the MBean to perform any operations needed after having been * unregistered in the MBean server.
* *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.
* *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.
* * @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