/*
 * Copyright (c) 2005, 2013, 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 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.
Type parameters:
  • <M> – either Method or ConvertingMethod, for Standard MBeans and MXBeans respectively.
Since:1.6
/** * 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.
/** 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.
/** * 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; }