/* * 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; /** *

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.

* *

There are two main use cases for this class: special-purpose MBeanServer implementations, * and namespaces containing Virtual MBeans. The next * sections explain these use cases.

* *

In the simplest case, a subclass needs to implement only two methods:

* * * *

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.

* *

Special-purpose MBeanServer implementations

* *

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.

* *

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.

* *

Here is an example of a special-purpose {@code MBeanServer} * implementation that contains exactly one MBean, which is specified at the * time of creation.

* *
 * 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;
 *     }
 *
 *     @Override
 *     protected {@code Set} {@link #getNames getNames}() {
 *         return Collections.singleton(objectName);
 *     }
 *
 *     @Override
 *     public DynamicMBean {@link #getDynamicMBeanFor
 *                                getDynamicMBeanFor}(ObjectName name)
 *             throws InstanceNotFoundException {
 *         if (objectName.equals(name))
 *             return mbean;
 *         else
 *             throw new InstanceNotFoundException(name);
 *     }
 * }
 * 
* *

Using this class, you could make an {@code MBeanServer} that contains * a {@link javax.management.timer.Timer Timer} MBean like this:

* *
 *     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);
 * 
* *

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 * below.

* *

Namespaces containing Virtual MBeans

* *

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}.

* *

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.

* *
 * public interface PropertyMBean {
 *     public String getValue();
 * }
 *
 * 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);
 *         }
 *     }
 *
 *     @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);
 *     }
 *
 *     @Override
 *     protected {@code Set} {@link #getNames getNames}() {
 *         {@code Set names = new TreeSet();}
 *         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;
 *     }
 * }
 * 
* *

Because the {@code getDynamicMBeanFor} method * returns a different object every time it is called, the default handling * of notifications will not work, as explained below. * 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.)

* *
 * public class PropsMBS {
 *     ...as above...
 *
 *     private final {@link VirtualEventManager} vem = new VirtualEventManager();
 *
 *     @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);
 *     }
 * }
 * 
* *

MBean creation and deletion

* *

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)}.

* *

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}.

* *

Notifications

* *

By default {@link MBeanServer#addNotificationListener(ObjectName, * NotificationListener, NotificationFilter, Object) addNotificationListener} * is accepted for an MBean {@code name} if {@link #getDynamicMBeanFor * getDynamicMBeanFor}(name) returns an object that is a * {@link NotificationEmitter}. That is appropriate if * {@code getDynamicMBeanFor}(name) always returns the * same object for the same {@code name}. 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.

* *

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:

* *
 *     private final VirtualEventManager vem = new VirtualEventManager();
 *
 *     @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);
 *     }
 * 
* *

A notification {@code n} can then be sent from the Virtual MBean * called {@code name} by calling {@link VirtualEventManager#publish * vem.publish}(name, n). See the example * above.

* * @since 1.7 */ public abstract class MBeanServerSupport implements MBeanServer { /** * A logger for this class. */ private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; /** *

Make a new {@code MBeanServerSupport} instance.

*/ protected MBeanServerSupport() { } /** *

Returns a dynamically created handle that makes it possible to * access the named MBean for the duration of a method call.

* *

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.

* @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; /** *

Subclasses should implement this method to return * the names of all MBeans handled by this object instance.

* *

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:

* * * * @return the names of all MBeans handled by this object. */ protected abstract Set getNames(); /** *

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}.

* * @param pattern an ObjectName pattern * @return the list of MBean names that match the given pattern. */ protected Set getMatchingNames(ObjectName pattern) { return Util.filterMatchingNames(pattern, getNames()); } /** *

Returns a {@link NotificationEmitter} which can be used to * subscribe or unsubscribe for notifications with the named * mbean.

* *

The default implementation of this method calls {@link * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object * if it is a {@code NotificationEmitter}, otherwise null. See above for further discussion of notification * handling.

* * @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; } /** *

Creates a new MBean in the MBean name space. * This operation is not supported in this base class implementation.

* The default implementation of this method always throws an {@link * UnsupportedOperationException} * wrapped in a {@link RuntimeOperationsException}.

* *

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 ObjectInstance, containing the * ObjectName and the Java class name of the newly * instantiated MBean. If the contained ObjectName * is n, the contained Java class name is * {@link javax.management.MBeanServer#getMBeanInfo * getMBeanInfo(n)}.getClassName(). * * @exception ReflectionException Wraps a * java.lang.ClassNotFoundException or a * java.lang.Exception 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 * preRegister (MBeanRegistration * 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: *

*/ 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"); } /** *

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.

* * {@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} * *

The default implementation of this method returns the string * "DefaultDomain".

*/ public String getDefaultDomain() { return "DefaultDomain"; } /** * {@inheritDoc} * *

The default implementation of this method returns * {@link #getNames()}.size().

*/ public Integer getMBeanCount() { return getNames().size(); } /** * {@inheritDoc} * *

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.

*/ public String[] getDomains() { final Set names = getNames(); final Set res = new TreeSet(); 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} * *

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.

* * @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} * *

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.

