jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java
changeset 1156 bbc2d15aaf7a
child 1222 78e3d021d528
equal deleted inserted replaced
1155:a9a142fcf1b5 1156:bbc2d15aaf7a
       
     1 /*
       
     2  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package com.sun.jmx.interceptor;
       
    27 
       
    28 
       
    29 import java.util.Collections;
       
    30 import java.util.HashMap;
       
    31 import java.util.Map;
       
    32 import java.util.Queue;
       
    33 import java.util.Set;
       
    34 
       
    35 import javax.management.Attribute;
       
    36 import javax.management.AttributeList;
       
    37 import javax.management.AttributeNotFoundException;
       
    38 import javax.management.InstanceAlreadyExistsException;
       
    39 import javax.management.InstanceNotFoundException;
       
    40 import javax.management.IntrospectionException;
       
    41 import javax.management.InvalidAttributeValueException;
       
    42 import javax.management.ListenerNotFoundException;
       
    43 import javax.management.MBeanException;
       
    44 import javax.management.MBeanInfo;
       
    45 import javax.management.MBeanRegistrationException;
       
    46 import javax.management.MBeanServer;
       
    47 import javax.management.MalformedObjectNameException;
       
    48 import javax.management.NotCompliantMBeanException;
       
    49 import javax.management.NotificationFilter;
       
    50 import javax.management.NotificationListener;
       
    51 import javax.management.ObjectInstance;
       
    52 import javax.management.ObjectName;
       
    53 import javax.management.QueryExp;
       
    54 import javax.management.ReflectionException;
       
    55 import javax.management.namespace.JMXNamespace;
       
    56 
       
    57 /**
       
    58  * A dispatcher that dispatches to MBeanServers.
       
    59  * <p><b>
       
    60  * This API is a Sun internal API and is subject to changes without notice.
       
    61  * </b></p>
       
    62  * @since 1.7
       
    63  */
       
    64 //
       
    65 // This is the base class for implementing dispatchers. We have two concrete
       
    66 // dispatcher implementations:
       
    67 //
       
    68 //   * A NamespaceDispatchInterceptor, which dispatch calls to existing
       
    69 //     namespace interceptors
       
    70 //   * A DomainDispatchInterceptor, which dispatch calls to existing domain
       
    71 //     interceptors.
       
    72 //
       
    73 // With the JMX Namespaces feature, the JMX MBeanServer is now structured
       
    74 // as follows:
       
    75 //
       
    76 // The JMX MBeanServer delegates to a NamespaceDispatchInterceptor,
       
    77 // which either dispatches to a namespace, or delegates to the
       
    78 // DomainDispatchInterceptor (if the object name contained no namespace).
       
    79 // The DomainDispatchInterceptor in turn either dispatches to a domain (if
       
    80 // there is a JMXDomain for that domain) or delegates to the
       
    81 // DefaultMBeanServerInterceptor (if there is no JMXDomain for that
       
    82 // domain). This makes the following picture:
       
    83 //
       
    84 //             JMX MBeanServer (outer shell)
       
    85 //                          |
       
    86 //                          |
       
    87 //              NamespaceDispatchInterceptor
       
    88 //                   /               \
       
    89 //     no namespace in object name?   \
       
    90 //                 /                   \
       
    91 //                /                   dispatch to namespace
       
    92 //         DomainDispatchInterceptor
       
    93 //              /              \
       
    94 //    no JMXDomain for domain?  \
       
    95 //            /                  \
       
    96 //           /                   dispatch to domain
       
    97 //  DefaultMBeanServerInterceptor
       
    98 //         /
       
    99 //   invoke locally registered MBean
       
   100 //
       
   101 //  The logic for maintaining a map of interceptors
       
   102 //  and dispatching to impacted interceptor, is implemented in this
       
   103 //  base class, which both NamespaceDispatchInterceptor and
       
   104 //  DomainDispatchInterceptor extend.
       
   105 //
       
   106 public abstract class DispatchInterceptor
       
   107         <T extends MBeanServer, N extends JMXNamespace>
       
   108         extends MBeanServerInterceptorSupport {
       
   109 
       
   110     /**
       
   111      * This is an abstraction which allows us to handle queryNames
       
   112      * and queryMBeans with the same algorithm. There are some subclasses
       
   113      * where we need to override both queryNames & queryMBeans to apply
       
   114      * the same transformation (usually aggregation of results when
       
   115      * several namespaces/domains are impacted) to both algorithms.
       
   116      * Usually the only thing that varies between the algorithm of
       
   117      * queryNames & the algorithm of queryMBean is the type of objects
       
   118      * in the returned Set. By using a QueryInvoker we can implement the
       
   119      * transformation only once and apply it to both queryNames &
       
   120      * queryMBeans.
       
   121      * @see QueryInterceptor below, and its subclass in
       
   122      * {@link DomainDispatcher}.
       
   123      **/
       
   124     static abstract class QueryInvoker<T> {
       
   125         abstract Set<T> query(MBeanServer mbs,
       
   126                         ObjectName pattern, QueryExp query);
       
   127     }
       
   128 
       
   129     /**
       
   130      * Used to perform queryNames. A QueryInvoker that invokes
       
   131      * queryNames on an MBeanServer.
       
   132      **/
       
   133     final static QueryInvoker<ObjectName> queryNamesInvoker =
       
   134             new QueryInvoker<ObjectName>() {
       
   135         Set<ObjectName> query(MBeanServer mbs,
       
   136                         ObjectName pattern, QueryExp query) {
       
   137             return mbs.queryNames(pattern,query);
       
   138         }
       
   139     };
       
   140 
       
   141     /**
       
   142      * Used to perform queryMBeans. A QueryInvoker that invokes
       
   143      * queryMBeans on an MBeanServer.
       
   144      **/
       
   145     final static QueryInvoker<ObjectInstance> queryMBeansInvoker =
       
   146             new QueryInvoker<ObjectInstance>() {
       
   147         Set<ObjectInstance> query(MBeanServer mbs,
       
   148                         ObjectName pattern, QueryExp query) {
       
   149             return mbs.queryMBeans(pattern,query);
       
   150         }
       
   151     };
       
   152 
       
   153     /**
       
   154      * We use this class to intercept queries.
       
   155      * There's a special case for JMXNamespace MBeans, because
       
   156      * "namespace//*:*" matches both "namespace//domain:k=v" and
       
   157      * "namespace//:type=JMXNamespace".
       
   158      * Therefore, queries may need to be forwarded to more than
       
   159      * on interceptor and the results aggregated...
       
   160      */
       
   161      static class QueryInterceptor {
       
   162         final MBeanServer wrapped;
       
   163         QueryInterceptor(MBeanServer mbs) {
       
   164             wrapped = mbs;
       
   165         }
       
   166         <X> Set<X> query(ObjectName pattern, QueryExp query,
       
   167                 QueryInvoker<X> invoker, MBeanServer server) {
       
   168             return invoker.query(server, pattern, query);
       
   169         }
       
   170 
       
   171         public Set<ObjectName> queryNames(ObjectName pattern, QueryExp query) {
       
   172             return query(pattern,query,queryNamesInvoker,wrapped);
       
   173         }
       
   174 
       
   175         public Set<ObjectInstance> queryMBeans(ObjectName pattern,
       
   176                 QueryExp query) {
       
   177             return query(pattern,query,queryMBeansInvoker,wrapped);
       
   178         }
       
   179     }
       
   180 
       
   181     // We don't need a ConcurrentHashMap here because getkeys() returns
       
   182     // an array of keys. Therefore there's no risk to have a
       
   183     // ConcurrentModificationException. We must however take into
       
   184     // account the fact that there can be no interceptor for
       
   185     // some of the returned keys if the map is being modified by
       
   186     // another thread, or by a callback within the same thread...
       
   187     // See getKeys() in this class and query() in DomainDispatcher.
       
   188     //
       
   189     private final Map<String,T> handlerMap =
       
   190             Collections.synchronizedMap(
       
   191             new HashMap<String,T>());
       
   192 
       
   193     // The key at which an interceptor for accessing the named MBean can be
       
   194     // found in the handlerMap. Note: there doesn't need to be an interceptor
       
   195     // for that key in the Map.
       
   196     //
       
   197     public abstract String getHandlerKey(ObjectName name);
       
   198 
       
   199     // Returns an interceptor for that name, or null if there's no interceptor
       
   200     // for that name.
       
   201     abstract MBeanServer getInterceptorOrNullFor(ObjectName name);
       
   202 
       
   203     // Returns a QueryInterceptor for that pattern.
       
   204     abstract QueryInterceptor getInterceptorForQuery(ObjectName pattern);
       
   205 
       
   206     // Returns the ObjectName of the JMXNamespace (or JMXDomain) for that
       
   207     // key (a namespace or a domain name).
       
   208     abstract ObjectName getHandlerNameFor(String key)
       
   209         throws MalformedObjectNameException;
       
   210 
       
   211     // Creates an interceptor for the given key, name, JMXNamespace (or
       
   212     // JMXDomain). Note: this will be either a NamespaceInterceptor
       
   213     // wrapping a JMXNamespace, if this object is an instance of
       
   214     // NamespaceDispatchInterceptor, or a DomainInterceptor wrapping a
       
   215     // JMXDomain, if this object is an instance of DomainDispatchInterceptor.
       
   216     abstract T createInterceptorFor(String key, ObjectName name,
       
   217             N jmxNamespace, Queue<Runnable> postRegisterQueue);
       
   218     //
       
   219     // The next interceptor in the chain.
       
   220     //
       
   221     // For the NamespaceDispatchInterceptor, this the DomainDispatchInterceptor.
       
   222     // For the DomainDispatchInterceptor, this is the
       
   223     // DefaultMBeanServerInterceptor.
       
   224     //
       
   225     // The logic of when to invoke the next interceptor in the chain depends
       
   226     // on the logic of the concrete dispatcher class.
       
   227     //
       
   228     // For instance, the NamespaceDispatchInterceptor invokes the next
       
   229     // interceptor when the object name doesn't contain any namespace.
       
   230     //
       
   231     // On the other hand, the DomainDispatchInterceptor invokes the
       
   232     // next interceptor when there's no interceptor for the accessed domain.
       
   233     //
       
   234     abstract MBeanServer getNextInterceptor();
       
   235 
       
   236     // hook for cleanup in subclasses.
       
   237     void interceptorReleased(T interceptor,
       
   238             Queue<Runnable> postDeregisterQueue) {
       
   239         // hook
       
   240     }
       
   241 
       
   242     // Hook for subclasses.
       
   243     MBeanServer getInterceptorForCreate(ObjectName name)
       
   244         throws MBeanRegistrationException {
       
   245         final MBeanServer ns = getInterceptorOrNullFor(name);
       
   246         if (ns == null) // name cannot be null here.
       
   247             throw new MBeanRegistrationException(
       
   248                     new IllegalArgumentException("No such MBean handler: " +
       
   249                         getHandlerKey(name) + " for " +name));
       
   250         return ns;
       
   251     }
       
   252 
       
   253     // Hook for subclasses.
       
   254     MBeanServer getInterceptorForInstance(ObjectName name)
       
   255         throws InstanceNotFoundException {
       
   256         final MBeanServer ns = getInterceptorOrNullFor(name);
       
   257         if (ns == null) // name cannot be null here.
       
   258             throw new InstanceNotFoundException(String.valueOf(name));
       
   259         return ns;
       
   260     }
       
   261 
       
   262     // sanity checks
       
   263     void validateHandlerNameFor(String key, ObjectName name) {
       
   264         if (key == null || key.equals(""))
       
   265             throw new IllegalArgumentException("invalid key for "+name+": "+key);
       
   266         try {
       
   267             final ObjectName handlerName = getHandlerNameFor(key);
       
   268             if (!name.equals(handlerName))
       
   269                 throw new IllegalArgumentException("bad handler name: "+name+
       
   270                         ". Should be: "+handlerName);
       
   271         } catch (MalformedObjectNameException x) {
       
   272             throw new IllegalArgumentException(name.toString(),x);
       
   273         }
       
   274     }
       
   275 
       
   276     // Called by the DefaultMBeanServerInterceptor when an instance
       
   277     // of JMXNamespace (or a subclass of it) is registered as an MBean.
       
   278     // This method is usually invoked from within the repository lock,
       
   279     // hence the necessity of the postRegisterQueue.
       
   280     public void addNamespace(ObjectName name, N jmxNamespace,
       
   281             Queue<Runnable> postRegisterQueue) {
       
   282         final String key = getHandlerKey(name);
       
   283         validateHandlerNameFor(key,name);
       
   284         synchronized (handlerMap) {
       
   285             final T exists =
       
   286                     handlerMap.get(key);
       
   287             if (exists != null)
       
   288                 throw new IllegalArgumentException(key+
       
   289                         ": handler already exists");
       
   290 
       
   291             final T ns = createInterceptorFor(key,name,jmxNamespace,
       
   292                     postRegisterQueue);
       
   293             handlerMap.put(key,ns);
       
   294         }
       
   295     }
       
   296 
       
   297     // Called by the DefaultMBeanServerInterceptor when an instance
       
   298     // of JMXNamespace (or a subclass of it) is deregistered.
       
   299     // This method is usually invoked from within the repository lock,
       
   300     // hence the necessity of the postDeregisterQueue.
       
   301     public void removeNamespace(ObjectName name, N jmxNamespace,
       
   302             Queue<Runnable> postDeregisterQueue) {
       
   303         final String key = getHandlerKey(name);
       
   304         final T ns;
       
   305         synchronized(handlerMap) {
       
   306             ns = handlerMap.remove(key);
       
   307         }
       
   308         interceptorReleased(ns,postDeregisterQueue);
       
   309     }
       
   310 
       
   311     // Get the interceptor for that key.
       
   312     T getInterceptor(String key) {
       
   313         synchronized (handlerMap) {
       
   314             return handlerMap.get(key);
       
   315         }
       
   316     }
       
   317 
       
   318     // We return an array of keys, which makes it possible to make
       
   319     // concurrent modifications of the handlerMap, provided that
       
   320     // the code which loops over the keys is prepared to handle null
       
   321     // interceptors.
       
   322     // See declaration of handlerMap above, and see also query() in
       
   323     // DomainDispatcher
       
   324     //
       
   325     public String[] getKeys() {
       
   326         synchronized (handlerMap) {
       
   327             final int size = handlerMap.size();
       
   328             return handlerMap.keySet().toArray(new String[size]);
       
   329         }
       
   330     }
       
   331 
       
   332     // From MBeanServer
       
   333     public ObjectInstance createMBean(String className, ObjectName name)
       
   334             throws ReflectionException, InstanceAlreadyExistsException,
       
   335                    MBeanRegistrationException, MBeanException,
       
   336                    NotCompliantMBeanException {
       
   337         return getInterceptorForCreate(name).createMBean(className,name);
       
   338     }
       
   339 
       
   340     // From MBeanServer
       
   341     public ObjectInstance createMBean(String className, ObjectName name,
       
   342                                       ObjectName loaderName)
       
   343             throws ReflectionException, InstanceAlreadyExistsException,
       
   344                    MBeanRegistrationException, MBeanException,
       
   345                    NotCompliantMBeanException, InstanceNotFoundException{
       
   346         return getInterceptorForCreate(name).createMBean(className,name,loaderName);
       
   347     }
       
   348 
       
   349     // From MBeanServer
       
   350     public ObjectInstance createMBean(String className, ObjectName name,
       
   351                                       Object params[], String signature[])
       
   352             throws ReflectionException, InstanceAlreadyExistsException,
       
   353                    MBeanRegistrationException, MBeanException,
       
   354                    NotCompliantMBeanException{
       
   355         return getInterceptorForCreate(name).
       
   356                 createMBean(className,name,params,signature);
       
   357     }
       
   358 
       
   359     // From MBeanServer
       
   360     public ObjectInstance createMBean(String className, ObjectName name,
       
   361                                       ObjectName loaderName, Object params[],
       
   362                                       String signature[])
       
   363             throws ReflectionException, InstanceAlreadyExistsException,
       
   364                    MBeanRegistrationException, MBeanException,
       
   365                    NotCompliantMBeanException, InstanceNotFoundException{
       
   366         return getInterceptorForCreate(name).createMBean(className,name,loaderName,
       
   367                                                    params,signature);
       
   368     }
       
   369 
       
   370     // From MBeanServer
       
   371     public ObjectInstance registerMBean(Object object, ObjectName name)
       
   372             throws InstanceAlreadyExistsException, MBeanRegistrationException,
       
   373                    NotCompliantMBeanException {
       
   374         return getInterceptorForCreate(name).registerMBean(object,name);
       
   375     }
       
   376 
       
   377     // From MBeanServer
       
   378     public void unregisterMBean(ObjectName name)
       
   379             throws InstanceNotFoundException, MBeanRegistrationException {
       
   380         getInterceptorForInstance(name).unregisterMBean(name);
       
   381     }
       
   382 
       
   383     // From MBeanServer
       
   384     public ObjectInstance getObjectInstance(ObjectName name)
       
   385             throws InstanceNotFoundException {
       
   386         return getInterceptorForInstance(name).getObjectInstance(name);
       
   387     }
       
   388 
       
   389     // From MBeanServer
       
   390     public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
       
   391         final QueryInterceptor mbs =
       
   392                 getInterceptorForQuery(name);
       
   393         if (mbs == null)  return Collections.emptySet();
       
   394         else return mbs.queryMBeans(name,query);
       
   395     }
       
   396 
       
   397     // From MBeanServer
       
   398     public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
       
   399         final QueryInterceptor mbs =
       
   400                 getInterceptorForQuery(name);
       
   401         if (mbs == null)  return Collections.emptySet();
       
   402         else return mbs.queryNames(name,query);
       
   403     }
       
   404 
       
   405     // From MBeanServer
       
   406     public boolean isRegistered(ObjectName name) {
       
   407         final MBeanServer mbs = getInterceptorOrNullFor(name);
       
   408         if (mbs == null) return false;
       
   409         else return mbs.isRegistered(name);
       
   410     }
       
   411 
       
   412     // From MBeanServer
       
   413     public Integer getMBeanCount() {
       
   414         return getNextInterceptor().getMBeanCount();
       
   415     }
       
   416 
       
   417     // From MBeanServer
       
   418     public Object getAttribute(ObjectName name, String attribute)
       
   419             throws MBeanException, AttributeNotFoundException,
       
   420                    InstanceNotFoundException, ReflectionException {
       
   421         return getInterceptorForInstance(name).getAttribute(name,attribute);
       
   422     }
       
   423 
       
   424     // From MBeanServer
       
   425     public AttributeList getAttributes(ObjectName name, String[] attributes)
       
   426             throws InstanceNotFoundException, ReflectionException {
       
   427         return getInterceptorForInstance(name).getAttributes(name,attributes);
       
   428     }
       
   429 
       
   430     // From MBeanServer
       
   431     public void setAttribute(ObjectName name, Attribute attribute)
       
   432             throws InstanceNotFoundException, AttributeNotFoundException,
       
   433                    InvalidAttributeValueException, MBeanException,
       
   434                    ReflectionException {
       
   435         getInterceptorForInstance(name).setAttribute(name,attribute);
       
   436     }
       
   437 
       
   438     // From MBeanServer
       
   439     public AttributeList setAttributes(ObjectName name,
       
   440                                        AttributeList attributes)
       
   441         throws InstanceNotFoundException, ReflectionException {
       
   442         return getInterceptorForInstance(name).setAttributes(name,attributes);
       
   443     }
       
   444 
       
   445     // From MBeanServer
       
   446     public Object invoke(ObjectName name, String operationName,
       
   447                          Object params[], String signature[])
       
   448             throws InstanceNotFoundException, MBeanException,
       
   449                    ReflectionException {
       
   450         return getInterceptorForInstance(name).invoke(name,operationName,params,
       
   451                 signature);
       
   452     }
       
   453 
       
   454     // From MBeanServer
       
   455     public String getDefaultDomain() {
       
   456         return getNextInterceptor().getDefaultDomain();
       
   457     }
       
   458 
       
   459     /**
       
   460      * Returns the list of domains in which any MBean is currently
       
   461      * registered.
       
   462      */
       
   463     public abstract String[] getDomains();
       
   464 
       
   465     // From MBeanServer
       
   466     public void addNotificationListener(ObjectName name,
       
   467                                         NotificationListener listener,
       
   468                                         NotificationFilter filter,
       
   469                                         Object handback)
       
   470             throws InstanceNotFoundException {
       
   471         getInterceptorForInstance(name).addNotificationListener(name,listener,filter,
       
   472                 handback);
       
   473     }
       
   474 
       
   475 
       
   476     // From MBeanServer
       
   477     public void addNotificationListener(ObjectName name,
       
   478                                         ObjectName listener,
       
   479                                         NotificationFilter filter,
       
   480                                         Object handback)
       
   481             throws InstanceNotFoundException {
       
   482         getInterceptorForInstance(name).addNotificationListener(name,listener,filter,
       
   483                 handback);
       
   484     }
       
   485 
       
   486     // From MBeanServer
       
   487     public void removeNotificationListener(ObjectName name,
       
   488                                            ObjectName listener)
       
   489         throws InstanceNotFoundException, ListenerNotFoundException {
       
   490         getInterceptorForInstance(name).removeNotificationListener(name,listener);
       
   491     }
       
   492 
       
   493     // From MBeanServer
       
   494     public void removeNotificationListener(ObjectName name,
       
   495                                            ObjectName listener,
       
   496                                            NotificationFilter filter,
       
   497                                            Object handback)
       
   498             throws InstanceNotFoundException, ListenerNotFoundException {
       
   499         getInterceptorForInstance(name).removeNotificationListener(name,listener,filter,
       
   500                 handback);
       
   501     }
       
   502 
       
   503 
       
   504     // From MBeanServer
       
   505     public void removeNotificationListener(ObjectName name,
       
   506                                            NotificationListener listener)
       
   507             throws InstanceNotFoundException, ListenerNotFoundException {
       
   508         getInterceptorForInstance(name).removeNotificationListener(name,listener);
       
   509     }
       
   510 
       
   511     // From MBeanServer
       
   512     public void removeNotificationListener(ObjectName name,
       
   513                                            NotificationListener listener,
       
   514                                            NotificationFilter filter,
       
   515                                            Object handback)
       
   516             throws InstanceNotFoundException, ListenerNotFoundException {
       
   517         getInterceptorForInstance(name).removeNotificationListener(name,listener,filter,
       
   518                 handback);
       
   519     }
       
   520 
       
   521     // From MBeanServer
       
   522     public MBeanInfo getMBeanInfo(ObjectName name)
       
   523             throws InstanceNotFoundException, IntrospectionException,
       
   524                    ReflectionException {
       
   525         return getInterceptorForInstance(name).getMBeanInfo(name);
       
   526     }
       
   527 
       
   528 
       
   529     // From MBeanServer
       
   530     public boolean isInstanceOf(ObjectName name, String className)
       
   531             throws InstanceNotFoundException {
       
   532         return getInterceptorForInstance(name).isInstanceOf(name,className);
       
   533     }
       
   534 
       
   535     // From MBeanServer
       
   536     public ClassLoader getClassLoaderFor(ObjectName mbeanName)
       
   537         throws InstanceNotFoundException {
       
   538         return getInterceptorForInstance(mbeanName).getClassLoaderFor(mbeanName);
       
   539     }
       
   540 
       
   541     // From MBeanServer
       
   542     public ClassLoader getClassLoader(ObjectName loaderName)
       
   543         throws InstanceNotFoundException {
       
   544         return getInterceptorForInstance(loaderName).getClassLoader(loaderName);
       
   545     }
       
   546 
       
   547 }