jdk/src/share/classes/javax/management/namespace/MBeanServerSupport.java
author dfuchs
Thu, 04 Sep 2008 14:46:36 +0200
changeset 1156 bbc2d15aaf7a
child 1225 6ef6227d36eb
permissions -rw-r--r--
5072476: RFE: support cascaded (federated) MBean Servers 6299231: Add support for named MBean Servers Summary: New javax.management.namespace package. Reviewed-by: emcmanus

/*
 * Copyright 2008 Sun Microsystems, Inc.  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.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
package javax.management.namespace;

import com.sun.jmx.defaults.JmxProperties;
import com.sun.jmx.mbeanserver.Util;
import java.io.ObjectInputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.DynamicWrapperMBean;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.JMRuntimeException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.OperationsException;
import javax.management.QueryEval;
import javax.management.QueryExp;
import javax.management.ReflectionException;
import javax.management.RuntimeOperationsException;
import javax.management.loading.ClassLoaderRepository;

/**
 * <p>Base class for custom implementations of the {@link MBeanServer}
 * interface. The commonest use of this class is as the {@linkplain
 * JMXNamespace#getSourceServer() source server} for a {@link
 * JMXNamespace}, although this class can be used anywhere an {@code
 * MBeanServer} instance is required. Note that the usual ways to
 * obtain an {@code MBeanServer} instance are either to use {@link
 * java.lang.management.ManagementFactory#getPlatformMBeanServer()
 * ManagementFactory.getPlatformMBeanServer()} or to use the {@code
 * newMBeanServer} or {@code createMBeanServer} methods from {@link
 * javax.management.MBeanServerFactory MBeanServerFactory}. {@code
 * MBeanServerSupport} is for certain cases where those are not
 * appropriate.</p>
 *
 * <p>There are two main use cases for this class: <a
 * href="#special-purpose">special-purpose MBeanServer implementations</a>,
 * and <a href="#virtual">namespaces containing Virtual MBeans</a>. The next
 * sections explain these use cases.</p>
 *
 * <p>In the simplest case, a subclass needs to implement only two methods:</p>
 *
 * <ul>
 *     <li>
 *         {@link #getNames getNames} which returns the name of
 *         all MBeans handled by this {@code MBeanServer}.
 *     </li>
 *     <li>
 *         {@link #getDynamicMBeanFor getDynamicMBeanFor} which returns a
 *         {@link DynamicMBean} that can be used to invoke operations and
 *         obtain meta data (MBeanInfo) on a given MBean.
 *     </li>
 * </ul>
 *
 * <p>Subclasses can create such {@link DynamicMBean} MBeans on the fly - for
 * instance, using the class {@link javax.management.StandardMBean}, just for
 * the duration of an MBeanServer method call.</p>
 *
 * <h4 id="special-purpose">Special-purpose MBeanServer implementations</h4>
 *
 * <p>In some cases
 * the general-purpose {@code MBeanServer} that you get from
 * {@link javax.management.MBeanServerFactory MBeanServerFactory} is not
 * appropriate.  You might need different security checks, or you might
 * want a mock {@code MBeanServer} suitable for use in tests, or you might
 * want a simplified and optimized {@code MBeanServer} for a special purpose.</p>
 *
 * <p>As an example of a special-purpose {@code MBeanServer}, the class {@link
 * javax.management.QueryNotificationFilter QueryNotificationFilter} constructs
 * an {@code MBeanServer} instance every time it filters a notification,
 * with just one MBean that represents the notification. Although it could
 * use {@code MBeanServerFactory.newMBeanServer}, a special-purpose {@code
 * MBeanServer} will be quicker to create, use less memory, and have simpler
 * methods that execute faster.</p>
 *
 * <p>Here is an example of a special-purpose {@code MBeanServer}
 * implementation that contains exactly one MBean, which is specified at the
 * time of creation.</p>
 *
 * <pre>
 * public class SingletonMBeanServer extends MBeanServerSupport {
 *     private final ObjectName objectName;
 *     private final DynamicMBean mbean;
 *
 *     public SingletonMBeanServer(ObjectName objectName, DynamicMBean mbean) {
 *         this.objectName = objectName;
 *         this.mbean = mbean;
 *     }
 *
 *     &#64;Override
 *     protected {@code Set<ObjectName>} {@link #getNames getNames}() {
 *         return Collections.singleton(objectName);
 *     }
 *
 *     &#64;Override
 *     public DynamicMBean {@link #getDynamicMBeanFor
 *                                getDynamicMBeanFor}(ObjectName name)
 *             throws InstanceNotFoundException {
 *         if (objectName.equals(name))
 *             return mbean;
 *         else
 *             throw new InstanceNotFoundException(name);
 *     }
 * }
 * </pre>
 *
 * <p>Using this class, you could make an {@code MBeanServer} that contains
 * a {@link javax.management.timer.Timer Timer} MBean like this:</p>
 *
 * <pre>
 *     Timer timer = new Timer();
 *     DynamicMBean mbean = new {@link javax.management.StandardMBean
 *                                     StandardMBean}(timer, TimerMBean.class);
 *     ObjectName name = new ObjectName("com.example:type=Timer");
 *     MBeanServer timerMBS = new SingletonMBeanServer(name, mbean);
 * </pre>
 *
 * <p>When {@code getDynamicMBeanFor} always returns the same object for the
 * same name, as here, notifications work in the expected way: if the object
 * is a {@link NotificationEmitter} then listeners can be added using
 * {@link MBeanServer#addNotificationListener(ObjectName, NotificationListener,
 * NotificationFilter, Object) MBeanServer.addNotificationListener}.  If
 * {@code getDynamicMBeanFor} does not always return the same object for the
 * same name, more work is needed to make notifications work, as described
 * <a href="#notifs">below</a>.</p>
 *
 * <h4 id="virtual">Namespaces containing Virtual MBeans</h4>
 *
 * <p>Virtual MBeans are MBeans that do not exist as Java objects,
 * except transiently while they are being accessed.  This is useful when
 * there might be very many of them, or when keeping track of their creation
 * and deletion might be expensive or hard.  For example, you might have one
 * MBean per system process.  With an ordinary {@code MBeanServer}, you would
 * have to list the system processes in order to create an MBean object for
 * each one, and you would have to track the arrival and departure of system
 * processes in order to create or delete the corresponding MBeans.  With
 * Virtual MBeans, you only need the MBean for a given process at the exact
 * point where it is referenced with a call such as
 * {@link MBeanServer#getAttribute MBeanServer.getAttribute}.</p>
 *
 * <p>Here is an example of an {@code MBeanServer} implementation that has
 * one MBean for every system property.  The system property {@code "java.home"}
 * is represented by the MBean called {@code
 * com.example:type=Property,name="java.home"}, with an attribute called
 * {@code Value} that is the value of the property.</p>
 *
 * <pre>
 * public interface PropertyMBean {
 *     public String getValue();
 * }
 *
 * <a name="PropsMBS"></a>public class PropsMBS extends MBeanServerSupport {
 *     private static ObjectName newObjectName(String name) {
 *         try {
 *             return new ObjectName(name);
 *         } catch (MalformedObjectNameException e) {
 *             throw new AssertionError(e);
 *         }
 *     }
 *
 *     public static class PropertyImpl implements PropertyMBean {
 *         private final String name;
 *
 *         public PropertyImpl(String name) {
 *             this.name = name;
 *         }
 *
 *         public String getValue() {
 *             return System.getProperty(name);
 *         }
 *     }
 *
 *     &#64;Override
 *     public DynamicMBean {@link #getDynamicMBeanFor
 *                                getDynamicMBeanFor}(ObjectName name)
 *             throws InstanceNotFoundException {
 *
 *         // Check that the name is a legal one for a Property MBean
 *         ObjectName namePattern = newObjectName(
 *                     "com.example:type=Property,name=\"*\"");
 *         if (!namePattern.apply(name))
 *             throw new InstanceNotFoundException(name);
 *
 *         // Extract the name of the property that the MBean corresponds to
 *         String propName = ObjectName.unquote(name.getKeyProperty("name"));
 *         if (System.getProperty(propName) == null)
 *             throw new InstanceNotFoundException(name);
 *
 *         // Construct and return a transient MBean object
 *         PropertyMBean propMBean = new PropertyImpl(propName);
 *         return new StandardMBean(propMBean, PropertyMBean.class, false);
 *     }
 *
 *     &#64;Override
 *     protected {@code Set<ObjectName>} {@link #getNames getNames}() {
 *         {@code Set<ObjectName> names = new TreeSet<ObjectName>();}
 *         Properties props = System.getProperties();
 *         for (String propName : props.stringPropertyNames()) {
 *             ObjectName objectName = newObjectName(
 *                     "com.example:type=Property,name=" +
 *                     ObjectName.quote(propName));
 *             names.add(objectName);
 *         }
 *         return names;
 *     }
 * }
 * </pre>
 *
 * <p id="virtual-notif-example">Because the {@code getDynamicMBeanFor} method
 * returns a different object every time it is called, the default handling
 * of notifications will not work, as explained <a href="#notifs">below</a>.
 * In this case it does not matter, because the object returned by {@code
 * getDynamicMBeanFor} is not a {@code NotificationEmitter}, so {@link
 * MBeanServer#addNotificationListener(ObjectName, NotificationListener,
 * NotificationFilter, Object) MBeanServer.addNotificationListener} will
 * always fail. But if we wanted to extend {@code PropsMBS} so that the MBean
 * for property {@code "foo"} emitted a notification every time that property
 * changed, we would need to do it as shown below. (Because there is no API to
 * be informed when a property changes, this code assumes that some other code
 * calls the {@code propertyChanged} method every time a property changes.)</p>
 *
 * <pre>
 * public class PropsMBS {
 *     ...as <a href="#PropsMBS">above</a>...
 *
 *     private final {@link VirtualEventManager} vem = new VirtualEventManager();
 *
 *     &#64;Override
 *     public NotificationEmitter {@link #getNotificationEmitterFor
 *                                       getNotificationEmitterFor}(
 *             ObjectName name) throws InstanceNotFoundException {
 *         getDynamicMBeanFor(name);  // check that the name is valid
 *         return vem.{@link VirtualEventManager#getNotificationEmitterFor
 *                           getNotificationEmitterFor}(name);
 *     }
 *
 *     public void propertyChanged(String name, String newValue) {
 *         ObjectName objectName = newObjectName(
 *                 "com.example:type=Property,name=" + ObjectName.quote(name));
 *         Notification n = new Notification(
 *                 "com.example.property.changed", objectName, 0L,
 *                 "Property " + name + " changed");
 *         n.setUserData(newValue);
 *         vem.{@link VirtualEventManager#publish publish}(objectName, n);
 *     }
 * }
 * </pre>
 *
 * <h4 id="creation">MBean creation and deletion</h4>
 *
 * <p>MBean creation through {@code MBeanServer.createMBean} is disabled
 * by default. Subclasses which need to support MBean creation
 * through {@code createMBean} need to implement a single method {@link
 * #createMBean(String, ObjectName, ObjectName, Object[], String[],
 * boolean)}.</p>
 *
 * <p>Similarly MBean registration and unregistration through {@code
 * registerMBean} and {@code unregisterMBean} are disabled by default.
 * Subclasses which need to support MBean registration and
 * unregistration will need to implement {@link #registerMBean registerMBean}
 * and {@link #unregisterMBean unregisterMBean}.</p>
 *
 * <h4 id="notifs">Notifications</h4>
 *
 * <p>By default {@link MBeanServer#addNotificationListener(ObjectName,
 * NotificationListener, NotificationFilter, Object) addNotificationListener}
 * is accepted for an MBean <em>{@code name}</em> if {@link #getDynamicMBeanFor
 * getDynamicMBeanFor}<code>(<em>name</em>)</code> returns an object that is a
 * {@link NotificationEmitter}.  That is appropriate if
 * {@code getDynamicMBeanFor}<code>(<em>name</em>)</code> always returns the
 * same object for the same <em>{@code name}</em>.  But with
 * Virtual MBeans, every call to {@code getDynamicMBeanFor} returns a new object,
 * which is discarded as soon as the MBean request has finished.
 * So a listener added to that object would be immediately forgotten.</p>
 *
 * <p>The simplest way for a subclass that defines Virtual MBeans
 * to support notifications is to create a private {@link VirtualEventManager}
 * and override the method {@link
 * #getNotificationEmitterFor getNotificationEmitterFor} as follows:</p>
 *
 * <pre>
 *     private final VirtualEventManager vem = new VirtualEventManager();
 *
 *     &#64;Override
 *     public NotificationEmitter getNotificationEmitterFor(
 *             ObjectName name) throws InstanceNotFoundException {
 *         // Check that the name is a valid Virtual MBean.
 *         // This is the easiest way to do that, but not always the
 *         // most efficient:
 *         getDynamicMBeanFor(name);
 *
 *         // Return an object that supports add/removeNotificationListener
 *         // through the VirtualEventManager.
 *         return vem.getNotificationEmitterFor(name);
 *     }
 * </pre>
 *
 * <p>A notification <em>{@code n}</em> can then be sent from the Virtual MBean
 * called <em>{@code name}</em> by calling {@link VirtualEventManager#publish
 * vem.publish}<code>(<em>name</em>, <em>n</em>)</code>.  See the example
 * <a href="#virtual-notif-example">above</a>.</p>
 *
 * @since 1.7
 */
