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.
277 lines
10 KiB
277 lines
10 KiB
/*
|
|
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package com.sun.jmx.mbeanserver;
|
|
|
|
|
|
import javax.management.Attribute;
|
|
import javax.management.AttributeList;
|
|
import javax.management.AttributeNotFoundException;
|
|
import javax.management.InvalidAttributeValueException;
|
|
import javax.management.MBeanException;
|
|
import javax.management.MBeanInfo;
|
|
import javax.management.MBeanRegistration;
|
|
import javax.management.MBeanServer;
|
|
import javax.management.NotCompliantMBeanException;
|
|
import javax.management.ObjectName;
|
|
import javax.management.ReflectionException;
|
|
import com.sun.jmx.mbeanserver.MXBeanMappingFactory;
|
|
import sun.reflect.misc.ReflectUtil;
|
|
|
|
/**
|
|
* Base class for MBeans. There is one instance of this class for
|
|
* every Standard MBean and every MXBean. We try to limit the amount
|
|
* of information per instance so we can handle very large numbers of
|
|
* MBeans comfortably.
|
|
*
|
|
* @param <M> either Method or ConvertingMethod, for Standard MBeans
|
|
* and MXBeans respectively.
|
|
*
|
|
* @since 1.6
|
|
*/
|
|
/*
|
|
* We maintain a couple of caches to increase sharing between
|
|
* different MBeans of the same type and also to reduce creation time
|
|
* for the second and subsequent instances of the same type.
|
|
*
|
|
* The first cache maps from an MBean interface to a PerInterface
|
|
* object containing information parsed out of the interface. The
|
|
* interface is either a Standard MBean interface or an MXBean
|
|
* interface, and there is one cache for each case.
|
|
*
|
|
* The PerInterface includes an MBeanInfo. This contains the
|
|
* attributes and operations parsed out of the interface's methods,
|
|
* plus a basic Descriptor for the interface containing at least the
|
|
* interfaceClassName field and any fields derived from annotations on
|
|
* the interface. This MBeanInfo can never be the MBeanInfo for any
|
|
* actual MBean, because an MBeanInfo's getClassName() is the name of
|
|
* a concrete class and we don't know what the class will be.
|
|
* Furthermore a real MBeanInfo may need to add constructors and/or
|
|
* notifications to the MBeanInfo.
|
|
*
|
|
* The PerInterface also contains an MBeanDispatcher which is able to
|
|
* route getAttribute, setAttribute, and invoke to the appropriate
|
|
* method of the interface, including doing any necessary translation
|
|
* of parameters and return values for MXBeans.
|
|
*
|
|
* The PerInterface also contains the original Class for the interface.
|
|
*
|
|
* We need to be careful about references. When there are no MBeans
|
|
* with a given interface, there must not be any strong references to
|
|
* the interface Class. Otherwise it could never be garbage collected,
|
|
* and neither could its ClassLoader or any other classes loaded by
|
|
* its ClassLoader. Therefore the cache must wrap the PerInterface
|
|
* in a WeakReference. Each instance of MBeanSupport has a strong
|
|
* reference to its PerInterface, which prevents PerInterface instances
|
|
* from being garbage-collected prematurely.
|
|
*
|
|
* The second cache maps from a concrete class and an MBean interface
|
|
* that that class implements to the MBeanInfo for that class and
|
|
* interface. (The ability to specify an interface separately comes
|
|
* from the class StandardMBean. MBeans registered directly in the
|
|
* MBean Server will always have the same interface here.)
|
|
*
|
|
* The MBeanInfo in this second cache will be the MBeanInfo from the
|
|
* PerInterface cache for the given itnerface, but with the
|
|
* getClassName() having the concrete class's name, and the public
|
|
* constructors based on the concrete class's constructors. This
|
|
* MBeanInfo can be shared between all instances of the concrete class
|
|
* specifying the same interface, except instances that are
|
|
* NotificationBroadcasters. NotificationBroadcasters supply the
|
|
* MBeanNotificationInfo[] in the MBeanInfo based on the instance
|
|
* method NotificationBroadcaster.getNotificationInfo(), so two
|
|
* instances of the same concrete class do not necessarily have the
|
|
* same MBeanNotificationInfo[]. Currently we do not try to detect
|
|
* when they do, although it would probably be worthwhile doing that
|
|
* since it is a very common case.
|
|
*
|
|
* Standard MBeans additionally have the property that
|
|
* getNotificationInfo() must in principle be called every time
|
|
* getMBeanInfo() is called for the MBean, since the returned array is
|
|
* allowed to change over time. We attempt to reduce the cost of
|
|
* doing this by detecting when the Standard MBean is a subclass of
|
|
* NotificationBroadcasterSupport that does not override
|
|
* getNotificationInfo(), meaning that the MBeanNotificationInfo[] is
|
|
* the one that was supplied to the constructor. MXBeans do not have
|
|
* this problem because their getNotificationInfo() method is called
|
|
* only once.
|
|
*
|
|
*/
|
|
public abstract class MBeanSupport<M>
|
|
implements DynamicMBean2, MBeanRegistration {
|
|
|
|
<T> MBeanSupport(T resource, Class<T> mbeanInterfaceType)
|
|
throws NotCompliantMBeanException {
|
|
if (mbeanInterfaceType == null)
|
|
throw new NotCompliantMBeanException("Null MBean interface");
|
|
if (!mbeanInterfaceType.isInstance(resource)) {
|
|
final String msg =
|
|
"Resource class " + resource.getClass().getName() +
|
|
" is not an instance of " + mbeanInterfaceType.getName();
|
|
throw new NotCompliantMBeanException(msg);
|
|
}
|
|
ReflectUtil.checkPackageAccess(mbeanInterfaceType);
|
|
this.resource = resource;
|
|
MBeanIntrospector<M> introspector = getMBeanIntrospector();
|
|
this.perInterface = introspector.getPerInterface(mbeanInterfaceType);
|
|
this.mbeanInfo = introspector.getMBeanInfo(resource, perInterface);
|
|
}
|
|
|
|
/** Return the appropriate introspector for this type of MBean. */
|
|
abstract MBeanIntrospector<M> getMBeanIntrospector();
|
|
|
|
/**
|
|
* Return a cookie for this MBean. This cookie will be passed to
|
|
* MBean method invocations where it can supply additional information
|
|
* to the invocation. For example, with MXBeans it can be used to
|
|
* supply the MXBeanLookup context for resolving inter-MXBean references.
|
|
*/
|
|
abstract Object getCookie();
|
|
|
|
public final boolean isMXBean() {
|
|
return perInterface.isMXBean();
|
|
}
|
|
|
|
// Methods that javax.management.StandardMBean should call from its
|
|
// preRegister and postRegister, given that it is not supposed to
|
|
// call the contained object's preRegister etc methods even if it has them
|
|
public abstract void register(MBeanServer mbs, ObjectName name)
|
|
throws Exception;
|
|
public abstract void unregister();
|
|
|
|
public final ObjectName preRegister(MBeanServer server, ObjectName name)
|
|
throws Exception {
|
|
if (resource instanceof MBeanRegistration)
|
|
name = ((MBeanRegistration) resource).preRegister(server, name);
|
|
return name;
|
|
}
|
|
|
|
public final void preRegister2(MBeanServer server, ObjectName name)
|
|
throws Exception {
|
|
register(server, name);
|
|
}
|
|
|
|
public final void registerFailed() {
|
|
unregister();
|
|
}
|
|
|
|
public final void postRegister(Boolean registrationDone) {
|
|
if (resource instanceof MBeanRegistration)
|
|
((MBeanRegistration) resource).postRegister(registrationDone);
|
|
}
|
|
|
|
public final void preDeregister() throws Exception {
|
|
if (resource instanceof MBeanRegistration)
|
|
((MBeanRegistration) resource).preDeregister();
|
|
}
|
|
|
|
public final void postDeregister() {
|
|
// Undo any work from registration. We do this in postDeregister
|
|
// not preDeregister, because if the user preDeregister throws an
|
|
// exception then the MBean is not unregistered.
|
|
try {
|
|
unregister();
|
|
} finally {
|
|
if (resource instanceof MBeanRegistration)
|
|
((MBeanRegistration) resource).postDeregister();
|
|
}
|
|
}
|
|
|
|
public final Object getAttribute(String attribute)
|
|
throws AttributeNotFoundException,
|
|
MBeanException,
|
|
ReflectionException {
|
|
return perInterface.getAttribute(resource, attribute, getCookie());
|
|
}
|
|
|
|
public final AttributeList getAttributes(String[] attributes) {
|
|
final AttributeList result = new AttributeList(attributes.length);
|
|
for (String attrName : attributes) {
|
|
try {
|
|
final Object attrValue = getAttribute(attrName);
|
|
result.add(new Attribute(attrName, attrValue));
|
|
} catch (Exception e) {
|
|
// OK: attribute is not included in returned list, per spec
|
|
// XXX: log the exception
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public final void setAttribute(Attribute attribute)
|
|
throws AttributeNotFoundException,
|
|
InvalidAttributeValueException,
|
|
MBeanException,
|
|
ReflectionException {
|
|
final String name = attribute.getName();
|
|
final Object value = attribute.getValue();
|
|
perInterface.setAttribute(resource, name, value, getCookie());
|
|
}
|
|
|
|
public final AttributeList setAttributes(AttributeList attributes) {
|
|
final AttributeList result = new AttributeList(attributes.size());
|
|
for (Object attrObj : attributes) {
|
|
// We can't use AttributeList.asList because it has side-effects
|
|
Attribute attr = (Attribute) attrObj;
|
|
try {
|
|
setAttribute(attr);
|
|
result.add(new Attribute(attr.getName(), attr.getValue()));
|
|
} catch (Exception e) {
|
|
// OK: attribute is not included in returned list, per spec
|
|
// XXX: log the exception
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public final Object invoke(String operation, Object[] params,
|
|
String[] signature)
|
|
throws MBeanException, ReflectionException {
|
|
return perInterface.invoke(resource, operation, params, signature,
|
|
getCookie());
|
|
}
|
|
|
|
// Overridden by StandardMBeanSupport
|
|
public MBeanInfo getMBeanInfo() {
|
|
return mbeanInfo;
|
|
}
|
|
|
|
public final String getClassName() {
|
|
return resource.getClass().getName();
|
|
}
|
|
|
|
public final Object getResource() {
|
|
return resource;
|
|
}
|
|
|
|
public final Class<?> getMBeanInterface() {
|
|
return perInterface.getMBeanInterface();
|
|
}
|
|
|
|
private final MBeanInfo mbeanInfo;
|
|
private final Object resource;
|
|
private final PerInterface<M> perInterface;
|
|
}
|