178 lines · 6.7 KB · Java
RawDownload
/* * Copyright (c) 2005, 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 com.sun.jmx.mbeanserver; import static com.sun.jmx.mbeanserver.Util.*; import java.util.Iterator;import java.util.Set; import javax.management.InstanceAlreadyExistsException;import javax.management.JMX;import javax.management.MBeanServer;import javax.management.NotCompliantMBeanException;import javax.management.ObjectName; /** * Base class for MXBeans. * * @since 1.6 */public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {     /**       <p>Construct an MXBean that wraps the given resource using the       given MXBean interface.</p>        @param resource the underlying resource for the new MXBean.        @param mxbeanInterface the interface to be used to determine       the MXBean's management interface.        @param <T> a type parameter that allows the compiler to check       that {@code resource} implements {@code mxbeanInterface},       provided that {@code mxbeanInterface} is a class constant like       {@code SomeMXBean.class}.        @throws IllegalArgumentException if {@code resource} is null or       if it does not implement the class {@code mxbeanInterface} or if       that class is not a valid MXBean interface.    */    public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface)            throws NotCompliantMBeanException {        super(resource, mxbeanInterface);    }     @Override    MBeanIntrospector<ConvertingMethod> getMBeanIntrospector() {        return MXBeanIntrospector.getInstance();    }     @Override    Object getCookie() {        return mxbeanLookup;    }     static <T> Class<? super T> findMXBeanInterface(Class<T> resourceClass) {        if (resourceClass == null)            throw new IllegalArgumentException("Null resource class");        final Set<Class<?>> intfs = transitiveInterfaces(resourceClass);        final Set<Class<?>> candidates = newSet();        for (Class<?> intf : intfs) {            if (JMX.isMXBeanInterface(intf))                candidates.add(intf);        }    reduce:        while (candidates.size() > 1) {            for (Class<?> intf : candidates) {                for (Iterator<Class<?>> it = candidates.iterator(); it.hasNext();                    ) {                    final Class<?> intf2 = it.next();                    if (intf != intf2 && intf2.isAssignableFrom(intf)) {                        it.remove();                        continue reduce;                    }                }            }            final String msg =                "Class " + resourceClass.getName() + " implements more than " +                "one MXBean interface: " + candidates;            throw new IllegalArgumentException(msg);        }        if (candidates.iterator().hasNext()) {            return Util.cast(candidates.iterator().next());        } else {            final String msg =                "Class " + resourceClass.getName() +                " is not a JMX compliant MXBean";            throw new IllegalArgumentException(msg);        }    }     /* Return all interfaces inherited by this class, directly or     * indirectly through the parent class and interfaces.     */    private static Set<Class<?>> transitiveInterfaces(Class<?> c) {        Set<Class<?>> set = newSet();        transitiveInterfaces(c, set);        return set;    }    private static void transitiveInterfaces(Class<?> c, Set<Class<?>> intfs) {        if (c == null)            return;        if (c.isInterface())            intfs.add(c);        transitiveInterfaces(c.getSuperclass(), intfs);        for (Class<?> sup : c.getInterfaces())            transitiveInterfaces(sup, intfs);    }     /*     * The sequence of events for tracking inter-MXBean references is     * relatively complicated.  We use the magical preRegister2 method     * which the MBeanServer knows about.  The steps during registration     * are:     * (1) Call user preRegister, if any.  If exception, abandon.     * (2) Call preRegister2 and hence this register method.  If exception,     * call postRegister(false) and abandon.     * (3) Try to register the MBean.  If exception, call registerFailed()     * which will call the unregister method.  (Also call postRegister(false).)     * (4) If we get this far, we can call postRegister(true).     *     * When we are wrapped in an instance of javax.management.StandardMBean,     * things are simpler.  That class calls this method from its preRegister,     * and propagates any exception.  There is no user preRegister in this case.     * If this method succeeds but registration subsequently fails,     * StandardMBean calls unregister from its postRegister(false) method.     */    @Override    public void register(MBeanServer server, ObjectName name)            throws InstanceAlreadyExistsException {        if (name == null)            throw new IllegalArgumentException("Null object name");        // eventually we could have some logic to supply a default name         synchronized (lock) {            this.mxbeanLookup = MXBeanLookup.lookupFor(server);            this.mxbeanLookup.addReference(name, getResource());            this.objectName = name;        }    }     @Override    public void unregister() {        synchronized (lock) {            if (mxbeanLookup != null) {                if (mxbeanLookup.removeReference(objectName, getResource()))                    objectName = null;            }        }    }    private final Object lock = new Object(); // for mxbeanLookup and objectName     private MXBeanLookup mxbeanLookup;    private ObjectName objectName;}