public abstract class MBeanServerSupport implements MBeanServer {

    /**
     * A logger for this class.
     */
    private static final Logger LOG =
            JmxProperties.NAMESPACE_LOGGER;

    /**
     * <p>Make a new {@code MBeanServerSupport} instance.</p>
     */
    protected MBeanServerSupport() {
    }

    /**
     * <p>Returns a dynamically created handle that makes it possible to
     * access the named MBean for the duration of a method call.</p>
     *
     * <p>An easy way to create such a {@link DynamicMBean} handle is, for
     * instance, to create a temporary MXBean instance and to wrap it in
     * an instance of
     * {@link javax.management.StandardMBean}.
     * This handle should remain valid for the duration of the call
     * but can then be discarded.</p>
     * @param name the name of the MBean for which a request was received.
     * @return a {@link DynamicMBean} handle that can be used to invoke
     * operations on the named MBean.
     * @throws InstanceNotFoundException if no such MBean is supposed
     *         to exist.
     */
    public abstract DynamicMBean getDynamicMBeanFor(ObjectName name)
                        throws InstanceNotFoundException;

    /**
     * <p>Subclasses should implement this method to return
     * the names of all MBeans handled by this object instance.</p>
     *
     * <p>The object returned by getNames() should be safely {@linkplain
     * Set#iterator iterable} even in the presence of other threads that may
     * cause the set of names to change. Typically this means one of the
     * following:</p>
     *
     * <ul>
     * <li>the returned set of names is always the same; or
     * <li>the returned set of names is an object such as a {@link
     * java.util.concurrent.CopyOnWriteArraySet CopyOnWriteArraySet} that is
     * safely iterable even if the set is changed by other threads; or
     * <li>a new Set is constructed every time this method is called.
     * </ul>
     *
     * @return the names of all MBeans handled by this object.
     */
    protected abstract Set<ObjectName> getNames();

