/* | 
|
 * 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;  | 
|
/** | 
|
 * <p>An MBean whose management interface is determined by reflection | 
|
 * on a Java interface.</p> | 
|
 * | 
|
 * <p>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.</p> | 
|
 * | 
|
 * <p>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...).</p> | 
|
 * | 
|
 * <p> This class also provides hooks that make it possible to supply | 
|
 * custom descriptions and names for the {@link MBeanInfo} returned by | 
|
 * the DynamicMBean interface.</p> | 
|
 * | 
|
 * <p>Using this class, an MBean can be created with any | 
|
 * implementation class name <i>Impl</i> and with a management | 
|
 * interface defined (as for current Standard MBeans) by any interface | 
|
 * <i>Intf</i>, in one of two general ways:</p> | 
|
 * | 
|
 * <ul> | 
|
 * | 
|
 * <li>Using the public constructor | 
|
 *     {@link #StandardMBean(java.lang.Object, java.lang.Class, boolean) | 
|
 *     StandardMBean(impl,interface)}: | 
|
 *     <pre> | 
|
 *     MBeanServer mbs; | 
|
 *     ... | 
|
 *     Impl impl = new Impl(...); | 
|
 *     StandardMBean mbean = new StandardMBean(impl, Intf.class, false); | 
|
 *     mbs.registerMBean(mbean, objectName); | 
|
 *     </pre></li> | 
|
 * | 
|
 * <li>Subclassing StandardMBean: | 
|
 *     <pre> | 
|
 *     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); | 
|
 *     </pre></li> | 
|
 * | 
|
 * </ul> | 
|
 * | 
|
 * <p>In either case, the class <i>Impl</i> must implement the | 
|
 * interface <i>Intf</i>.</p> | 
|
 * | 
|
 * <p>Standard MBeans based on the naming relationship between | 
|
 * implementation and interface classes are of course still | 
|
 * available.</p> | 
|
 * | 
|
 * <p>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}.</p> | 
|
 * | 
|
 * @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 <var>implementation</var>, using the | 
|
     * specified <var>mbeanInterface</var> class. | 
|
     * @param implementation The implementation of this MBean. | 
|
     *        If <code>null</code>, and null implementation is allowed, | 
|
     *        then the implementation is assumed to be <var>this</var>. | 
|
     * @param mbeanInterface The Management Interface exported by this | 
|
     *        MBean's implementation. If <code>null</code>, then this | 
|
     *        object will use standard JMX design pattern to determine | 
|
     *        the management interface associated with the given | 
|
     *        implementation. | 
|
     * @param nullImplementationAllowed <code>true</code> if a null | 
|
     *        implementation is allowed. If null implementation is allowed, | 
|
     *        and a null implementation is passed, then the implementation | 
|
     *        is assumed to be <var>this</var>. | 
|
     * @exception IllegalArgumentException if the given | 
|
     *    <var>implementation</var> is null, and null is not allowed. | 
|
**/  | 
|
private <T> void construct(T implementation, Class<T> mbeanInterface,  | 
|
boolean nullImplementationAllowed,  | 
|
boolean isMXBean)  | 
|
throws NotCompliantMBeanException {  | 
|
if (implementation == null) {  | 
|
// Have to use (T)this rather than mbeanInterface.cast(this)  | 
|
            // because mbeanInterface might be null. | 
|
if (nullImplementationAllowed)  | 
|
implementation = Util.<T>cast(this);  | 
|
else throw new IllegalArgumentException("implementation is null");  | 
|
}  | 
|
if (isMXBean) {  | 
|
if (mbeanInterface == null) {  | 
|
mbeanInterface = Util.cast(Introspector.getMXBeanInterface(  | 
|
implementation.getClass()));  | 
|
}  | 
|
this.mbean = new MXBeanSupport(implementation, mbeanInterface);  | 
|
        } else { | 
|
if (mbeanInterface == null) {  | 
|
mbeanInterface = Util.cast(Introspector.getStandardMBeanInterface(  | 
|
implementation.getClass()));  | 
|
}  | 
|
this.mbean =  | 
|
new StandardMBeanSupport(implementation, mbeanInterface);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * <p>Make a DynamicMBean out of the object | 
|
     * <var>implementation</var>, using the specified | 
|
     * <var>mbeanInterface</var> class.</p> | 
|
     * | 
|
     * @param implementation The implementation of this MBean. | 
|
     * @param mbeanInterface The Management Interface exported by this | 
|
     *        MBean's implementation. If <code>null</code>, then this | 
|
     *        object will use standard JMX design pattern to determine | 
|
     *        the management interface associated with the given | 
|
     *        implementation. | 
|
     * @param <T> Allows the compiler to check | 
|
     * that {@code implementation} does indeed implement the class | 
|
     * described by {@code mbeanInterface}.  The compiler can only | 
|
     * check this if {@code mbeanInterface} is a class literal such | 
|
     * as {@code MyMBean.class}. | 
|
     * | 
|
     * @exception IllegalArgumentException if the given | 
|
     *    <var>implementation</var> is null. | 
|
     * @exception NotCompliantMBeanException if the <var>mbeanInterface</var> | 
|
     *    does not follow JMX design patterns for Management Interfaces, or | 
|
     *    if the given <var>implementation</var> does not implement the | 
|
     *    specified interface. | 
|
**/  | 
|
public <T> StandardMBean(T implementation, Class<T> mbeanInterface)  | 
|
throws NotCompliantMBeanException {  | 
|
construct(implementation, mbeanInterface, false, false);  | 
|
}  | 
|
    /** | 
|
     * <p>Make a DynamicMBean out of <var>this</var>, using the specified | 
|
     * <var>mbeanInterface</var> class.</p> | 
|
     * | 
|
     * <p>Calls {@link #StandardMBean(java.lang.Object, java.lang.Class) | 
|
     *       this(this,mbeanInterface)}. | 
|
     * This constructor is reserved to subclasses.</p> | 
|
     * | 
|
     * @param mbeanInterface The Management Interface exported by this | 
|
     *        MBean. | 
|
     * | 
|
     * @exception NotCompliantMBeanException if the <var>mbeanInterface</var> | 
|
     *    does not follow JMX design patterns for Management Interfaces, or | 
|
     *    if <var>this</var> does not implement the specified interface. | 
|
**/  | 
|
protected StandardMBean(Class<?> mbeanInterface)  | 
|
throws NotCompliantMBeanException {  | 
|
construct(null, mbeanInterface, true, false);  | 
|
}  | 
|
    /** | 
|
     * <p>Make a DynamicMBean out of the object | 
|
     * <var>implementation</var>, using the specified | 
|
     * <var>mbeanInterface</var> 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.</p> | 
|
     * | 
|
     * @param implementation The implementation of this MBean. | 
|
     * @param mbeanInterface The Management Interface exported by this | 
|
     *        MBean's implementation. If <code>null</code>, 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 <T> Allows the compiler to check | 
|
     * that {@code implementation} does indeed implement the class | 
|
     * described by {@code mbeanInterface}.  The compiler can only | 
|
     * check this if {@code mbeanInterface} is a class literal such | 
|
     * as {@code MyMBean.class}. | 
|
     * | 
|
     * @exception IllegalArgumentException if the given | 
|
     *    <var>implementation</var> is null, or if the <var>mbeanInterface</var> | 
|
     *    does not follow JMX design patterns for Management Interfaces, or | 
|
     *    if the given <var>implementation</var> does not implement the | 
|
     *    specified interface. | 
|
     * | 
|
     * @since 1.6 | 
|
**/  | 
|
public <T> StandardMBean(T implementation, Class<T> mbeanInterface,  | 
|
                             boolean isMXBean) { | 
|
        try { | 
|
construct(implementation, mbeanInterface, false, isMXBean);  | 
|
} catch (NotCompliantMBeanException e) {  | 
|
throw new IllegalArgumentException(e);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * <p>Make a DynamicMBean out of <var>this</var>, using the specified | 
|
     * <var>mbeanInterface</var> 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.</p> | 
|
     * | 
|
     * <p>Calls {@link #StandardMBean(java.lang.Object, java.lang.Class, boolean) | 
|
     *       this(this, mbeanInterface, isMXBean)}. | 
|
     * This constructor is reserved to subclasses.</p> | 
|
     * | 
|
     * @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 <var>mbeanInterface</var> | 
|
     *    does not follow JMX design patterns for Management Interfaces, or | 
|
     *    if <var>this</var> 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);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * <p>Replace the implementation object wrapped in this object.</p> | 
|
     * | 
|
     * @param implementation The new implementation of this Standard MBean | 
|
     * (or MXBean). The <code>implementation</code> object must implement | 
|
     * the Standard MBean (or MXBean) interface that was supplied when this | 
|
     * <code>StandardMBean</code> was constructed. | 
|
     * | 
|
     * @exception IllegalArgumentException if the given | 
|
     * <var>implementation</var> is null. | 
|
     * | 
|
     * @exception NotCompliantMBeanException if the given | 
|
     * <var>implementation</var> 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.<Class<Object>>cast(getMBeanInterface()));  | 
|
        } else { | 
|
this.mbean = new StandardMBeanSupport(implementation,  | 
|
Util.<Class<Object>>cast(getMBeanInterface()));  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Get the implementation of this Standard MBean (or MXBean). | 
|
     * @return The implementation of this Standard MBean (or MXBean). | 
|
     * | 
|
     * @see #setImplementation | 
|
**/  | 
|
public Object getImplementation() {  | 
|
return mbean.getResource();  | 
|
}  | 
|
    /** | 
|
     * Get the Management Interface of this Standard MBean (or MXBean). | 
|
     * @return The management interface of this Standard MBean (or MXBean). | 
|
**/  | 
|
public final Class<?> getMBeanInterface() {  | 
|
return mbean.getMBeanInterface();  | 
|
}  | 
|
    /** | 
|
     * Get the class of the implementation of this Standard MBean (or MXBean). | 
|
     * @return The class of the implementation of this Standard MBean (or MXBean). | 
|
**/  | 
|
public Class<?> getImplementationClass() {  | 
|
return mbean.getResource().getClass();  | 
|
}  | 
|
// ------------------------------------------------------------------  | 
|
// From the DynamicMBean interface.  | 
|
    // ------------------------------------------------------------------ | 
|
public Object getAttribute(String attribute)  | 
|
throws AttributeNotFoundException,  | 
|
MBeanException,  | 
|
ReflectionException {  | 
|
return mbean.getAttribute(attribute);  | 
|
}  | 
|
// ------------------------------------------------------------------  | 
|
// From the DynamicMBean interface.  | 
|
    // ------------------------------------------------------------------ | 
|
public void setAttribute(Attribute attribute)  | 
|
throws AttributeNotFoundException,  | 
|
InvalidAttributeValueException,  | 
|
MBeanException,  | 
|
ReflectionException {  | 
|
mbean.setAttribute(attribute);  | 
|
}  | 
|
// ------------------------------------------------------------------  | 
|
// From the DynamicMBean interface.  | 
|
    // ------------------------------------------------------------------ | 
|
public AttributeList getAttributes(String[] attributes) {  | 
|
return mbean.getAttributes(attributes);  | 
|
}  | 
|
// ------------------------------------------------------------------  | 
|
// From the DynamicMBean interface.  | 
|
    // ------------------------------------------------------------------ | 
|
public AttributeList setAttributes(AttributeList attributes) {  | 
|
return mbean.setAttributes(attributes);  | 
|
}  | 
|
// ------------------------------------------------------------------  | 
|
// From the DynamicMBean interface.  | 
|
    // ------------------------------------------------------------------ | 
|
public Object invoke(String actionName, Object params[], String signature[])  | 
|
throws MBeanException, ReflectionException {  | 
|
return mbean.invoke(actionName, params, signature);  | 
|
}  | 
|
    /** | 
|
     * Get the {@link MBeanInfo} for this MBean. | 
|
     * <p> | 
|
     * This method implements | 
|
     * {@link javax.management.DynamicMBean#getMBeanInfo() | 
|
     *   DynamicMBean.getMBeanInfo()}. | 
|
     * <p> | 
|
     * 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.<br> | 
|
     * Otherwise, this method builds a default MBeanInfo for this MBean, | 
|
     * using the Management Interface specified for this MBean. | 
|
     * <p> | 
|
     * While building the MBeanInfo, this method calls the customization | 
|
     * hooks that make it possible for subclasses to supply their custom | 
|
     * descriptions, parameter names, etc...<br> | 
|
     * 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. | 
|
     * <br> | 
|
     * 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. | 
|
     * <br> | 
|
     * 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();  | 
|
}  | 
|
    /** | 
|
     * <p>Customization hook: | 
|
     * Get the description that will be used in the MBeanFeatureInfo | 
|
     * returned by this MBean.</p> | 
|
     * | 
|
     * <p>Subclasses may redefine this method in order to supply | 
|
     * their custom description.  The default implementation returns | 
|
     * {@link MBeanFeatureInfo#getDescription() | 
|
     * info.getDescription()}.</p> | 
|
     * | 
|
     * <p>This method is called by | 
|
     *      {@link #getDescription(MBeanAttributeInfo)}, | 
|
     *      {@link #getDescription(MBeanOperationInfo)}, | 
|
     *      {@link #getDescription(MBeanConstructorInfo)}.</p> | 
|
     * | 
|
     * @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. | 
|
     * | 
|
     * <p>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. | 
|
     * <br> | 
|
     * 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  <var>sequence</var> | 
|
     * MBeanParameterInfo of the MBeanConstructorInfo returned by this MBean. | 
|
     * <br> | 
|
     * 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 <var>sequence</var> | 
|
     * MBeanParameterInfo of the MBeanConstructorInfo returned by this MBean. | 
|
     * <br> | 
|
     * 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. | 
|
     * <br> | 
|
     * 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 <var>impact</var> flag of the operation that will be used in | 
|
     * the MBeanOperationInfo returned by this MBean. | 
|
     * <br> | 
|
     * 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 <var>sequence</var> | 
|
     * MBeanParameterInfo of the MBeanOperationInfo returned by this MBean. | 
|
     * <br> | 
|
     * 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  <var>sequence</var> | 
|
     * MBeanParameterInfo of the MBeanOperationInfo returned by this MBean. | 
|
     * <br> | 
|
     * 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. | 
|
     * <br> | 
|
     * By default, this method returns <code>null</code> if the wrapped | 
|
     * implementation is not <var>this</var>. 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 <code>MBeanServer.createMBean(...)</code>.<br> | 
|
     * Otherwise, if the wrapped implementation is <var>this</var>, | 
|
     * <var>ctors</var> is returned. | 
|
     * <br> | 
|
     * 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 <code>null</code> is | 
|
     *        passed, the wrapped implementation is ignored and | 
|
     *        <var>ctors</var> 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. | 
|
     * <br> | 
|
     * 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;  | 
|
}  | 
|
    /** | 
|
     * <p>Get the Descriptor that will be used in the MBeanInfo | 
|
     * returned by this MBean.</p> | 
|
     * | 
|
     * <p>Subclasses may redefine this method in order to supply | 
|
     * their custom descriptor.</p> | 
|
     * | 
|
     * <p>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.</p> | 
|
     * | 
|
     * @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();  | 
|
Map<String,Object> fields = new HashMap<String,Object>();  | 
|
for (String fieldName : d.getFieldNames()) {  | 
|
                if (fieldName.equals("immutableInfo")) { | 
|
// Replace immutableInfo as the underlying MBean/MXBean  | 
|
// could already implement NotificationBroadcaster and  | 
|
                    // return immutableInfo=true in its MBeanInfo. | 
|
fields.put(fieldName, Boolean.toString(immutableInfo));  | 
|
                } else { | 
|
fields.put(fieldName, d.getFieldValue(fieldName));  | 
|
}  | 
|
}  | 
|
desc = new ImmutableDescriptor(fields);  | 
|
}  | 
|
return desc;  | 
|
}  | 
|
    /** | 
|
     * Customization hook: | 
|
     * Return the MBeanInfo cached for this object. | 
|
     * | 
|
     * <p>Subclasses 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. | 
|
     * | 
|
     * <p>Subclasses may redefine this method in order to implement | 
|
     * their own caching policy.  The default implementation stores | 
|
     * <code>info</code> in this instance.  A subclass can define | 
|
     * other policies, such as not saving <code>info</code> (so it is | 
|
     * reconstructed every time {@link #getMBeanInfo()} is called) or | 
|
     * sharing a unique {@link MBeanInfo} object when several | 
|
     * <code>StandardMBean</code> instances have equal {@link | 
|
     * MBeanInfo} values. | 
|
     * | 
|
     * @param info the new <code>MBeanInfo</code> 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 <T> boolean identicalArrays(T[] a, T[] b) {  | 
|
if (a == b)  | 
|
return true;  | 
|
if (a == null || b == null || a.length != b.length)  | 
|
return false;  | 
|
for (int i = 0; i < a.length; i++) {  | 
|
if (a[i] != b[i])  | 
|
return false;  | 
|
}  | 
|
return true;  | 
|
}  | 
|
private static <T> boolean equal(T a, T b) {  | 
|
if (a == b)  | 
|
return true;  | 
|
if (a == null || b == null)  | 
|
return false;  | 
|
return a.equals(b);  | 
|
}  | 
|
private static MBeanParameterInfo  | 
|
customize(MBeanParameterInfo pi,  | 
|
String name,  | 
|
String description) {  | 
|
if (equal(name, pi.getName()) &&  | 
|
equal(description, pi.getDescription()))  | 
|
return pi;  | 
|
else if (pi instanceof OpenMBeanParameterInfo) {  | 
|
OpenMBeanParameterInfo opi = (OpenMBeanParameterInfo) pi;  | 
|
return new OpenMBeanParameterInfoSupport(name,  | 
|
description,  | 
|
opi.getOpenType(),  | 
|
pi.getDescriptor());  | 
|
        } else { | 
|
return new MBeanParameterInfo(name,  | 
|
pi.getType(),  | 
|
description,  | 
|
pi.getDescriptor());  | 
|
}  | 
|
}  | 
|
private static MBeanConstructorInfo  | 
|
customize(MBeanConstructorInfo ci,  | 
|
String description,  | 
|
MBeanParameterInfo[] signature) {  | 
|
if (equal(description, ci.getDescription()) &&  | 
|
identicalArrays(signature, ci.getSignature()))  | 
|
return ci;  | 
|
if (ci instanceof OpenMBeanConstructorInfo) {  | 
|
OpenMBeanParameterInfo[] oparams =  | 
|
paramsToOpenParams(signature);  | 
|
return new OpenMBeanConstructorInfoSupport(ci.getName(),  | 
|
description,  | 
|
oparams,  | 
|
ci.getDescriptor());  | 
|
        } else { | 
|
return new MBeanConstructorInfo(ci.getName(),  | 
|
description,  | 
|
signature,  | 
|
ci.getDescriptor());  | 
|
}  | 
|
}  | 
|
private static MBeanOperationInfo  | 
|
customize(MBeanOperationInfo oi,  | 
|
String description,  | 
|
MBeanParameterInfo[] signature,  | 
|
                      int impact) { | 
|
if (equal(description, oi.getDescription()) &&  | 
|
identicalArrays(signature, oi.getSignature()) &&  | 
|
impact == oi.getImpact())  | 
|
return oi;  | 
|
if (oi instanceof OpenMBeanOperationInfo) {  | 
|
OpenMBeanOperationInfo ooi = (OpenMBeanOperationInfo) oi;  | 
|
OpenMBeanParameterInfo[] oparams =  | 
|
paramsToOpenParams(signature);  | 
|
return new OpenMBeanOperationInfoSupport(oi.getName(),  | 
|
description,  | 
|
oparams,  | 
|
ooi.getReturnOpenType(),  | 
|
impact,  | 
|
oi.getDescriptor());  | 
|
        } else { | 
|
return new MBeanOperationInfo(oi.getName(),  | 
|
description,  | 
|
signature,  | 
|
oi.getReturnType(),  | 
|
impact,  | 
|
oi.getDescriptor());  | 
|
}  | 
|
}  | 
|
private static MBeanAttributeInfo  | 
|
customize(MBeanAttributeInfo ai,  | 
|
String description) {  | 
|
if (equal(description, ai.getDescription()))  | 
|
return ai;  | 
|
if (ai instanceof OpenMBeanAttributeInfo) {  | 
|
OpenMBeanAttributeInfo oai = (OpenMBeanAttributeInfo) ai;  | 
|
return new OpenMBeanAttributeInfoSupport(ai.getName(),  | 
|
description,  | 
|
oai.getOpenType(),  | 
|
ai.isReadable(),  | 
|
ai.isWritable(),  | 
|
ai.isIs(),  | 
|
ai.getDescriptor());  | 
|
        } else { | 
|
return new MBeanAttributeInfo(ai.getName(),  | 
|
ai.getType(),  | 
|
description,  | 
|
ai.isReadable(),  | 
|
ai.isWritable(),  | 
|
ai.isIs(),  | 
|
ai.getDescriptor());  | 
|
}  | 
|
}  | 
|
private static OpenMBeanParameterInfo[]  | 
|
paramsToOpenParams(MBeanParameterInfo[] params) {  | 
|
if (params instanceof OpenMBeanParameterInfo[])  | 
|
return (OpenMBeanParameterInfo[]) params;  | 
|
OpenMBeanParameterInfo[] oparams =  | 
|
new OpenMBeanParameterInfoSupport[params.length];  | 
|
System.arraycopy(params, 0, oparams, 0, params.length);  | 
|
return oparams;  | 
|
}  | 
|
// ------------------------------------------------------------------  | 
|
// Build the custom MBeanConstructorInfo[]  | 
|
    // ------------------------------------------------------------------ | 
|
private MBeanConstructorInfo[]  | 
|
getConstructors(MBeanInfo info, Object impl) {  | 
|
final MBeanConstructorInfo[] ctors =  | 
|
getConstructors(info.getConstructors(), impl);  | 
|
if (ctors == null)  | 
|
return null;  | 
|
final int ctorlen = ctors.length;  | 
|
final MBeanConstructorInfo[] nctors = new MBeanConstructorInfo[ctorlen];  | 
|
for (int i=0; i<ctorlen; i++) {  | 
|
final MBeanConstructorInfo c = ctors[i];  | 
|
final MBeanParameterInfo[] params = c.getSignature();  | 
|
final MBeanParameterInfo[] nps;  | 
|
if (params != null) {  | 
|
final int plen = params.length;  | 
|
nps = new MBeanParameterInfo[plen];  | 
|
for (int ii=0;ii<plen;ii++) {  | 
|
MBeanParameterInfo p = params[ii];  | 
|
nps[ii] = customize(p,  | 
|
getParameterName(c,p,ii),  | 
|
getDescription(c,p,ii));  | 
|
}  | 
|
            } else { | 
|
nps = null;  | 
|
}  | 
|
nctors[i] =  | 
|
customize(c, getDescription(c), nps);  | 
|
}  | 
|
return nctors;  | 
|
}  | 
|
// ------------------------------------------------------------------  | 
|
// Build the custom MBeanOperationInfo[]  | 
|
    // ------------------------------------------------------------------ | 
|
private MBeanOperationInfo[] getOperations(MBeanInfo info) {  | 
|
final MBeanOperationInfo[] ops = info.getOperations();  | 
|
if (ops == null)  | 
|
return null;  | 
|
final int oplen = ops.length;  | 
|
final MBeanOperationInfo[] nops = new MBeanOperationInfo[oplen];  | 
|
for (int i=0; i<oplen; i++) {  | 
|
final MBeanOperationInfo o = ops[i];  | 
|
final MBeanParameterInfo[] params = o.getSignature();  | 
|
final MBeanParameterInfo[] nps;  | 
|
if (params != null) {  | 
|
final int plen = params.length;  | 
|
nps = new MBeanParameterInfo[plen];  | 
|
for (int ii=0;ii<plen;ii++) {  | 
|
MBeanParameterInfo p = params[ii];  | 
|
nps[ii] = customize(p,  | 
|
getParameterName(o,p,ii),  | 
|
getDescription(o,p,ii));  | 
|
}  | 
|
            } else { | 
|
nps = null;  | 
|
}  | 
|
nops[i] = customize(o, getDescription(o), nps, getImpact(o));  | 
|
}  | 
|
return nops;  | 
|
}  | 
|
// ------------------------------------------------------------------  | 
|
// Build the custom MBeanAttributeInfo[]  | 
|
    // ------------------------------------------------------------------ | 
|
private MBeanAttributeInfo[] getAttributes(MBeanInfo info) {  | 
|
final MBeanAttributeInfo[] atts = info.getAttributes();  | 
|
if (atts == null)  | 
|
            return null; // should not happen | 
|
final MBeanAttributeInfo[] natts;  | 
|
final int attlen = atts.length;  | 
|
natts = new MBeanAttributeInfo[attlen];  | 
|
for (int i=0; i<attlen; i++) {  | 
|
final MBeanAttributeInfo a = atts[i];  | 
|
natts[i] = customize(a, getDescription(a));  | 
|
}  | 
|
return natts;  | 
|
}  | 
|
    /** | 
|
     * <p>Allows the MBean to perform any operations it needs before | 
|
     * being registered in the MBean server.  If the name of the MBean | 
|
     * is not specified, the MBean can provide a name for its | 
|
     * registration.  If any exception is raised, the MBean will not be | 
|
     * registered in the MBean server.</p> | 
|
     * | 
|
     * <p>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.</p> | 
|
     * | 
|
     * <p>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.</p> | 
|
     * | 
|
     * @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 the <code>createMBean</code> or | 
|
     * <code>registerMBean</code> 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 <code>name</code> | 
|
     * 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;  | 
|
}  | 
|
    /** | 
|
     * <p>Allows the MBean to perform any operations needed after having been | 
|
     * registered in the MBean server or after the registration has failed.</p> | 
|
     * | 
|
     * <p>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.</p> | 
|
     * | 
|
     * <p>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.</p> | 
|
     * | 
|
     * @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();  | 
|
}  | 
|
    /** | 
|
     * <p>Allows the MBean to perform any operations it needs before | 
|
     * being unregistered by the MBean server.</p> | 
|
     * | 
|
     * <p>The default implementation of this method does nothing.</p> | 
|
     * | 
|
     * <p>It is good practice for a subclass that overrides this method | 
|
     * to call the overridden method via {@code super.preDeregister(...)}.</p> | 
|
     * | 
|
     * @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 {  | 
|
}  | 
|
    /** | 
|
     * <p>Allows the MBean to perform any operations needed after having been | 
|
     * unregistered in the MBean server.</p> | 
|
     * | 
|
     * <p>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.</p> | 
|
     * | 
|
     * <p>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.</p> | 
|
     * | 
|
     * @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<Class<?>, Boolean> mbeanInfoSafeMap =  | 
|
new WeakHashMap<Class<?>, Boolean>();  | 
|
    /** | 
|
     * Return true if {@code subclass} is known to preserve the immutability | 
|
     * of the {@code MBeanInfo}. The {@code subclass} is considered to have | 
|
     * an immutable {@code MBeanInfo} if it does not override any of the | 
|
     * getMBeanInfo, getCachedMBeanInfo, cacheMBeanInfo and getNotificationInfo | 
|
     * methods. | 
|
*/  | 
|
static boolean immutableInfo(Class<? extends StandardMBean> subclass) {  | 
|
if (subclass == StandardMBean.class ||  | 
|
subclass == StandardEmitterMBean.class)  | 
|
return true;  | 
|
synchronized (mbeanInfoSafeMap) {  | 
|
Boolean safe = mbeanInfoSafeMap.get(subclass);  | 
|
if (safe == null) {  | 
|
                try { | 
|
MBeanInfoSafeAction action =  | 
|
new MBeanInfoSafeAction(subclass);  | 
|
safe = AccessController.doPrivileged(action);  | 
|
} catch (Exception e) { // e.g. SecurityException  | 
|
                    /* We don't know, so we assume it isn't.  */ | 
|
safe = false;  | 
|
}  | 
|
mbeanInfoSafeMap.put(subclass, safe);  | 
|
}  | 
|
return safe;  | 
|
}  | 
|
}  | 
|
static boolean overrides(Class<?> subclass, Class<?> superclass,  | 
|
String name, Class<?>... params) {  | 
|
for (Class<?> c = subclass; c != superclass; c = c.getSuperclass()) {  | 
|
            try { | 
|
c.getDeclaredMethod(name, params);  | 
|
return true;  | 
|
} catch (NoSuchMethodException e) {  | 
|
// OK: this class doesn't override it  | 
|
}  | 
|
}  | 
|
return false;  | 
|
}  | 
|
private static class MBeanInfoSafeAction  | 
|
implements PrivilegedAction<Boolean> {  | 
|
private final Class<?> subclass;  | 
|
MBeanInfoSafeAction(Class<?> subclass) {  | 
|
this.subclass = subclass;  | 
|
}  | 
|
public Boolean run() {  | 
|
// Check for "void cacheMBeanInfo(MBeanInfo)" method.  | 
|
            // | 
|
if (overrides(subclass, StandardMBean.class,  | 
|
"cacheMBeanInfo", MBeanInfo.class))  | 
|
return false;  | 
|
// Check for "MBeanInfo getCachedMBeanInfo()" method.  | 
|
            // | 
|
if (overrides(subclass, StandardMBean.class,  | 
|
"getCachedMBeanInfo", (Class<?>[]) null))  | 
|
return false;  | 
|
// Check for "MBeanInfo getMBeanInfo()" method.  | 
|
            // | 
|
if (overrides(subclass, StandardMBean.class,  | 
|
"getMBeanInfo", (Class<?>[]) null))  | 
|
return false;  | 
|
// Check for "MBeanNotificationInfo[] getNotificationInfo()"  | 
|
// method.  | 
|
//  | 
|
// This method is taken into account for the MBeanInfo  | 
|
// immutability checks if and only if the given subclass is  | 
|
// StandardEmitterMBean itself or can be assigned to  | 
|
// StandardEmitterMBean.  | 
|
            // | 
|
if (StandardEmitterMBean.class.isAssignableFrom(subclass))  | 
|
if (overrides(subclass, StandardEmitterMBean.class,  | 
|
"getNotificationInfo", (Class<?>[]) null))  | 
|
return false;  | 
|
return true;  | 
|
}  | 
|
}  | 
|
}  |