* * @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} * *

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.

* * @throws RuntimeOperationsException {@inheritDoc} */ public AttributeList getAttributes(ObjectName name, String[] attributes) throws InstanceNotFoundException, ReflectionException { final DynamicMBean mbean = nonNullMBeanFor(name); return mbean.getAttributes(attributes); } /** * {@inheritDoc} * *

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.

* * @throws RuntimeOperationsException {@inheritDoc} */ public AttributeList setAttributes(ObjectName name, AttributeList attributes) throws InstanceNotFoundException, ReflectionException { final DynamicMBean mbean = nonNullMBeanFor(name); return mbean.setAttributes(attributes); } /** * {@inheritDoc} * *

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.

*/ 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} * *

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.

*/ public MBeanInfo getMBeanInfo(ObjectName name) throws InstanceNotFoundException, IntrospectionException, ReflectionException { final DynamicMBean mbean = nonNullMBeanFor(name); return mbean.getMBeanInfo(); } /** * {@inheritDoc} * *

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}.

*/ public ObjectInstance getObjectInstance(ObjectName name) throws InstanceNotFoundException { final DynamicMBean mbean = nonNullMBeanFor(name); final String className = mbean.getMBeanInfo().getClassName(); return new ObjectInstance(name, className); } /** * {@inheritDoc} * *

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.

* * @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} * *

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)}.

*/ public Set queryMBeans(ObjectName pattern, QueryExp query) { final Set names = queryNames(pattern, query); if (names.isEmpty()) return Collections.emptySet(); final Set mbeans = new HashSet(); for (ObjectName name : names) { try { mbeans.add(getObjectInstance(name)); } catch (SecurityException x) { // DLS: OK continue; } catch (InstanceNotFoundException x) { // DLS: OK continue; } } return mbeans; } /** * {@inheritDoc} * *

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.

*/ public Set queryNames(ObjectName pattern, QueryExp query) { try { final Set 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} according to a pattern and a query. * This might be quite inefficient for virtual name spaces. */ Set filterListOfObjectNames(Set list, QueryExp query) { if (list.isEmpty() || query == null) return list; // create a new result set final Set result = new HashSet(); 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. /** *

Adds a listener to a registered MBean. A notification emitted by * the MBean will be forwarded to the listener.

* *

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} * *

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} * *

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); } /** *

Adds a listener to a registered MBean.

* *

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.

* *

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}.

* * @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} * *

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 removeNotificationListener(ObjectName name, ObjectName listenerName) throws InstanceNotFoundException, ListenerNotFoundException { NotificationListener listener = getListenerMBean(listenerName); removeNotificationListener(name, listener); } /** * {@inheritDoc} * *

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 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} * *

This operation is not supported in this base class implementation. * The default implementation of this method always throws * {@link InstanceNotFoundException} wrapping * {@link UnsupportedOperationException}.

* * @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} * *

The default implementation of this method calls * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies * the logic just described to the result.

*/ 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} * *

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}.

*/ 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} * *

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 ObjectInstance registerMBean(Object object, ObjectName name) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { throw newUnsupportedException("registerMBean"); } /** * {@inheritDoc} * *

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} * *

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 Object instantiate(String className) throws ReflectionException, MBeanException { throw new UnsupportedOperationException("Not applicable."); } /** * {@inheritDoc} * *

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 Object instantiate(String className, ObjectName loaderName) throws ReflectionException, MBeanException, InstanceNotFoundException { throw new UnsupportedOperationException("Not applicable."); } /** * {@inheritDoc} * *

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 Object instantiate(String className, Object[] params, String[] signature) throws ReflectionException, MBeanException { throw new UnsupportedOperationException("Not applicable."); } /** * {@inheritDoc} * *

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 Object instantiate(String className, ObjectName loaderName, Object[] params, String[] signature) throws ReflectionException, MBeanException, InstanceNotFoundException { throw new UnsupportedOperationException("Not applicable."); } /** * {@inheritDoc} * *

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} */ @Deprecated public ObjectInputStream deserialize(ObjectName name, byte[] data) throws InstanceNotFoundException, OperationsException { throw new UnsupportedOperationException("Not applicable."); } /** * {@inheritDoc} * *

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} */ @Deprecated public ObjectInputStream deserialize(String className, byte[] data) throws OperationsException, ReflectionException { throw new UnsupportedOperationException("Not applicable."); } /** * {@inheritDoc} * *

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} */ @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)); } }