    /**
     * <p>List names matching the given pattern.
     * The default implementation of this method calls {@link #getNames()}
     * and returns the subset of those names matching {@code pattern}.</p>
     *
     * @param pattern an ObjectName pattern
     * @return the list of MBean names that match the given pattern.
     */
    protected Set<ObjectName> getMatchingNames(ObjectName pattern) {
        return Util.filterMatchingNames(pattern, getNames());
    }

    /**
     * <p>Returns a {@link NotificationEmitter} which can be used to
     * subscribe or unsubscribe for notifications with the named
     * mbean.</p>
     *
     * <p>The default implementation of this method calls {@link
     * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object
     * if it is a {@code NotificationEmitter}, otherwise null. See <a
     * href="#notifs">above</a> for further discussion of notification
     * handling.</p>
     *
     * @param name The name of the MBean whose notifications are being
     * subscribed, or unsuscribed.
     *
     * @return A {@link NotificationEmitter} that can be used to subscribe or
     * unsubscribe for notifications emitted by the named MBean, or {@code
     * null} if the MBean does not emit notifications and should not be
     * considered as a {@code NotificationEmitter}.
     *
     * @throws InstanceNotFoundException if {@code name} is not the name of
     * an MBean in this {@code MBeanServer}.
     */
    public NotificationEmitter getNotificationEmitterFor(ObjectName name)
            throws InstanceNotFoundException {
        DynamicMBean mbean = getDynamicMBeanFor(name);
        if (mbean instanceof NotificationEmitter)
            return (NotificationEmitter) mbean;
        else
            return null;
    }

