0N/A/*
2362N/A * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.jmx.mbeanserver;
0N/A
0N/A
0N/Aimport javax.management.Attribute;
0N/Aimport javax.management.AttributeList;
0N/Aimport javax.management.AttributeNotFoundException;
0N/Aimport javax.management.InvalidAttributeValueException;
0N/Aimport javax.management.MBeanException;
0N/Aimport javax.management.MBeanInfo;
0N/Aimport javax.management.MBeanRegistration;
0N/Aimport javax.management.MBeanServer;
0N/Aimport javax.management.NotCompliantMBeanException;
0N/Aimport javax.management.ObjectName;
0N/Aimport javax.management.ReflectionException;
1790N/Aimport com.sun.jmx.mbeanserver.MXBeanMappingFactory;
5789N/Aimport sun.reflect.misc.ReflectUtil;
0N/A
0N/A/**
0N/A * Base class for MBeans. There is one instance of this class for
0N/A * every Standard MBean and every MXBean. We try to limit the amount
0N/A * of information per instance so we can handle very large numbers of
0N/A * MBeans comfortably.
0N/A *
0N/A * @param <M> either Method or ConvertingMethod, for Standard MBeans
0N/A * and MXBeans respectively.
0N/A *
0N/A * @since 1.6
0N/A */
0N/A/*
0N/A * We maintain a couple of caches to increase sharing between
0N/A * different MBeans of the same type and also to reduce creation time
0N/A * for the second and subsequent instances of the same type.
0N/A *
0N/A * The first cache maps from an MBean interface to a PerInterface
0N/A * object containing information parsed out of the interface. The
0N/A * interface is either a Standard MBean interface or an MXBean
0N/A * interface, and there is one cache for each case.
0N/A *
0N/A * The PerInterface includes an MBeanInfo. This contains the
0N/A * attributes and operations parsed out of the interface's methods,
0N/A * plus a basic Descriptor for the interface containing at least the
0N/A * interfaceClassName field and any fields derived from annotations on
0N/A * the interface. This MBeanInfo can never be the MBeanInfo for any
0N/A * actual MBean, because an MBeanInfo's getClassName() is the name of
0N/A * a concrete class and we don't know what the class will be.
0N/A * Furthermore a real MBeanInfo may need to add constructors and/or
0N/A * notifications to the MBeanInfo.
0N/A *
0N/A * The PerInterface also contains an MBeanDispatcher which is able to
0N/A * route getAttribute, setAttribute, and invoke to the appropriate
0N/A * method of the interface, including doing any necessary translation
0N/A * of parameters and return values for MXBeans.
0N/A *
0N/A * The PerInterface also contains the original Class for the interface.
0N/A *
0N/A * We need to be careful about references. When there are no MBeans
0N/A * with a given interface, there must not be any strong references to
0N/A * the interface Class. Otherwise it could never be garbage collected,
0N/A * and neither could its ClassLoader or any other classes loaded by
0N/A * its ClassLoader. Therefore the cache must wrap the PerInterface
0N/A * in a WeakReference. Each instance of MBeanSupport has a strong
0N/A * reference to its PerInterface, which prevents PerInterface instances
0N/A * from being garbage-collected prematurely.
0N/A *
0N/A * The second cache maps from a concrete class and an MBean interface
0N/A * that that class implements to the MBeanInfo for that class and
0N/A * interface. (The ability to specify an interface separately comes
0N/A * from the class StandardMBean. MBeans registered directly in the
0N/A * MBean Server will always have the same interface here.)
0N/A *
0N/A * The MBeanInfo in this second cache will be the MBeanInfo from the
0N/A * PerInterface cache for the given itnerface, but with the
0N/A * getClassName() having the concrete class's name, and the public
0N/A * constructors based on the concrete class's constructors. This
0N/A * MBeanInfo can be shared between all instances of the concrete class
0N/A * specifying the same interface, except instances that are
0N/A * NotificationBroadcasters. NotificationBroadcasters supply the
0N/A * MBeanNotificationInfo[] in the MBeanInfo based on the instance
0N/A * method NotificationBroadcaster.getNotificationInfo(), so two
0N/A * instances of the same concrete class do not necessarily have the
0N/A * same MBeanNotificationInfo[]. Currently we do not try to detect
0N/A * when they do, although it would probably be worthwhile doing that
0N/A * since it is a very common case.
0N/A *
0N/A * Standard MBeans additionally have the property that
0N/A * getNotificationInfo() must in principle be called every time
0N/A * getMBeanInfo() is called for the MBean, since the returned array is
0N/A * allowed to change over time. We attempt to reduce the cost of
0N/A * doing this by detecting when the Standard MBean is a subclass of
0N/A * NotificationBroadcasterSupport that does not override
0N/A * getNotificationInfo(), meaning that the MBeanNotificationInfo[] is
0N/A * the one that was supplied to the constructor. MXBeans do not have
0N/A * this problem because their getNotificationInfo() method is called
0N/A * only once.
0N/A *
0N/A */
0N/Apublic abstract class MBeanSupport<M>
0N/A implements DynamicMBean2, MBeanRegistration {
0N/A
1790N/A <T> MBeanSupport(T resource, Class<T> mbeanInterfaceType)
0N/A throws NotCompliantMBeanException {
353N/A if (mbeanInterfaceType == null)
0N/A throw new NotCompliantMBeanException("Null MBean interface");
353N/A if (!mbeanInterfaceType.isInstance(resource)) {
0N/A final String msg =
0N/A "Resource class " + resource.getClass().getName() +
353N/A " is not an instance of " + mbeanInterfaceType.getName();
0N/A throw new NotCompliantMBeanException(msg);
0N/A }
5789N/A ReflectUtil.checkPackageAccess(mbeanInterfaceType);
0N/A this.resource = resource;
1790N/A MBeanIntrospector<M> introspector = getMBeanIntrospector();
353N/A this.perInterface = introspector.getPerInterface(mbeanInterfaceType);
0N/A this.mbeanInfo = introspector.getMBeanInfo(resource, perInterface);
0N/A }
0N/A
0N/A /** Return the appropriate introspector for this type of MBean. */
1790N/A abstract MBeanIntrospector<M> getMBeanIntrospector();
0N/A
0N/A /**
0N/A * Return a cookie for this MBean. This cookie will be passed to
0N/A * MBean method invocations where it can supply additional information
0N/A * to the invocation. For example, with MXBeans it can be used to
0N/A * supply the MXBeanLookup context for resolving inter-MXBean references.
0N/A */
0N/A abstract Object getCookie();
0N/A
0N/A public final boolean isMXBean() {
0N/A return perInterface.isMXBean();
0N/A }
0N/A
0N/A // Methods that javax.management.StandardMBean should call from its
0N/A // preRegister and postRegister, given that it is not supposed to
0N/A // call the contained object's preRegister etc methods even if it has them
0N/A public abstract void register(MBeanServer mbs, ObjectName name)
0N/A throws Exception;
0N/A public abstract void unregister();
0N/A
0N/A public final ObjectName preRegister(MBeanServer server, ObjectName name)
0N/A throws Exception {
0N/A if (resource instanceof MBeanRegistration)
353N/A name = ((MBeanRegistration) resource).preRegister(server, name);
353N/A return name;
0N/A }
0N/A
0N/A public final void preRegister2(MBeanServer server, ObjectName name)
0N/A throws Exception {
0N/A register(server, name);
0N/A }
0N/A
0N/A public final void registerFailed() {
0N/A unregister();
0N/A }
0N/A
0N/A public final void postRegister(Boolean registrationDone) {
0N/A if (resource instanceof MBeanRegistration)
0N/A ((MBeanRegistration) resource).postRegister(registrationDone);
0N/A }
0N/A
0N/A public final void preDeregister() throws Exception {
0N/A if (resource instanceof MBeanRegistration)
0N/A ((MBeanRegistration) resource).preDeregister();
0N/A }
0N/A
0N/A public final void postDeregister() {
0N/A // Undo any work from registration. We do this in postDeregister
0N/A // not preDeregister, because if the user preDeregister throws an
0N/A // exception then the MBean is not unregistered.
0N/A try {
0N/A unregister();
0N/A } finally {
0N/A if (resource instanceof MBeanRegistration)
0N/A ((MBeanRegistration) resource).postDeregister();
0N/A }
0N/A }
0N/A
0N/A public final Object getAttribute(String attribute)
0N/A throws AttributeNotFoundException,
0N/A MBeanException,
0N/A ReflectionException {
0N/A return perInterface.getAttribute(resource, attribute, getCookie());
0N/A }
0N/A
0N/A public final AttributeList getAttributes(String[] attributes) {
0N/A final AttributeList result = new AttributeList(attributes.length);
0N/A for (String attrName : attributes) {
0N/A try {
0N/A final Object attrValue = getAttribute(attrName);
0N/A result.add(new Attribute(attrName, attrValue));
0N/A } catch (Exception e) {
0N/A // OK: attribute is not included in returned list, per spec
0N/A // XXX: log the exception
0N/A }
0N/A }
0N/A return result;
0N/A }
0N/A
0N/A public final void setAttribute(Attribute attribute)
0N/A throws AttributeNotFoundException,
0N/A InvalidAttributeValueException,
0N/A MBeanException,
0N/A ReflectionException {
0N/A final String name = attribute.getName();
0N/A final Object value = attribute.getValue();
0N/A perInterface.setAttribute(resource, name, value, getCookie());
0N/A }
0N/A
0N/A public final AttributeList setAttributes(AttributeList attributes) {
0N/A final AttributeList result = new AttributeList(attributes.size());
0N/A for (Object attrObj : attributes) {
0N/A // We can't use AttributeList.asList because it has side-effects
0N/A Attribute attr = (Attribute) attrObj;
0N/A try {
0N/A setAttribute(attr);
0N/A result.add(new Attribute(attr.getName(), attr.getValue()));
0N/A } catch (Exception e) {
0N/A // OK: attribute is not included in returned list, per spec
0N/A // XXX: log the exception
0N/A }
0N/A }
0N/A return result;
0N/A }
0N/A
0N/A public final Object invoke(String operation, Object[] params,
0N/A String[] signature)
0N/A throws MBeanException, ReflectionException {
0N/A return perInterface.invoke(resource, operation, params, signature,
0N/A getCookie());
0N/A }
0N/A
0N/A // Overridden by StandardMBeanSupport
0N/A public MBeanInfo getMBeanInfo() {
0N/A return mbeanInfo;
0N/A }
0N/A
0N/A public final String getClassName() {
0N/A return resource.getClass().getName();
0N/A }
0N/A
1790N/A public final Object getResource() {
0N/A return resource;
0N/A }
0N/A
0N/A public final Class<?> getMBeanInterface() {
0N/A return perInterface.getMBeanInterface();
0N/A }
0N/A
0N/A private final MBeanInfo mbeanInfo;
0N/A private final Object resource;
0N/A private final PerInterface<M> perInterface;
0N/A}