    private NotificationEmitter getNonNullNotificationEmitterFor(
            ObjectName name)
            throws InstanceNotFoundException {
        NotificationEmitter emitter = getNotificationEmitterFor(name);
        if (emitter == null) {
            IllegalArgumentException iae = new IllegalArgumentException(
                    "Not a NotificationEmitter: " + name);
            throw new RuntimeOperationsException(iae);
        }
        return emitter;
    }

    /**
     * <p>Creates a new MBean in the MBean name space.
     * This operation is not supported in this base class implementation.</p>
     * The default implementation of this method always throws an {@link
     * UnsupportedOperationException}
     * wrapped in a {@link RuntimeOperationsException}.</p>
     *
     * <p>Subclasses may redefine this method to provide an implementation.
     * All the various flavors of {@code MBeanServer.createMBean} methods
     * will eventually call this method. A subclass that wishes to
     * support MBean creation through {@code createMBean} thus only
     * needs to provide an implementation for this one method.
     *
     * @param className The class name of the MBean to be instantiated.
     * @param name The object name of the MBean. May be null.
     * @param params An array containing the parameters of the
     * constructor to be invoked.
     * @param signature An array containing the signature of the
     * constructor to be invoked.
     * @param loaderName The object name of the class loader to be used.
     * @param useCLR This parameter is {@code true} when this method
     *        is called from one of the {@code MBeanServer.createMBean} methods
     *        whose signature does not include the {@code ObjectName} of an
     *        MBean class loader to use for loading the MBean class.
     *
     * @return An <CODE>ObjectInstance</CODE>, containing the
     * <CODE>ObjectName</CODE> and the Java class name of the newly
     * instantiated MBean.  If the contained <code>ObjectName</code>
     * is <code>n</code>, the contained Java class name is
     * <code>{@link javax.management.MBeanServer#getMBeanInfo
     * getMBeanInfo(n)}.getClassName()</code>.
     *
     * @exception ReflectionException Wraps a
     * <CODE>java.lang.ClassNotFoundException</CODE> or a
     * <CODE>java.lang.Exception</CODE> that occurred when trying to
     * invoke the MBean's constructor.
     * @exception InstanceAlreadyExistsException The MBean is already
     * under the control of the MBean server.
     * @exception MBeanRegistrationException The
     * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
     * interface) method of the MBean has thrown an exception. The
     * MBean will not be registered.
     * @exception MBeanException The constructor of the MBean has
     * thrown an exception
     * @exception NotCompliantMBeanException This class is not a JMX
     * compliant MBean
     * @exception InstanceNotFoundException The specified class loader
     * is not registered in the MBean server.
     * @exception RuntimeOperationsException Wraps either:
     * <ul>
     * <li>a <CODE>java.lang.IllegalArgumentException</CODE>: The className
     * passed in parameter is null, the <CODE>ObjectName</CODE> passed in
     * parameter contains a pattern or no <CODE>ObjectName</CODE> is specified
     * for the MBean; or</li>
     * <li>an {@code UnsupportedOperationException} if creating MBeans is not
     * supported by this {@code MBeanServer} implementation.
     * </ul>
     */
    public ObjectInstance createMBean(String className,
            ObjectName name, ObjectName loaderName, Object[] params,
            String[] signature, boolean useCLR)
            throws ReflectionException, InstanceAlreadyExistsException,
            MBeanRegistrationException, MBeanException,
            NotCompliantMBeanException, InstanceNotFoundException {
        throw newUnsupportedException("createMBean");
    }


    /**
     * <p>Attempts to determine whether the named MBean should be
     * considered as an instance of a given class.  The default implementation
     * of this method calls {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}
     * to get an MBean object.  Then its behaviour is the same as the standard
     * {@link MBeanServer#isInstanceOf MBeanServer.isInstanceOf} method.</p>
     *
     * {@inheritDoc}
     */
    public boolean isInstanceOf(ObjectName name, String className)
        throws InstanceNotFoundException {

        final DynamicMBean instance = nonNullMBeanFor(name);

        try {
            final String mbeanClassName = instance.getMBeanInfo().getClassName();

            if (mbeanClassName.equals(className))
                return true;

            final Object resource;
            final ClassLoader cl;
            if (instance instanceof DynamicWrapperMBean) {
                DynamicWrapperMBean d = (DynamicWrapperMBean) instance;
                resource = d.getWrappedObject();
                cl = d.getWrappedClassLoader();
            } else {
                resource = instance;
                cl = instance.getClass().getClassLoader();
            }

            final Class<?> classNameClass = Class.forName(className, false, cl);

            if (classNameClass.isInstance(resource))
                return true;

            if (classNameClass == NotificationBroadcaster.class ||
                    classNameClass == NotificationEmitter.class) {
                try {
                    getNotificationEmitterFor(name);
                    return true;
                } catch (Exception x) {
                    LOG.finest("MBean " + name +
                            " is not a notification emitter. Ignoring: "+x);
                    return false;
                }
            }

            final Class<?> resourceClass = Class.forName(mbeanClassName, false, cl);
            return classNameClass.isAssignableFrom(resourceClass);
        } catch (Exception x) {
            /* Could be SecurityException or ClassNotFoundException */
            LOG.logp(Level.FINEST,
                    MBeanServerSupport.class.getName(),
                    "isInstanceOf", "Exception calling isInstanceOf", x);
            return false;
        }
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method returns the string
     * "DefaultDomain".</p>
     */
    public String getDefaultDomain() {
        return "DefaultDomain";
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method returns
     * {@link #getNames()}.size().</p>
     */
    public Integer getMBeanCount() {
        return getNames().size();
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method first calls {@link #getNames
     * getNames()} to get a list of all MBean names,
     * and from this set of names, derives the set of domains which contain
     * MBeans.</p>
     */
    public String[] getDomains() {
        final Set<ObjectName> names = getNames();
        final Set<String> res = new TreeSet<String>();
        for (ObjectName n : names) {
            if (n == null) continue; // not allowed but you never know.
            res.add(n.getDomain());
        }
        return res.toArray(new String[res.size()]);
    }


    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method will first
     * call {@link
     *    #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle
     * to the named MBean,
     * and then call {@link DynamicMBean#getAttribute getAttribute}
     * on that {@link DynamicMBean} handle.</p>
     *
     * @throws RuntimeOperationsException {@inheritDoc}
     */
    public Object getAttribute(ObjectName name, String attribute)
        throws MBeanException, AttributeNotFoundException,
               InstanceNotFoundException, ReflectionException {
        final DynamicMBean mbean = nonNullMBeanFor(name);
        return mbean.getAttribute(attribute);
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method will first
     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}
     * to obtain a handle to the named MBean,
     * and then call {@link DynamicMBean#setAttribute setAttribute}
     * on that {@link DynamicMBean} handle.</p>
     *
     * @throws RuntimeOperationsException {@inheritDoc}
     */
    public void setAttribute(ObjectName name, Attribute attribute)
        throws InstanceNotFoundException, AttributeNotFoundException,
            InvalidAttributeValueException, MBeanException,
            ReflectionException {
        final DynamicMBean mbean = nonNullMBeanFor(name);
        mbean.setAttribute(attribute);
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method will first
     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
     * handle to the named MBean,
     * and then call {@link DynamicMBean#getAttributes getAttributes}
     * on that {@link DynamicMBean} handle.</p>
     *
     * @throws RuntimeOperationsException {@inheritDoc}
     */
    public AttributeList getAttributes(ObjectName name,
            String[] attributes) throws InstanceNotFoundException,
            ReflectionException {
        final DynamicMBean mbean = nonNullMBeanFor(name);
        return mbean.getAttributes(attributes);
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method will first
     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
     * handle to the named MBean,
     * and then call {@link DynamicMBean#setAttributes setAttributes}
     * on that {@link DynamicMBean} handle.</p>
     *
     * @throws RuntimeOperationsException {@inheritDoc}
     */
    public AttributeList setAttributes(ObjectName name, AttributeList attributes)
        throws InstanceNotFoundException, ReflectionException {
        final DynamicMBean mbean = nonNullMBeanFor(name);
        return mbean.setAttributes(attributes);
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method will first
     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
     * handle to the named MBean,
     * and then call {@link DynamicMBean#invoke invoke}
     * on that {@link DynamicMBean} handle.</p>
     */
    public Object invoke(ObjectName name, String operationName,
                Object[] params, String[] signature)
                throws InstanceNotFoundException, MBeanException,
                       ReflectionException {
        final DynamicMBean mbean = nonNullMBeanFor(name);
        return mbean.invoke(operationName, params, signature);
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method will first
     * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a
     * handle to the named MBean,
     * and then call {@link DynamicMBean#getMBeanInfo getMBeanInfo}
     * on that {@link DynamicMBean} handle.</p>
     */
    public MBeanInfo getMBeanInfo(ObjectName name)
        throws InstanceNotFoundException, IntrospectionException,
               ReflectionException {
        final DynamicMBean mbean = nonNullMBeanFor(name);
        return mbean.getMBeanInfo();
   }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method will call
     * {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}.<!--
     * -->{@link DynamicMBean#getMBeanInfo getMBeanInfo()}.<!--
     * -->{@link MBeanInfo#getClassName getClassName()} to get the
     * class name to combine with {@code name} to produce a new
     * {@code ObjectInstance}.</p>
     */
    public ObjectInstance getObjectInstance(ObjectName name)
            throws InstanceNotFoundException {
        final DynamicMBean mbean = nonNullMBeanFor(name);
        final String className = mbean.getMBeanInfo().getClassName();
        return new ObjectInstance(name, className);
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method will first call {@link
     * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle to the
     * named MBean. If {@code getDynamicMBeanFor} returns an object, {@code
     * isRegistered} will return true. If {@code getDynamicMBeanFor} returns
     * null or throws {@link InstanceNotFoundException}, {@code isRegistered}
     * will return false.</p>
     *
     * @throws RuntimeOperationsException {@inheritDoc}
     */
    public boolean isRegistered(ObjectName name) {
        try {
            final DynamicMBean mbean = getDynamicMBeanFor(name);
            return mbean!=null;
        } catch (InstanceNotFoundException x) {
            if (LOG.isLoggable(Level.FINEST))
                LOG.finest("MBean "+name+" is not registered: "+x);
            return false;
        }
    }


    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method will first
     * call {@link #queryNames queryNames}
     * to get a list of all matching MBeans, and then, for each returned name,
     * call {@link #getObjectInstance getObjectInstance(name)}.</p>
     */
    public Set<ObjectInstance> queryMBeans(ObjectName pattern, QueryExp query) {
        final Set<ObjectName> names = queryNames(pattern, query);
        if (names.isEmpty()) return Collections.emptySet();
        final Set<ObjectInstance> mbeans = new HashSet<ObjectInstance>();
        for (ObjectName name : names) {
            try {
                mbeans.add(getObjectInstance(name));
            } catch (SecurityException x) { // DLS: OK
                continue;
            } catch (InstanceNotFoundException x) { // DLS: OK
                continue;
            }
        }
        return mbeans;
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method calls {@link #getMatchingNames
     * getMatchingNames(pattern)} to obtain a list of MBeans matching
     * the given name pattern. If the {@code query} parameter is null,
     * this will be the result. Otherwise, it will evaluate the
     * {@code query} parameter for each of the returned names, exactly
     * as an {@code MBeanServer} would. This might result in
     * {@link #getDynamicMBeanFor getDynamicMBeanFor} being called
     * several times for each returned name.</p>
     */
    public Set<ObjectName> queryNames(ObjectName pattern, QueryExp query) {
        try {
            final Set<ObjectName> res = getMatchingNames(pattern);
            return filterListOfObjectNames(res, query);
        } catch (Exception x) {
            LOG.fine("Unexpected exception raised in queryNames: "+x);
            LOG.log(Level.FINEST, "Unexpected exception raised in queryNames", x);
        }
        // We reach here only when an exception was raised.
        //
        return Collections.emptySet();
    }

    private final static boolean apply(final QueryExp query,
                  final ObjectName on,
                  final MBeanServer srv) {
        boolean res = false;
        MBeanServer oldServer = QueryEval.getMBeanServer();
        query.setMBeanServer(srv);
        try {
            res = query.apply(on);
        } catch (Exception e) {
            LOG.finest("QueryExp.apply threw exception, returning false." +
                    " Cause: "+e);
            res = false;
        } finally {
           /*
            * query.setMBeanServer is probably
            * QueryEval.setMBeanServer so put back the old
            * value.  Since that method uses a ThreadLocal
            * variable, this code is only needed for the
            * unusual case where the user creates a custom
            * QueryExp that calls a nested query on another
            * MBeanServer.
            */
            query.setMBeanServer(oldServer);
        }
        return res;
    }

    /**
     * Filters a {@code Set<ObjectName>} according to a pattern and a query.
     * This might be quite inefficient for virtual name spaces.
     */
    Set<ObjectName>
            filterListOfObjectNames(Set<ObjectName> list,
                                    QueryExp query) {
        if (list.isEmpty() || query == null)
            return list;

        // create a new result set
        final Set<ObjectName> result = new HashSet<ObjectName>();

        for (ObjectName on : list) {
            // if on doesn't match query exclude it.
            if (apply(query, on, this))
                result.add(on);
        }
        return result;
    }


    // Don't use {@inheritDoc}, because we don't want to say that the
    // MBeanServer replaces a reference to the MBean by its ObjectName.
    /**
     * <p>Adds a listener to a registered MBean. A notification emitted by
     * the MBean will be forwarded to the listener.</p>
     *
     * <p>This implementation calls
     * {@link #getNotificationEmitterFor getNotificationEmitterFor}
     * and invokes {@code addNotificationListener} on the
     * {@link NotificationEmitter} it returns.
     *
     * @see #getDynamicMBeanFor getDynamicMBeanFor
     * @see #getNotificationEmitterFor getNotificationEmitterFor
     */
    public void addNotificationListener(ObjectName name,
            NotificationListener listener, NotificationFilter filter,
            Object handback) throws InstanceNotFoundException {
        final NotificationEmitter emitter =
                getNonNullNotificationEmitterFor(name);
        emitter.addNotificationListener(listener, filter, handback);
    }

    /**
     * {@inheritDoc}
     *
     * <p>This implementation calls
     * {@link #getNotificationEmitterFor getNotificationEmitterFor}
     * and invokes {@code removeNotificationListener} on the
     * {@link NotificationEmitter} it returns.
     * @see #getDynamicMBeanFor getDynamicMBeanFor
     * @see #getNotificationEmitterFor getNotificationEmitterFor
     */
    public void removeNotificationListener(ObjectName name,
            NotificationListener listener)
            throws InstanceNotFoundException, ListenerNotFoundException {
        final NotificationEmitter emitter =
                getNonNullNotificationEmitterFor(name);
        emitter.removeNotificationListener(listener);
    }

    /**
     * {@inheritDoc}
     *
     * <p>This implementation calls
     * {@link #getNotificationEmitterFor getNotificationEmitterFor}
     * and invokes {@code removeNotificationListener} on the
     * {@link NotificationEmitter} it returns.
     * @see #getDynamicMBeanFor getDynamicMBeanFor
     * @see #getNotificationEmitterFor getNotificationEmitterFor
     */
    public void removeNotificationListener(ObjectName name,
            NotificationListener listener, NotificationFilter filter,
            Object handback)
            throws InstanceNotFoundException, ListenerNotFoundException {
        NotificationEmitter emitter =
                getNonNullNotificationEmitterFor(name);
        emitter.removeNotificationListener(listener);
    }


    /**
     * <p>Adds a listener to a registered MBean.</p>
     *
     * <p>The default implementation of this method first calls
     * {@link #getDynamicMBeanFor getDynamicMBeanFor(listenerName)}.
     * If that successfully returns an object, call it {@code
     * mbean}, then (a) if {@code mbean} is an instance of {@link
     * NotificationListener} then this method calls {@link
     * #addNotificationListener(ObjectName, NotificationListener,
     * NotificationFilter, Object) addNotificationListener(name, mbean, filter,
     * handback)}, otherwise (b) this method throws an exception as specified
     * for this case.</p>
     *
     * <p>This default implementation is not appropriate for Virtual MBeans,
     * although that only matters if the object returned by {@code
     * getDynamicMBeanFor} can be an instance of
     * {@code NotificationListener}.</p>
     *
     * @throws RuntimeOperationsException {@inheritDoc}
     */
    public void addNotificationListener(ObjectName name, ObjectName listenerName,
            NotificationFilter filter, Object handback)
            throws InstanceNotFoundException {
        NotificationListener listener = getListenerMBean(listenerName);
        addNotificationListener(name, listener, filter, handback);
    }

    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.</p>
     *
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    public void removeNotificationListener(ObjectName name,
            ObjectName listenerName)
            throws InstanceNotFoundException, ListenerNotFoundException {
        NotificationListener listener = getListenerMBean(listenerName);
        removeNotificationListener(name, listener);
    }

    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.</p>
     *
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    public void removeNotificationListener(ObjectName name,
            ObjectName listenerName, NotificationFilter filter,
            Object handback)
            throws InstanceNotFoundException, ListenerNotFoundException {
        NotificationListener listener = getListenerMBean(listenerName);
        removeNotificationListener(name, listener, filter, handback);
    }

    private NotificationListener getListenerMBean(ObjectName listenerName)
            throws InstanceNotFoundException {
        Object mbean = getDynamicMBeanFor(listenerName);
        if (mbean instanceof NotificationListener)
            return (NotificationListener) mbean;
        else {
            throw newIllegalArgumentException(
                    "MBean is not a NotificationListener: " + listenerName);
        }
    }


    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link InstanceNotFoundException} wrapping
     * {@link UnsupportedOperationException}.</p>
     *
     * @return the default implementation of this method never returns.
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    public ClassLoader getClassLoader(ObjectName loaderName)
            throws InstanceNotFoundException {
        final UnsupportedOperationException failed =
                new UnsupportedOperationException("getClassLoader");
        final InstanceNotFoundException x =
                new InstanceNotFoundException(String.valueOf(loaderName));
        x.initCause(failed);
        throw x;
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method calls
     * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies
     * the logic just described to the result.</p>
     */
    public ClassLoader getClassLoaderFor(ObjectName mbeanName)
            throws InstanceNotFoundException {
        final DynamicMBean mbean = nonNullMBeanFor(mbeanName);
        if (mbean instanceof DynamicWrapperMBean)
            return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
        else
            return mbean.getClass().getClassLoader();
    }

    /**
     * {@inheritDoc}
     *
     * <p>The default implementation of this method returns a
     * {@link ClassLoaderRepository} containing exactly one loader,
     * the {@linkplain Thread#getContextClassLoader() context class loader}
     * for the current thread.
     * Subclasses can override this method to return a different
     * {@code ClassLoaderRepository}.</p>
     */
    public ClassLoaderRepository getClassLoaderRepository() {
        // We return a new ClassLoaderRepository each time this
        // method is called. This is by design, because the
        // SingletonClassLoaderRepository is a very small object and
        // getClassLoaderRepository() will not be called very often
        // (the connector server calls it once) - in the context of
        // MBeanServerSupport there's a very good chance that this method will
        // *never* be called.
        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
        return Util.getSingleClassLoaderRepository(ccl);
    }


    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.</p>
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    public ObjectInstance registerMBean(Object object, ObjectName name)
            throws InstanceAlreadyExistsException, MBeanRegistrationException,
            NotCompliantMBeanException {
        throw newUnsupportedException("registerMBean");
    }

    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    public void unregisterMBean(ObjectName name)
            throws InstanceNotFoundException, MBeanRegistrationException {
        throw newUnsupportedException("unregisterMBean");
    }

    /**
     * Calls {@link #createMBean(String, ObjectName,
     *           ObjectName, Object[], String[], boolean)
     * createMBean(className, name, null, params, signature, true)};
     */
    public final ObjectInstance createMBean(String className, ObjectName name,
            Object[] params, String[] signature)
            throws ReflectionException, InstanceAlreadyExistsException,
            MBeanRegistrationException, MBeanException,
            NotCompliantMBeanException {
        try {
            return safeCreateMBean(className, name, null, params, signature, true);
        } catch (InstanceNotFoundException ex) {
            // should not happen!
            throw new MBeanException(ex, "Unexpected exception: " + ex);
        }
    }

    /**
     * Calls {@link #createMBean(String, ObjectName,
     *           ObjectName, Object[], String[], boolean)
     * createMBean(className,name, loaderName, params, signature, false)};
     */
    public final ObjectInstance createMBean(String className, ObjectName name,
            ObjectName loaderName, Object[] params, String[] signature)
            throws ReflectionException, InstanceAlreadyExistsException,
            MBeanRegistrationException, MBeanException,
            NotCompliantMBeanException, InstanceNotFoundException {
        return safeCreateMBean(className, name, loaderName, params, signature, false);
    }

    /**
     * Calls {@link #createMBean(String, ObjectName,
     *           ObjectName, Object[], String[], boolean)
     * createMBean(className, name, null, null, null, true)};
     */
    public final ObjectInstance createMBean(String className, ObjectName name)
        throws ReflectionException, InstanceAlreadyExistsException,
            MBeanRegistrationException, MBeanException,
            NotCompliantMBeanException {
        try {
            return safeCreateMBean(className, name, null, null, null, true);
        } catch (InstanceNotFoundException ex) {
            // should not happen!
            throw new MBeanException(ex, "Unexpected exception: " + ex);
        }
    }

    /**
     * Calls {@link #createMBean(String, ObjectName,
     *           ObjectName, Object[], String[], boolean)
     * createMBean(className, name, loaderName, null, null, false)};
     */
    public final ObjectInstance createMBean(String className, ObjectName name,
            ObjectName loaderName)
            throws ReflectionException, InstanceAlreadyExistsException,
            MBeanRegistrationException, MBeanException,
            NotCompliantMBeanException, InstanceNotFoundException {
        return safeCreateMBean(className, name, loaderName, null, null, false);
    }

    // make sure all exceptions are correctly wrapped in a JMXException
    private ObjectInstance safeCreateMBean(String className,
            ObjectName name, ObjectName loaderName, Object[] params,
            String[] signature, boolean useRepository)
            throws ReflectionException, InstanceAlreadyExistsException,
            MBeanRegistrationException, MBeanException,
            NotCompliantMBeanException, InstanceNotFoundException {
        try {
            return createMBean(className, name, loaderName, params,
                               signature, useRepository);
        } catch (ReflectionException x) { throw x;
        } catch (InstanceAlreadyExistsException x) { throw x;
        } catch (MBeanRegistrationException x) { throw x;
        } catch (MBeanException x) { throw x;
        } catch (NotCompliantMBeanException x) { throw x;
        } catch (InstanceNotFoundException x) { throw x;
        } catch (SecurityException x) { throw x;
        } catch (JMRuntimeException x) { throw x;
        } catch (RuntimeException x) {
            throw new RuntimeOperationsException(x, x.toString());
        } catch (Exception x) {
            throw new MBeanException(x, x.toString());
        }
    }


    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.</p>
     *
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    public Object instantiate(String className)
            throws ReflectionException, MBeanException {
        throw new UnsupportedOperationException("Not applicable.");
    }

    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.</p>
     *
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    public Object instantiate(String className, ObjectName loaderName)
            throws ReflectionException, MBeanException,
            InstanceNotFoundException {
        throw new UnsupportedOperationException("Not applicable.");
    }

    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.</p>
     *
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    public Object instantiate(String className, Object[] params,
            String[] signature) throws ReflectionException, MBeanException {
        throw new UnsupportedOperationException("Not applicable.");
    }

    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.</p>
     *
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    public Object instantiate(String className, ObjectName loaderName,
            Object[] params, String[] signature)
            throws ReflectionException, MBeanException,
            InstanceNotFoundException {
        throw new UnsupportedOperationException("Not applicable.");
    }


    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.</p>
     *
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    @Deprecated
    public ObjectInputStream deserialize(ObjectName name, byte[] data)
            throws InstanceNotFoundException, OperationsException {
        throw new UnsupportedOperationException("Not applicable.");
    }

    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.</p>
     *
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    @Deprecated
    public ObjectInputStream deserialize(String className, byte[] data)
            throws OperationsException, ReflectionException {
        throw new UnsupportedOperationException("Not applicable.");
    }

    /**
     * {@inheritDoc}
     *
     * <p>This operation is not supported in this base class implementation.
     * The default implementation of this method always throws
     * {@link RuntimeOperationsException} wrapping
     * {@link UnsupportedOperationException}.</p>
     *
     * @throws javax.management.RuntimeOperationsException wrapping
     *        {@link UnsupportedOperationException}
     */
    @Deprecated
    public ObjectInputStream deserialize(String className,
            ObjectName loaderName, byte[] data)
            throws InstanceNotFoundException, OperationsException,
            ReflectionException {
        throw new UnsupportedOperationException("Not applicable.");
    }


    // Calls getDynamicMBeanFor, and throws an InstanceNotFoundException
    // if the returned mbean is null.
    // The DynamicMBean returned by this method is thus guaranteed to be
    // non null.
    //
    private DynamicMBean nonNullMBeanFor(ObjectName name)
            throws InstanceNotFoundException {
        if (name == null)
            throw newIllegalArgumentException("Null ObjectName");
        if (name.getDomain().equals("")) {
            String defaultDomain = getDefaultDomain();
            try {
                name = name.withDomain(getDefaultDomain());
            } catch (Exception e) {
                throw newIllegalArgumentException(
                        "Illegal default domain: " + defaultDomain);
            }
        }
        final DynamicMBean mbean = getDynamicMBeanFor(name);
        if (mbean!=null) return mbean;
        throw new InstanceNotFoundException(String.valueOf(name));
    }

    static RuntimeException newUnsupportedException(String operation) {
        return new RuntimeOperationsException(
            new UnsupportedOperationException(
                operation+": Not supported in this namespace"));
    }

    static RuntimeException newIllegalArgumentException(String msg) {
        return new RuntimeOperationsException(
                new IllegalArgumentException(msg));
    }

}