1 /*
   2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jmx.interceptor;
  27 
  28 
  29 // JMX RI
  30 import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
  31 import com.sun.jmx.mbeanserver.DynamicMBean2;
  32 import com.sun.jmx.mbeanserver.Introspector;
  33 import com.sun.jmx.mbeanserver.MBeanInstantiator;
  34 import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
  35 import com.sun.jmx.mbeanserver.NamedObject;
  36 import com.sun.jmx.mbeanserver.Repository;
  37 import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
  38 import com.sun.jmx.mbeanserver.Util;
  39 import com.sun.jmx.remote.util.EnvHelp;
  40 
  41 import java.io.ObjectInputStream;
  42 import java.lang.ref.WeakReference;
  43 import java.security.AccessControlContext;
  44 import java.security.AccessController;
  45 import java.security.Permission;
  46 import java.security.PrivilegedAction;
  47 import java.security.ProtectionDomain;
  48 import java.util.ArrayList;
  49 import java.util.HashSet;
  50 import java.util.List;
  51 import java.util.Set;
  52 import java.util.WeakHashMap;
  53 import java.util.logging.Level;
  54 
  55 // JMX import
  56 import javax.management.Attribute;
  57 import javax.management.AttributeList;
  58 import javax.management.AttributeNotFoundException;
  59 import javax.management.DynamicMBean;
  60 import javax.management.InstanceAlreadyExistsException;
  61 import javax.management.InstanceNotFoundException;
  62 import javax.management.IntrospectionException;
  63 import javax.management.InvalidAttributeValueException;
  64 import javax.management.JMRuntimeException;
  65 import javax.management.ListenerNotFoundException;
  66 import javax.management.MBeanException;
  67 import javax.management.MBeanInfo;
  68 import javax.management.MBeanPermission;
  69 import javax.management.MBeanRegistration;
  70 import javax.management.MBeanRegistrationException;
  71 import javax.management.MBeanServer;
  72 import javax.management.MBeanServerDelegate;
  73 import javax.management.MBeanServerNotification;
  74 import javax.management.MBeanTrustPermission;
  75 import javax.management.NotCompliantMBeanException;
  76 import javax.management.Notification;
  77 import javax.management.NotificationBroadcaster;
  78 import javax.management.NotificationEmitter;
  79 import javax.management.NotificationFilter;
  80 import javax.management.NotificationListener;
  81 import javax.management.ObjectInstance;
  82 import javax.management.ObjectName;
  83 import javax.management.OperationsException;
  84 import javax.management.QueryEval;
  85 import javax.management.QueryExp;
  86 import javax.management.ReflectionException;
  87 import javax.management.RuntimeErrorException;
  88 import javax.management.RuntimeMBeanException;
  89 import javax.management.RuntimeOperationsException;
  90 import javax.management.loading.ClassLoaderRepository;
  91 
  92 /**
  93  * This is the default class for MBean manipulation on the agent side. It
  94  * contains the methods necessary for the creation, registration, and
  95  * deletion of MBeans as well as the access methods for registered MBeans.
  96  * This is the core component of the JMX infrastructure.
  97  * <P>
  98  * Every MBean which is added to the MBean server becomes manageable: its attributes and operations
  99  * become remotely accessible through the connectors/adaptors connected to that MBean server.
 100  * A Java object cannot be registered in the MBean server unless it is a JMX compliant MBean.
 101  * <P>
 102  * When an MBean is registered or unregistered in the MBean server an
 103  * {@link javax.management.MBeanServerNotification MBeanServerNotification}
 104  * Notification is emitted. To register an object as listener to MBeanServerNotifications
 105  * you should call the MBean server method {@link #addNotificationListener addNotificationListener} with <CODE>ObjectName</CODE>
 106  * the <CODE>ObjectName</CODE> of the {@link javax.management.MBeanServerDelegate MBeanServerDelegate}.
 107  * This <CODE>ObjectName</CODE> is:
 108  * <BR>
 109  * <CODE>JMImplementation:type=MBeanServerDelegate</CODE>.
 110  *
 111  * @since 1.5
 112  */
 113 public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
 114 
 115     /** The MBeanInstantiator object used by the
 116      *  DefaultMBeanServerInterceptor */
 117     private final transient MBeanInstantiator instantiator;
 118 
 119     /** The MBean server object that is associated to the
 120      *  DefaultMBeanServerInterceptor */
 121     private transient MBeanServer server = null;
 122 
 123     /** The MBean server delegate object that is associated to the
 124      *  DefaultMBeanServerInterceptor */
 125     private final transient MBeanServerDelegate delegate;
 126 
 127     /** The Repository object used by the DefaultMBeanServerInterceptor */
 128     private final transient Repository repository;
 129 
 130     /** Wrappers for client listeners.  */
 131     /* See the comment before addNotificationListener below.  */
 132     private final transient
 133         WeakHashMap<ListenerWrapper, WeakReference<ListenerWrapper>>
 134             listenerWrappers =
 135                 new WeakHashMap<ListenerWrapper,
 136                                 WeakReference<ListenerWrapper>>();
 137 
 138     /** The default domain of the object names */
 139     private final String domain;
 140 
 141     /** The sequence number identifying the notifications sent */
 142     // Now sequence number is handled by MBeanServerDelegate.
 143     // private int sequenceNumber=0;
 144 
 145     /**
 146      * Creates a DefaultMBeanServerInterceptor with the specified
 147      * repository instance.
 148      * <p>Do not forget to call <code>initialize(outer,delegate)</code>
 149      * before using this object.
 150      * @param outer A pointer to the MBeanServer object that must be
 151      *        passed to the MBeans when invoking their
 152      *        {@link javax.management.MBeanRegistration} interface.
 153      * @param delegate A pointer to the MBeanServerDelegate associated
 154      *        with the new MBeanServer. The new MBeanServer must register
 155      *        this MBean in its MBean repository.
 156      * @param instantiator The MBeanInstantiator that will be used to
 157      *        instantiate MBeans and take care of class loading issues.
 158      * @param repository The repository to use for this MBeanServer.
 159      */
 160     public DefaultMBeanServerInterceptor(MBeanServer         outer,
 161                                          MBeanServerDelegate delegate,
 162                                          MBeanInstantiator   instantiator,
 163                                          Repository          repository) {
 164         if (outer == null) throw new
 165             IllegalArgumentException("outer MBeanServer cannot be null");
 166         if (delegate == null) throw new
 167             IllegalArgumentException("MBeanServerDelegate cannot be null");
 168         if (instantiator == null) throw new
 169             IllegalArgumentException("MBeanInstantiator cannot be null");
 170         if (repository == null) throw new
 171             IllegalArgumentException("Repository cannot be null");
 172 
 173         this.server   = outer;
 174         this.delegate = delegate;
 175         this.instantiator = instantiator;
 176         this.repository   = repository;
 177         this.domain       = repository.getDefaultDomain();
 178     }
 179 
 180     public ObjectInstance createMBean(String className, ObjectName name)
 181         throws ReflectionException, InstanceAlreadyExistsException,
 182                MBeanRegistrationException, MBeanException,
 183                NotCompliantMBeanException {
 184 
 185         return createMBean(className, name, (Object[]) null, (String[]) null);
 186 
 187     }
 188 
 189     public ObjectInstance createMBean(String className, ObjectName name,
 190                                       ObjectName loaderName)
 191         throws ReflectionException, InstanceAlreadyExistsException,
 192                MBeanRegistrationException, MBeanException,
 193                NotCompliantMBeanException, InstanceNotFoundException {
 194 
 195         return createMBean(className, name, loaderName, (Object[]) null,
 196                            (String[]) null);
 197     }
 198 
 199     public ObjectInstance createMBean(String className, ObjectName name,
 200                                       Object[] params, String[] signature)
 201         throws ReflectionException, InstanceAlreadyExistsException,
 202                MBeanRegistrationException, MBeanException,
 203                NotCompliantMBeanException  {
 204 
 205         try {
 206             return createMBean(className, name, null, true,
 207                                params, signature);
 208         } catch (InstanceNotFoundException e) {
 209             /* Can only happen if loaderName doesn't exist, but we just
 210                passed null, so we shouldn't get this exception.  */
 211             throw EnvHelp.initCause(
 212                 new IllegalArgumentException("Unexpected exception: " + e), e);
 213         }
 214     }
 215 
 216     public ObjectInstance createMBean(String className, ObjectName name,
 217                                       ObjectName loaderName,
 218                                       Object[] params, String[] signature)
 219         throws ReflectionException, InstanceAlreadyExistsException,
 220                MBeanRegistrationException, MBeanException,
 221                NotCompliantMBeanException, InstanceNotFoundException  {
 222 
 223         return createMBean(className, name, loaderName, false,
 224                            params, signature);
 225     }
 226 
 227     private ObjectInstance createMBean(String className, ObjectName name,
 228                                        ObjectName loaderName,
 229                                        boolean withDefaultLoaderRepository,
 230                                        Object[] params, String[] signature)
 231         throws ReflectionException, InstanceAlreadyExistsException,
 232                MBeanRegistrationException, MBeanException,
 233                NotCompliantMBeanException, InstanceNotFoundException {
 234 
 235         Class<?> theClass;
 236 
 237         if (className == null) {
 238             final RuntimeException wrapped =
 239                 new IllegalArgumentException("The class name cannot be null");
 240             throw new RuntimeOperationsException(wrapped,
 241                       "Exception occurred during MBean creation");
 242         }
 243 
 244         if (name != null) {
 245             if (name.isPattern()) {
 246                 final RuntimeException wrapped =
 247                     new IllegalArgumentException("Invalid name->" +
 248                                                  name.toString());
 249                 final String msg = "Exception occurred during MBean creation";
 250                 throw new RuntimeOperationsException(wrapped, msg);
 251             }
 252 
 253             name = nonDefaultDomain(name);
 254         }
 255 
 256         checkMBeanPermission(className, null, null, "instantiate");
 257         checkMBeanPermission(className, null, name, "registerMBean");
 258 
 259         /* Load the appropriate class. */
 260         if (withDefaultLoaderRepository) {
 261             if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
 262                 MBEANSERVER_LOGGER.logp(Level.FINER,
 263                         DefaultMBeanServerInterceptor.class.getName(),
 264                         "createMBean",
 265                         "ClassName = " + className + ", ObjectName = " + name);
 266             }
 267             theClass =
 268                 instantiator.findClassWithDefaultLoaderRepository(className);
 269         } else if (loaderName == null) {
 270             if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
 271                 MBEANSERVER_LOGGER.logp(Level.FINER,
 272                         DefaultMBeanServerInterceptor.class.getName(),
 273                         "createMBean", "ClassName = " + className +
 274                         ", ObjectName = " + name + ", Loader name = null");
 275             }
 276 
 277             theClass = instantiator.findClass(className,
 278                                   server.getClass().getClassLoader());
 279         } else {
 280             loaderName = nonDefaultDomain(loaderName);
 281 
 282             if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
 283                 MBEANSERVER_LOGGER.logp(Level.FINER,
 284                         DefaultMBeanServerInterceptor.class.getName(),
 285                         "createMBean", "ClassName = " + className +
 286                         ", ObjectName = " + name +
 287                         ", Loader name = " + loaderName);
 288             }
 289 
 290             theClass = instantiator.findClass(className, loaderName);
 291         }
 292 
 293         checkMBeanTrustPermission(theClass);
 294 
 295         // Check that the MBean can be instantiated by the MBeanServer.
 296         Introspector.testCreation(theClass);
 297 
 298         // Check the JMX MBean compliance of the class
 299         Introspector.checkCompliance(theClass);
 300 
 301         Object moi= instantiator.instantiate(theClass, params,  signature,
 302                                              server.getClass().getClassLoader());
 303 
 304         final String infoClassName = getNewMBeanClassName(moi);
 305 
 306         return registerObject(infoClassName, moi, name);
 307     }
 308 
 309     public ObjectInstance registerMBean(Object object, ObjectName name)
 310         throws InstanceAlreadyExistsException, MBeanRegistrationException,
 311         NotCompliantMBeanException  {
 312 
 313         // ------------------------------
 314         // ------------------------------
 315         Class<?> theClass = object.getClass();
 316 
 317         Introspector.checkCompliance(theClass);
 318 
 319         final String infoClassName = getNewMBeanClassName(object);
 320 
 321         checkMBeanPermission(infoClassName, null, name, "registerMBean");
 322         checkMBeanTrustPermission(theClass);
 323 
 324         return registerObject(infoClassName, object, name);
 325     }
 326 
 327     private static String getNewMBeanClassName(Object mbeanToRegister)
 328             throws NotCompliantMBeanException {
 329         if (mbeanToRegister instanceof DynamicMBean) {
 330             DynamicMBean mbean = (DynamicMBean) mbeanToRegister;
 331             final String name;
 332             try {
 333                 name = mbean.getMBeanInfo().getClassName();
 334             } catch (Exception e) {
 335                 // Includes case where getMBeanInfo() returns null
 336                 NotCompliantMBeanException ncmbe =
 337                     new NotCompliantMBeanException("Bad getMBeanInfo()");
 338                 ncmbe.initCause(e);
 339                 throw ncmbe;
 340             }
 341             if (name == null) {
 342                 final String msg = "MBeanInfo has null class name";
 343                 throw new NotCompliantMBeanException(msg);
 344             }
 345             return name;
 346         } else
 347             return mbeanToRegister.getClass().getName();
 348     }
 349 
 350     private final Set<ObjectName> beingUnregistered =
 351         new HashSet<ObjectName>();
 352 
 353     public void unregisterMBean(ObjectName name)
 354             throws InstanceNotFoundException, MBeanRegistrationException  {
 355 
 356         if (name == null) {
 357             final RuntimeException wrapped =
 358                 new IllegalArgumentException("Object name cannot be null");
 359             throw new RuntimeOperationsException(wrapped,
 360                       "Exception occurred trying to unregister the MBean");
 361         }
 362 
 363         name = nonDefaultDomain(name);
 364 
 365         /* The semantics of preDeregister are tricky.  If it throws an
 366            exception, then the unregisterMBean fails.  This allows an
 367            MBean to refuse to be unregistered.  If it returns
 368            successfully, then the unregisterMBean can proceed.  In
 369            this case the preDeregister may have cleaned up some state,
 370            and will not expect to be called a second time.  So if two
 371            threads try to unregister the same MBean at the same time
 372            then one of them must wait for the other one to either (a)
 373            call preDeregister and get an exception or (b) call
 374            preDeregister successfully and unregister the MBean.
 375            Suppose thread T1 is unregistering an MBean and thread T2
 376            is trying to unregister the same MBean, so waiting for T1.
 377            Then a deadlock is possible if the preDeregister for T1
 378            ends up needing a lock held by T2.  Given the semantics
 379            just described, there does not seem to be any way to avoid
 380            this.  This will not happen to code where it is clear for
 381            any given MBean what thread may unregister that MBean.
 382 
 383            On the other hand we clearly do not want a thread that is
 384            unregistering MBean A to have to wait for another thread
 385            that is unregistering another MBean B (see bug 6318664).  A
 386            deadlock in this situation could reasonably be considered
 387            gratuitous.  So holding a global lock across the
 388            preDeregister call would be bad.
 389 
 390            So we have a set of ObjectNames that some thread is
 391            currently unregistering.  When a thread wants to unregister
 392            a name, it must first check if the name is in the set, and
 393            if so it must wait.  When a thread successfully unregisters
 394            a name it removes the name from the set and notifies any
 395            waiting threads that the set has changed.
 396 
 397            This implies that we must be very careful to ensure that
 398            the name is removed from the set and waiters notified, no
 399            matter what code path is taken.  */
 400 
 401         synchronized (beingUnregistered) {
 402             while (beingUnregistered.contains(name)) {
 403                 try {
 404                     beingUnregistered.wait();
 405                 } catch (InterruptedException e) {
 406                     throw new MBeanRegistrationException(e, e.toString());
 407                     // pretend the exception came from preDeregister;
 408                     // in another execution sequence it could have
 409                 }
 410             }
 411             beingUnregistered.add(name);
 412         }
 413 
 414         try {
 415             exclusiveUnregisterMBean(name);
 416         } finally {
 417             synchronized (beingUnregistered) {
 418                 beingUnregistered.remove(name);
 419                 beingUnregistered.notifyAll();
 420             }
 421         }
 422     }
 423 
 424     private void exclusiveUnregisterMBean(ObjectName name)
 425             throws InstanceNotFoundException, MBeanRegistrationException {
 426 
 427         DynamicMBean instance = getMBean(name);
 428         // may throw InstanceNotFoundException
 429 
 430         checkMBeanPermission(instance, null, name, "unregisterMBean");
 431 
 432         if (instance instanceof MBeanRegistration)
 433             preDeregisterInvoke((MBeanRegistration) instance);
 434 
 435         final Object resource = getResource(instance);
 436 
 437         // Unregisters the MBean from the repository.
 438         // Returns the resource context that was used.
 439         // The returned context does nothing for regular MBeans.
 440         // For ClassLoader MBeans and JMXNamespace (and JMXDomain)
 441         // MBeans - the context makes it possible to unregister these
 442         // objects from the appropriate framework artifacts, such as
 443         // the CLR or the dispatcher, from within the repository lock.
 444         // In case of success, we also need to call context.done() at the
 445         // end of this method.
 446         //
 447         final ResourceContext context =
 448                 unregisterFromRepository(resource, instance, name);
 449 
 450         try {
 451             if (instance instanceof MBeanRegistration)
 452                 postDeregisterInvoke(name,(MBeanRegistration) instance);
 453         } finally {
 454             context.done();
 455         }
 456     }
 457 
 458     public ObjectInstance getObjectInstance(ObjectName name)
 459             throws InstanceNotFoundException {
 460 
 461         name = nonDefaultDomain(name);
 462         DynamicMBean instance = getMBean(name);
 463 
 464         checkMBeanPermission(instance, null, name, "getObjectInstance");
 465 
 466         final String className = getClassName(instance);
 467 
 468         return new ObjectInstance(name, className);
 469     }
 470 
 471     public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
 472         SecurityManager sm = System.getSecurityManager();
 473         if (sm != null) {
 474             // Check if the caller has the right to invoke 'queryMBeans'
 475             //
 476             checkMBeanPermission((String) null, null, null, "queryMBeans");
 477 
 478             // Perform query without "query".
 479             //
 480             Set<ObjectInstance> list = queryMBeansImpl(name, null);
 481 
 482             // Check if the caller has the right to invoke 'queryMBeans'
 483             // on each specific classname/objectname in the list.
 484             //
 485             Set<ObjectInstance> allowedList =
 486                 new HashSet<ObjectInstance>(list.size());
 487             for (ObjectInstance oi : list) {
 488                 try {
 489                     checkMBeanPermission(oi.getClassName(), null,
 490                                          oi.getObjectName(), "queryMBeans");
 491                     allowedList.add(oi);
 492                 } catch (SecurityException e) {
 493                     // OK: Do not add this ObjectInstance to the list
 494                 }
 495             }
 496 
 497             // Apply query to allowed MBeans only.
 498             //
 499             return filterListOfObjectInstances(allowedList, query);
 500         } else {
 501             // Perform query.
 502             //
 503             return queryMBeansImpl(name, query);
 504         }
 505     }
 506 
 507     private Set<ObjectInstance> queryMBeansImpl(ObjectName name,
 508                                                 QueryExp query) {
 509         // Query the MBeans on the repository
 510         //
 511         Set<NamedObject> list = repository.query(name, query);
 512 
 513         return (objectInstancesFromFilteredNamedObjects(list, query));
 514     }
 515 
 516     public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
 517         Set<ObjectName> queryList;
 518         SecurityManager sm = System.getSecurityManager();
 519         if (sm != null) {
 520             // Check if the caller has the right to invoke 'queryNames'
 521             //
 522             checkMBeanPermission((String) null, null, null, "queryNames");
 523 
 524             // Perform query without "query".
 525             //
 526             Set<ObjectInstance> list = queryMBeansImpl(name, null);
 527 
 528             // Check if the caller has the right to invoke 'queryNames'
 529             // on each specific classname/objectname in the list.
 530             //
 531             Set<ObjectInstance> allowedList =
 532                 new HashSet<ObjectInstance>(list.size());
 533             for (ObjectInstance oi : list) {
 534                 try {
 535                     checkMBeanPermission(oi.getClassName(), null,
 536                                          oi.getObjectName(), "queryNames");
 537                     allowedList.add(oi);
 538                 } catch (SecurityException e) {
 539                     // OK: Do not add this ObjectInstance to the list
 540                 }
 541             }
 542 
 543             // Apply query to allowed MBeans only.
 544             //
 545             Set<ObjectInstance> queryObjectInstanceList =
 546                 filterListOfObjectInstances(allowedList, query);
 547             queryList = new HashSet<ObjectName>(queryObjectInstanceList.size());
 548             for (ObjectInstance oi : queryObjectInstanceList) {
 549                 queryList.add(oi.getObjectName());
 550             }
 551         } else {
 552             // Perform query.
 553             //
 554             queryList = queryNamesImpl(name, query);
 555         }
 556         return queryList;
 557     }
 558 
 559     private Set<ObjectName> queryNamesImpl(ObjectName name, QueryExp query) {
 560         // Query the MBeans on the repository
 561         //
 562         Set<NamedObject> list = repository.query(name, query);
 563 
 564         return (objectNamesFromFilteredNamedObjects(list, query));
 565     }
 566 
 567     public boolean isRegistered(ObjectName name) {
 568         if (name == null) {
 569             throw new RuntimeOperationsException(
 570                      new IllegalArgumentException("Object name cannot be null"),
 571                      "Object name cannot be null");
 572         }
 573 
 574         name = nonDefaultDomain(name);
 575 
 576         /* No Permission check */
 577         // isRegistered is always unchecked as per JMX spec.
 578 
 579         return (repository.contains(name));
 580     }
 581 
 582     public String[] getDomains()  {
 583         SecurityManager sm = System.getSecurityManager();
 584         if (sm != null) {
 585             // Check if the caller has the right to invoke 'getDomains'
 586             //
 587             checkMBeanPermission((String) null, null, null, "getDomains");
 588 
 589             // Return domains
 590             //
 591             String[] domains = repository.getDomains();
 592 
 593             // Check if the caller has the right to invoke 'getDomains'
 594             // on each specific domain in the list.
 595             //
 596             List<String> result = new ArrayList<String>(domains.length);
 597             for (int i = 0; i < domains.length; i++) {
 598                 try {
 599                     ObjectName dom = Util.newObjectName(domains[i] + ":x=x");
 600                     checkMBeanPermission((String) null, null, dom, "getDomains");
 601                     result.add(domains[i]);
 602                 } catch (SecurityException e) {
 603                     // OK: Do not add this domain to the list
 604                 }
 605             }
 606 
 607             // Make an array from result.
 608             //
 609             return result.toArray(new String[result.size()]);
 610         } else {
 611             return repository.getDomains();
 612         }
 613     }
 614 
 615     public Integer getMBeanCount() {
 616         return (repository.getCount());
 617     }
 618 
 619     public Object getAttribute(ObjectName name, String attribute)
 620         throws MBeanException, AttributeNotFoundException,
 621                InstanceNotFoundException, ReflectionException {
 622 
 623         if (name == null) {
 624             throw new RuntimeOperationsException(new
 625                 IllegalArgumentException("Object name cannot be null"),
 626                 "Exception occurred trying to invoke the getter on the MBean");
 627         }
 628         if (attribute == null) {
 629             throw new RuntimeOperationsException(new
 630                 IllegalArgumentException("Attribute cannot be null"),
 631                 "Exception occurred trying to invoke the getter on the MBean");
 632         }
 633 
 634         name = nonDefaultDomain(name);
 635 
 636         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
 637             MBEANSERVER_LOGGER.logp(Level.FINER,
 638                     DefaultMBeanServerInterceptor.class.getName(),
 639                     "getAttribute",
 640                     "Attribute = " + attribute + ", ObjectName = " + name);
 641         }
 642 
 643         final DynamicMBean instance = getMBean(name);
 644         checkMBeanPermission(instance, attribute, name, "getAttribute");
 645 
 646         try {
 647             return instance.getAttribute(attribute);
 648         } catch (AttributeNotFoundException e) {
 649             throw e;
 650         } catch (Throwable t) {
 651             rethrowMaybeMBeanException(t);
 652             throw new AssertionError(); // not reached
 653         }
 654     }
 655 
 656     public AttributeList getAttributes(ObjectName name, String[] attributes)
 657         throws InstanceNotFoundException, ReflectionException  {
 658 
 659         if (name == null) {
 660             throw new RuntimeOperationsException(new
 661                 IllegalArgumentException("ObjectName name cannot be null"),
 662                 "Exception occurred trying to invoke the getter on the MBean");
 663         }
 664 
 665         if (attributes == null) {
 666             throw new RuntimeOperationsException(new
 667                 IllegalArgumentException("Attributes cannot be null"),
 668                 "Exception occurred trying to invoke the getter on the MBean");
 669         }
 670 
 671         name = nonDefaultDomain(name);
 672 
 673         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
 674             MBEANSERVER_LOGGER.logp(Level.FINER,
 675                     DefaultMBeanServerInterceptor.class.getName(),
 676                     "getAttributes", "ObjectName = " + name);
 677         }
 678 
 679         final DynamicMBean instance = getMBean(name);
 680         final String[] allowedAttributes;
 681         final SecurityManager sm = System.getSecurityManager();
 682         if (sm == null)
 683             allowedAttributes = attributes;
 684         else {
 685             final String classname = getClassName(instance);
 686 
 687             // Check if the caller has the right to invoke 'getAttribute'
 688             //
 689             checkMBeanPermission(classname, null, name, "getAttribute");
 690 
 691             // Check if the caller has the right to invoke 'getAttribute'
 692             // on each specific attribute
 693             //
 694             List<String> allowedList =
 695                 new ArrayList<String>(attributes.length);
 696             for (String attr : attributes) {
 697                 try {
 698                     checkMBeanPermission(classname, attr, name, "getAttribute");
 699                     allowedList.add(attr);
 700                 } catch (SecurityException e) {
 701                     // OK: Do not add this attribute to the list
 702                 }
 703             }
 704             allowedAttributes =
 705                     allowedList.toArray(new String[allowedList.size()]);
 706         }
 707 
 708         try {
 709             return instance.getAttributes(allowedAttributes);
 710         } catch (Throwable t) {
 711             rethrow(t);
 712             throw new AssertionError();
 713         }
 714     }
 715 
 716     public void setAttribute(ObjectName name, Attribute attribute)
 717         throws InstanceNotFoundException, AttributeNotFoundException,
 718                InvalidAttributeValueException, MBeanException,
 719                ReflectionException  {
 720 
 721         if (name == null) {
 722             throw new RuntimeOperationsException(new
 723                 IllegalArgumentException("ObjectName name cannot be null"),
 724                 "Exception occurred trying to invoke the setter on the MBean");
 725         }
 726 
 727         if (attribute == null) {
 728             throw new RuntimeOperationsException(new
 729                 IllegalArgumentException("Attribute cannot be null"),
 730                 "Exception occurred trying to invoke the setter on the MBean");
 731         }
 732 
 733         name = nonDefaultDomain(name);
 734 
 735         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
 736             MBEANSERVER_LOGGER.logp(Level.FINER,
 737                     DefaultMBeanServerInterceptor.class.getName(),
 738                     "setAttribute", "ObjectName = " + name +
 739                     ", Attribute = " + attribute.getName());
 740         }
 741 
 742         DynamicMBean instance = getMBean(name);
 743         checkMBeanPermission(instance, attribute.getName(), name, "setAttribute");
 744 
 745         try {
 746             instance.setAttribute(attribute);
 747         } catch (AttributeNotFoundException e) {
 748             throw e;
 749         } catch (InvalidAttributeValueException e) {
 750             throw e;
 751         } catch (Throwable t) {
 752             rethrowMaybeMBeanException(t);
 753             throw new AssertionError();
 754         }
 755     }
 756 
 757     public AttributeList setAttributes(ObjectName name,
 758                                        AttributeList attributes)
 759             throws InstanceNotFoundException, ReflectionException  {
 760 
 761         if (name == null) {
 762             throw new RuntimeOperationsException(new
 763                 IllegalArgumentException("ObjectName name cannot be null"),
 764                 "Exception occurred trying to invoke the setter on the MBean");
 765         }
 766 
 767         if (attributes == null) {
 768             throw new RuntimeOperationsException(new
 769             IllegalArgumentException("AttributeList  cannot be null"),
 770             "Exception occurred trying to invoke the setter on the MBean");
 771         }
 772 
 773         name = nonDefaultDomain(name);
 774 
 775         final DynamicMBean instance = getMBean(name);
 776         final AttributeList allowedAttributes;
 777         final SecurityManager sm = System.getSecurityManager();
 778         if (sm == null)
 779             allowedAttributes = attributes;
 780         else {
 781             String classname = getClassName(instance);
 782 
 783             // Check if the caller has the right to invoke 'setAttribute'
 784             //
 785             checkMBeanPermission(classname, null, name, "setAttribute");
 786 
 787             // Check if the caller has the right to invoke 'setAttribute'
 788             // on each specific attribute
 789             //
 790             allowedAttributes = new AttributeList(attributes.size());
 791             for (Attribute attribute : attributes.asList()) {
 792                 try {
 793                     checkMBeanPermission(classname, attribute.getName(),
 794                                          name, "setAttribute");
 795                     allowedAttributes.add(attribute);
 796                 } catch (SecurityException e) {
 797                     // OK: Do not add this attribute to the list
 798                 }
 799             }
 800         }
 801         try {
 802             return instance.setAttributes(allowedAttributes);
 803         } catch (Throwable t) {
 804             rethrow(t);
 805             throw new AssertionError();
 806         }
 807     }
 808 
 809     public Object invoke(ObjectName name, String operationName,
 810                          Object params[], String signature[])
 811             throws InstanceNotFoundException, MBeanException,
 812                    ReflectionException {
 813 
 814         name = nonDefaultDomain(name);
 815 
 816         DynamicMBean instance = getMBean(name);
 817         checkMBeanPermission(instance, operationName, name, "invoke");
 818         try {
 819             return instance.invoke(operationName, params, signature);
 820         } catch (Throwable t) {
 821             rethrowMaybeMBeanException(t);
 822             throw new AssertionError();
 823         }
 824     }
 825 
 826     /* Centralize some of the tedious exception wrapping demanded by the JMX
 827        spec. */
 828     private static void rethrow(Throwable t)
 829             throws ReflectionException {
 830         try {
 831             throw t;
 832         } catch (ReflectionException e) {
 833             throw e;
 834         } catch (RuntimeOperationsException e) {
 835             throw e;
 836         } catch (RuntimeErrorException e) {
 837             throw e;
 838         } catch (RuntimeException e) {
 839             throw new RuntimeMBeanException(e, e.toString());
 840         } catch (Error e) {
 841             throw new RuntimeErrorException(e, e.toString());
 842         } catch (Throwable t2) {
 843             // should not happen
 844             throw new RuntimeException("Unexpected exception", t2);
 845         }
 846     }
 847 
 848     private static void rethrowMaybeMBeanException(Throwable t)
 849             throws ReflectionException, MBeanException {
 850         if (t instanceof MBeanException)
 851             throw (MBeanException) t;
 852         rethrow(t);
 853     }
 854 
 855     /**
 856      * Register <code>object</code> in the repository, with the
 857      * given <code>name</code>.
 858      * This method is called by the various createMBean() flavours
 859      * and by registerMBean() after all MBean compliance tests
 860      * have been performed.
 861      * <p>
 862      * This method does not performed any kind of test compliance,
 863      * and the caller should make sure that the given <code>object</code>
 864      * is MBean compliant.
 865      * <p>
 866      * This methods performed all the basic steps needed for object
 867      * registration:
 868      * <ul>
 869      * <li>If the <code>object</code> implements the MBeanRegistration
 870      *     interface, it invokes preRegister() on the object.</li>
 871      * <li>Then the object is added to the repository with the given
 872      *     <code>name</code>.</li>
 873      * <li>Finally, if the <code>object</code> implements the
 874      *     MBeanRegistration interface, it invokes postRegister()
 875      *     on the object.</li>
 876      * </ul>
 877      * @param object A reference to a MBean compliant object.
 878      * @param name   The ObjectName of the <code>object</code> MBean.
 879      * @return the actual ObjectName with which the object was registered.
 880      * @exception InstanceAlreadyExistsException if an object is already
 881      *            registered with that name.
 882      * @exception MBeanRegistrationException if an exception occurs during
 883      *            registration.
 884      **/
 885     private ObjectInstance registerObject(String classname,
 886                                           Object object, ObjectName name)
 887         throws InstanceAlreadyExistsException,
 888                MBeanRegistrationException,
 889                NotCompliantMBeanException {
 890 
 891         if (object == null) {
 892             final RuntimeException wrapped =
 893                 new IllegalArgumentException("Cannot add null object");
 894             throw new RuntimeOperationsException(wrapped,
 895                         "Exception occurred trying to register the MBean");
 896         }
 897 
 898         DynamicMBean mbean = Introspector.makeDynamicMBean(object);
 899 
 900         return registerDynamicMBean(classname, mbean, name);
 901     }
 902 
 903     private ObjectInstance registerDynamicMBean(String classname,
 904                                                 DynamicMBean mbean,
 905                                                 ObjectName name)
 906         throws InstanceAlreadyExistsException,
 907                MBeanRegistrationException,
 908                NotCompliantMBeanException {
 909 
 910 
 911         name = nonDefaultDomain(name);
 912 
 913         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
 914             MBEANSERVER_LOGGER.logp(Level.FINER,
 915                     DefaultMBeanServerInterceptor.class.getName(),
 916                     "registerMBean", "ObjectName = " + name);
 917         }
 918 
 919         ObjectName logicalName = preRegister(mbean, server, name);
 920 
 921         // preRegister returned successfully, so from this point on we
 922         // must call postRegister(false) if there is any problem.
 923         boolean registered = false;
 924         boolean registerFailed = false;
 925         ResourceContext context = null;
 926 
 927         try {
 928             if (mbean instanceof DynamicMBean2) {
 929                 try {
 930                     ((DynamicMBean2) mbean).preRegister2(server, logicalName);
 931                     registerFailed = true;  // until we succeed
 932                 } catch (Exception e) {
 933                     if (e instanceof RuntimeException)
 934                         throw (RuntimeException) e;
 935                     if (e instanceof InstanceAlreadyExistsException)
 936                         throw (InstanceAlreadyExistsException) e;
 937                     throw new RuntimeException(e);
 938                 }
 939             }
 940 
 941             if (logicalName != name && logicalName != null) {
 942                 logicalName =
 943                         ObjectName.getInstance(nonDefaultDomain(logicalName));
 944             }
 945 
 946             checkMBeanPermission(classname, null, logicalName, "registerMBean");
 947 
 948             if (logicalName == null) {
 949                 final RuntimeException wrapped =
 950                     new IllegalArgumentException("No object name specified");
 951                 throw new RuntimeOperationsException(wrapped,
 952                             "Exception occurred trying to register the MBean");
 953             }
 954 
 955             final Object resource = getResource(mbean);
 956 
 957             // Register the MBean with the repository.
 958             // Returns the resource context that was used.
 959             // The returned context does nothing for regular MBeans.
 960             // For ClassLoader MBeans the context makes it possible to register these
 961             // objects with the appropriate framework artifacts, such as
 962             // the CLR, from within the repository lock.
 963             // In case of success, we also need to call context.done() at the
 964             // end of this method.
 965             //
 966             context = registerWithRepository(resource, mbean, logicalName);
 967 
 968 
 969             registerFailed = false;
 970             registered = true;
 971 
 972         } finally {
 973             try {
 974                 postRegister(logicalName, mbean, registered, registerFailed);
 975             } finally {
 976                 if (registered && context!=null) context.done();
 977             }
 978         }
 979         return new ObjectInstance(logicalName, classname);
 980     }
 981 
 982     private static void throwMBeanRegistrationException(Throwable t, String where)
 983     throws MBeanRegistrationException {
 984         if (t instanceof RuntimeException) {
 985             throw new RuntimeMBeanException((RuntimeException)t,
 986                     "RuntimeException thrown " + where);
 987         } else if (t instanceof Error) {
 988             throw new RuntimeErrorException((Error)t,
 989                     "Error thrown " + where);
 990         } else if (t instanceof MBeanRegistrationException) {
 991             throw (MBeanRegistrationException)t;
 992         } else if (t instanceof Exception) {
 993             throw new MBeanRegistrationException((Exception)t,
 994                     "Exception thrown " + where);
 995         } else // neither Error nor Exception??
 996             throw new RuntimeException(t);
 997     }
 998 
 999     private static ObjectName preRegister(
1000             DynamicMBean mbean, MBeanServer mbs, ObjectName name)
1001             throws InstanceAlreadyExistsException, MBeanRegistrationException {
1002 
1003         ObjectName newName = null;
1004 
1005         try {
1006             if (mbean instanceof MBeanRegistration)
1007                 newName = ((MBeanRegistration) mbean).preRegister(mbs, name);
1008         } catch (Throwable t) {
1009             throwMBeanRegistrationException(t, "in preRegister method");
1010         }
1011 
1012         if (newName != null) return newName;
1013         else return name;
1014     }
1015 
1016     private static void postRegister(
1017             ObjectName logicalName, DynamicMBean mbean,
1018             boolean registrationDone, boolean registerFailed) {
1019 
1020         if (registerFailed && mbean instanceof DynamicMBean2)
1021             ((DynamicMBean2) mbean).registerFailed();
1022         try {
1023             if (mbean instanceof MBeanRegistration)
1024                 ((MBeanRegistration) mbean).postRegister(registrationDone);
1025         } catch (RuntimeException e) {
1026             MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+
1027                     "]: " + "Exception thrown by postRegister: " +
1028                     "rethrowing <"+e+">, but keeping the MBean registered");
1029             throw new RuntimeMBeanException(e,
1030                       "RuntimeException thrown in postRegister method: "+
1031                       "rethrowing <"+e+">, but keeping the MBean registered");
1032         } catch (Error er) {
1033             MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+
1034                     "]: " + "Error thrown by postRegister: " +
1035                     "rethrowing <"+er+">, but keeping the MBean registered");
1036             throw new RuntimeErrorException(er,
1037                       "Error thrown in postRegister method: "+
1038                       "rethrowing <"+er+">, but keeping the MBean registered");
1039         }
1040     }
1041 
1042     private static void preDeregisterInvoke(MBeanRegistration moi)
1043             throws MBeanRegistrationException {
1044         try {
1045             moi.preDeregister();
1046         } catch (Throwable t) {
1047             throwMBeanRegistrationException(t, "in preDeregister method");
1048         }
1049     }
1050 
1051     private static void postDeregisterInvoke(ObjectName mbean,
1052             MBeanRegistration moi) {
1053         try {
1054             moi.postDeregister();
1055         } catch (RuntimeException e) {
1056             MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+
1057                     "]: " + "Exception thrown by postDeregister: " +
1058                     "rethrowing <"+e+">, although the MBean is succesfully " +
1059                     "unregistered");
1060             throw new RuntimeMBeanException(e,
1061                       "RuntimeException thrown in postDeregister method: "+
1062                       "rethrowing <"+e+
1063                       ">, although the MBean is sucessfully unregistered");
1064         } catch (Error er) {
1065             MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+
1066                     "]: " + "Error thrown by postDeregister: " +
1067                     "rethrowing <"+er+">, although the MBean is succesfully " +
1068                     "unregistered");
1069             throw new RuntimeErrorException(er,
1070                       "Error thrown in postDeregister method: "+
1071                       "rethrowing <"+er+
1072                       ">, although the MBean is sucessfully unregistered");
1073         }
1074     }
1075 
1076     /**
1077      * Gets a specific MBean controlled by the DefaultMBeanServerInterceptor.
1078      * The name must have a non-default domain.
1079      */
1080     private DynamicMBean getMBean(ObjectName name)
1081         throws InstanceNotFoundException {
1082 
1083         if (name == null) {
1084             throw new RuntimeOperationsException(new
1085                 IllegalArgumentException("Object name cannot be null"),
1086                                "Exception occurred trying to get an MBean");
1087         }
1088         DynamicMBean obj = repository.retrieve(name);
1089         if (obj == null) {
1090             if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1091                 MBEANSERVER_LOGGER.logp(Level.FINER,
1092                         DefaultMBeanServerInterceptor.class.getName(),
1093                         "getMBean", name + " : Found no object");
1094             }
1095             throw new InstanceNotFoundException(name.toString());
1096         }
1097         return obj;
1098     }
1099 
1100     private static Object getResource(DynamicMBean mbean) {
1101         if (mbean instanceof DynamicMBean2)
1102             return ((DynamicMBean2) mbean).getResource();
1103         else
1104             return mbean;
1105     }
1106 
1107     private ObjectName nonDefaultDomain(ObjectName name) {
1108         if (name == null || name.getDomain().length() > 0)
1109             return name;
1110 
1111         /* The ObjectName looks like ":a=b", and that's what its
1112            toString() will return in this implementation.  So
1113            we can just stick the default domain in front of it
1114            to get a non-default-domain name.  We depend on the
1115            fact that toString() works like that and that it
1116            leaves wildcards in place (so we can detect an error
1117            if one is supplied where it shouldn't be).  */
1118         final String completeName = domain + name;
1119 
1120         return Util.newObjectName(completeName);
1121     }
1122 
1123     public String getDefaultDomain()  {
1124         return domain;
1125     }
1126 
1127     /*
1128      * Notification handling.
1129      *
1130      * This is not trivial, because the MBeanServer translates the
1131      * source of a received notification from a reference to an MBean
1132      * into the ObjectName of that MBean.  While that does make
1133      * notification sending easier for MBean writers, it comes at a
1134      * considerable cost.  We need to replace the source of a
1135      * notification, which is basically wrong if there are also
1136      * listeners registered directly with the MBean (without going
1137      * through the MBean server).  We also need to wrap the listener
1138      * supplied by the client of the MBeanServer with a listener that
1139      * performs the substitution before forwarding.  This is why we
1140      * strongly discourage people from putting MBean references in the
1141      * source of their notifications.  Instead they should arrange to
1142      * put the ObjectName there themselves.
1143      *
1144      * However, existing code relies on the substitution, so we are
1145      * stuck with it.
1146      *
1147      * Here's how we handle it.  When you add a listener, we make a
1148      * ListenerWrapper around it.  We look that up in the
1149      * listenerWrappers map, and if there was already a wrapper for
1150      * that listener with the given ObjectName, we reuse it.  This map
1151      * is a WeakHashMap, so a listener that is no longer registered
1152      * with any MBean can be garbage collected.
1153      *
1154      * We cannot use simpler solutions such as always creating a new
1155      * wrapper or always registering the same listener with the MBean
1156      * and using the handback to find the client's original listener.
1157      * The reason is that we need to support the removeListener
1158      * variant that removes all (listener,filter,handback) triples on
1159      * a broadcaster that have a given listener.  And we do not have
1160      * any way to inspect a broadcaster's internal list of triples.
1161      * So the same client listener must always map to the same
1162      * listener registered with the broadcaster.
1163      *
1164      * Another possible solution would be to map from ObjectName to
1165      * list of listener wrappers (or IdentityHashMap of listener
1166      * wrappers), making this list the first time a listener is added
1167      * on a given MBean, and removing it when the MBean is removed.
1168      * This is probably more costly in memory, but could be useful if
1169      * some day we don't want to rely on weak references.
1170      */
1171     public void addNotificationListener(ObjectName name,
1172                                         NotificationListener listener,
1173                                         NotificationFilter filter,
1174                                         Object handback)
1175             throws InstanceNotFoundException {
1176 
1177         // ------------------------------
1178         // ------------------------------
1179         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1180             MBEANSERVER_LOGGER.logp(Level.FINER,
1181                     DefaultMBeanServerInterceptor.class.getName(),
1182                     "addNotificationListener", "ObjectName = " + name);
1183         }
1184 
1185         DynamicMBean instance = getMBean(name);
1186         checkMBeanPermission(instance, null, name, "addNotificationListener");
1187 
1188         NotificationBroadcaster broadcaster =
1189                 getNotificationBroadcaster(name, instance,
1190                                            NotificationBroadcaster.class);
1191 
1192         // ------------------
1193         // Check listener
1194         // ------------------
1195         if (listener == null) {
1196             throw new RuntimeOperationsException(new
1197                 IllegalArgumentException("Null listener"),"Null listener");
1198         }
1199 
1200         NotificationListener listenerWrapper =
1201             getListenerWrapper(listener, name, instance, true);
1202         broadcaster.addNotificationListener(listenerWrapper, filter, handback);
1203     }
1204 
1205     public void addNotificationListener(ObjectName name,
1206                                         ObjectName listener,
1207                                         NotificationFilter filter,
1208                                         Object handback)
1209             throws InstanceNotFoundException {
1210 
1211         // ------------------------------
1212         // ------------------------------
1213 
1214         // ----------------
1215         // Get listener object
1216         // ----------------
1217         DynamicMBean instance = getMBean(listener);
1218         Object resource = getResource(instance);
1219         if (!(resource instanceof NotificationListener)) {
1220             throw new RuntimeOperationsException(new
1221                 IllegalArgumentException(listener.getCanonicalName()),
1222                 "The MBean " + listener.getCanonicalName() +
1223                 "does not implement the NotificationListener interface") ;
1224         }
1225 
1226         // ----------------
1227         // Add a listener on an MBean
1228         // ----------------
1229         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1230             MBEANSERVER_LOGGER.logp(Level.FINER,
1231                     DefaultMBeanServerInterceptor.class.getName(),
1232                     "addNotificationListener",
1233                     "ObjectName = " + name + ", Listener = " + listener);
1234         }
1235         server.addNotificationListener(name,(NotificationListener) resource,
1236                                        filter, handback) ;
1237     }
1238 
1239     public void removeNotificationListener(ObjectName name,
1240                                            NotificationListener listener)
1241             throws InstanceNotFoundException, ListenerNotFoundException {
1242         removeNotificationListener(name, listener, null, null, true);
1243     }
1244 
1245     public void removeNotificationListener(ObjectName name,
1246                                            NotificationListener listener,
1247                                            NotificationFilter filter,
1248                                            Object handback)
1249             throws InstanceNotFoundException, ListenerNotFoundException {
1250         removeNotificationListener(name, listener, filter, handback, false);
1251     }
1252 
1253     public void removeNotificationListener(ObjectName name,
1254                                            ObjectName listener)
1255             throws InstanceNotFoundException, ListenerNotFoundException {
1256         NotificationListener instance = getListener(listener);
1257 
1258         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1259             MBEANSERVER_LOGGER.logp(Level.FINER,
1260                     DefaultMBeanServerInterceptor.class.getName(),
1261                     "removeNotificationListener",
1262                     "ObjectName = " + name + ", Listener = " + listener);
1263         }
1264         server.removeNotificationListener(name, instance);
1265     }
1266 
1267     public void removeNotificationListener(ObjectName name,
1268                                            ObjectName listener,
1269                                            NotificationFilter filter,
1270                                            Object handback)
1271             throws InstanceNotFoundException, ListenerNotFoundException {
1272 
1273         NotificationListener instance = getListener(listener);
1274 
1275         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1276             MBEANSERVER_LOGGER.logp(Level.FINER,
1277                     DefaultMBeanServerInterceptor.class.getName(),
1278                     "removeNotificationListener",
1279                     "ObjectName = " + name + ", Listener = " + listener);
1280         }
1281         server.removeNotificationListener(name, instance, filter, handback);
1282     }
1283 
1284     private NotificationListener getListener(ObjectName listener)
1285         throws ListenerNotFoundException {
1286         // ----------------
1287         // Get listener object
1288         // ----------------
1289         DynamicMBean instance;
1290         try {
1291             instance = getMBean(listener);
1292         } catch (InstanceNotFoundException e) {
1293             throw EnvHelp.initCause(
1294                           new ListenerNotFoundException(e.getMessage()), e);
1295         }
1296 
1297         Object resource = getResource(instance);
1298         if (!(resource instanceof NotificationListener)) {
1299             final RuntimeException exc =
1300                 new IllegalArgumentException(listener.getCanonicalName());
1301             final String msg =
1302                 "MBean " + listener.getCanonicalName() + " does not " +
1303                 "implement " + NotificationListener.class.getName();
1304             throw new RuntimeOperationsException(exc, msg);
1305         }
1306         return (NotificationListener) resource;
1307     }
1308 
1309     private void removeNotificationListener(ObjectName name,
1310                                             NotificationListener listener,
1311                                             NotificationFilter filter,
1312                                             Object handback,
1313                                             boolean removeAll)
1314             throws InstanceNotFoundException, ListenerNotFoundException {
1315 
1316         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1317             MBEANSERVER_LOGGER.logp(Level.FINER,
1318                     DefaultMBeanServerInterceptor.class.getName(),
1319                     "removeNotificationListener", "ObjectName = " + name);
1320         }
1321 
1322         DynamicMBean instance = getMBean(name);
1323         checkMBeanPermission(instance, null, name, "removeNotificationListener");
1324 
1325         /* We could simplify the code by assigning broadcaster after
1326            assigning listenerWrapper, but that would change the error
1327            behavior when both the broadcaster and the listener are
1328            erroneous.  */
1329 
1330         Class<? extends NotificationBroadcaster> reqClass =
1331             removeAll ? NotificationBroadcaster.class : NotificationEmitter.class;
1332         NotificationBroadcaster broadcaster =
1333             getNotificationBroadcaster(name, instance, reqClass);
1334 
1335         NotificationListener listenerWrapper =
1336             getListenerWrapper(listener, name, instance, false);
1337 
1338         if (listenerWrapper == null)
1339             throw new ListenerNotFoundException("Unknown listener");
1340 
1341         if (removeAll)
1342             broadcaster.removeNotificationListener(listenerWrapper);
1343         else {
1344             NotificationEmitter emitter = (NotificationEmitter) broadcaster;
1345             emitter.removeNotificationListener(listenerWrapper,
1346                                                filter,
1347                                                handback);
1348         }
1349     }
1350 
1351     private static <T extends NotificationBroadcaster>
1352             T getNotificationBroadcaster(ObjectName name, Object instance,
1353                                          Class<T> reqClass) {
1354         if (reqClass.isInstance(instance))
1355             return reqClass.cast(instance);
1356         if (instance instanceof DynamicMBean2)
1357             instance = ((DynamicMBean2) instance).getResource();
1358         if (reqClass.isInstance(instance))
1359             return reqClass.cast(instance);
1360         final RuntimeException exc =
1361             new IllegalArgumentException(name.getCanonicalName());
1362         final String msg =
1363             "MBean " + name.getCanonicalName() + " does not " +
1364             "implement " + reqClass.getName();
1365         throw new RuntimeOperationsException(exc, msg);
1366     }
1367 
1368     public MBeanInfo getMBeanInfo(ObjectName name)
1369         throws InstanceNotFoundException, IntrospectionException,
1370                ReflectionException {
1371 
1372         // ------------------------------
1373         // ------------------------------
1374 
1375         DynamicMBean moi = getMBean(name);
1376         final MBeanInfo mbi;
1377         try {
1378             mbi = moi.getMBeanInfo();
1379         } catch (RuntimeMBeanException e) {
1380             throw e;
1381         } catch (RuntimeErrorException e) {
1382             throw e;
1383         } catch (RuntimeException e) {
1384             throw new RuntimeMBeanException(e,
1385                     "getMBeanInfo threw RuntimeException");
1386         } catch (Error e) {
1387             throw new RuntimeErrorException(e, "getMBeanInfo threw Error");
1388         }
1389         if (mbi == null)
1390             throw new JMRuntimeException("MBean " + name +
1391                                          "has no MBeanInfo");
1392 
1393         checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo");
1394 
1395         return mbi;
1396     }
1397 
1398     public boolean isInstanceOf(ObjectName name, String className)
1399         throws InstanceNotFoundException {
1400 
1401         final DynamicMBean instance = getMBean(name);
1402         checkMBeanPermission(instance, null, name, "isInstanceOf");
1403 
1404         try {
1405             Object resource = getResource(instance);
1406 
1407             final String resourceClassName =
1408                     (resource instanceof DynamicMBean) ?
1409                         getClassName((DynamicMBean) resource) :
1410                         resource.getClass().getName();
1411 
1412             if (resourceClassName.equals(className))
1413                 return true;
1414             final ClassLoader cl = resource.getClass().getClassLoader();
1415 
1416             final Class<?> classNameClass = Class.forName(className, false, cl);
1417             if (classNameClass.isInstance(resource))
1418                 return true;
1419 
1420             final Class<?> resourceClass = Class.forName(resourceClassName, false, cl);
1421             return classNameClass.isAssignableFrom(resourceClass);
1422         } catch (Exception x) {
1423             /* Could be SecurityException or ClassNotFoundException */
1424             if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
1425                 MBEANSERVER_LOGGER.logp(Level.FINEST,
1426                         DefaultMBeanServerInterceptor.class.getName(),
1427                         "isInstanceOf", "Exception calling isInstanceOf", x);
1428             }
1429             return false;
1430         }
1431 
1432     }
1433 
1434     /**
1435      * <p>Return the {@link java.lang.ClassLoader} that was used for
1436      * loading the class of the named MBean.
1437      * @param mbeanName The ObjectName of the MBean.
1438      * @return The ClassLoader used for that MBean.
1439      * @exception InstanceNotFoundException if the named MBean is not found.
1440      */
1441     public ClassLoader getClassLoaderFor(ObjectName mbeanName)
1442         throws InstanceNotFoundException {
1443 
1444         DynamicMBean instance = getMBean(mbeanName);
1445         checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor");
1446         return getResource(instance).getClass().getClassLoader();
1447     }
1448 
1449     /**
1450      * <p>Return the named {@link java.lang.ClassLoader}.
1451      * @param loaderName The ObjectName of the ClassLoader.
1452      * @return The named ClassLoader.
1453      * @exception InstanceNotFoundException if the named ClassLoader
1454      * is not found.
1455      */
1456     public ClassLoader getClassLoader(ObjectName loaderName)
1457             throws InstanceNotFoundException {
1458 
1459         if (loaderName == null) {
1460             checkMBeanPermission((String) null, null, null, "getClassLoader");
1461             return server.getClass().getClassLoader();
1462         }
1463 
1464         DynamicMBean instance = getMBean(loaderName);
1465         checkMBeanPermission(instance, null, loaderName, "getClassLoader");
1466 
1467         Object resource = getResource(instance);
1468 
1469         /* Check if the given MBean is a ClassLoader */
1470         if (!(resource instanceof ClassLoader))
1471             throw new InstanceNotFoundException(loaderName.toString() +
1472                                                 " is not a classloader");
1473 
1474         return (ClassLoader) resource;
1475     }
1476 
1477     /**
1478      * Sends an MBeanServerNotifications with the specified type for the
1479      * MBean with the specified ObjectName
1480      */
1481     private void sendNotification(String NotifType, ObjectName name) {
1482 
1483         // ------------------------------
1484         // ------------------------------
1485 
1486         // ---------------------
1487         // Create notification
1488         // ---------------------
1489         MBeanServerNotification notif = new MBeanServerNotification(
1490             NotifType,MBeanServerDelegate.DELEGATE_NAME,0,name);
1491 
1492         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1493             MBEANSERVER_LOGGER.logp(Level.FINER,
1494                     DefaultMBeanServerInterceptor.class.getName(),
1495                     "sendNotification", NotifType + " " + name);
1496         }
1497 
1498         delegate.sendNotification(notif);
1499     }
1500 
1501     /**
1502      * Applies the specified queries to the set of NamedObjects.
1503      */
1504     private Set<ObjectName>
1505         objectNamesFromFilteredNamedObjects(Set<NamedObject> list,
1506                                             QueryExp query) {
1507         Set<ObjectName> result = new HashSet<ObjectName>();
1508         // No query ...
1509         if (query == null) {
1510             for (NamedObject no : list) {
1511                 result.add(no.getName());
1512             }
1513         } else {
1514             // Access the filter
1515             final MBeanServer oldServer = QueryEval.getMBeanServer();
1516             query.setMBeanServer(server);
1517             try {
1518                 for (NamedObject no : list) {
1519                     boolean res;
1520                     try {
1521                         res = query.apply(no.getName());
1522                     } catch (Exception e) {
1523                         res = false;
1524                     }
1525                     if (res) {
1526                         result.add(no.getName());
1527                     }
1528                 }
1529             } finally {
1530                 /*
1531                  * query.setMBeanServer is probably
1532                  * QueryEval.setMBeanServer so put back the old
1533                  * value.  Since that method uses a ThreadLocal
1534                  * variable, this code is only needed for the
1535                  * unusual case where the user creates a custom
1536                  * QueryExp that calls a nested query on another
1537                  * MBeanServer.
1538                  */
1539                 query.setMBeanServer(oldServer);
1540             }
1541         }
1542         return result;
1543     }
1544 
1545     /**
1546      * Applies the specified queries to the set of NamedObjects.
1547      */
1548     private Set<ObjectInstance>
1549         objectInstancesFromFilteredNamedObjects(Set<NamedObject> list,
1550                                                 QueryExp query) {
1551         Set<ObjectInstance> result = new HashSet<ObjectInstance>();
1552         // No query ...
1553         if (query == null) {
1554             for (NamedObject no : list) {
1555                 final DynamicMBean obj = no.getObject();
1556                 final String className = safeGetClassName(obj);
1557                 result.add(new ObjectInstance(no.getName(), className));
1558             }
1559         } else {
1560             // Access the filter
1561             MBeanServer oldServer = QueryEval.getMBeanServer();
1562             query.setMBeanServer(server);
1563             try {
1564                 for (NamedObject no : list) {
1565                     final DynamicMBean obj = no.getObject();
1566                     boolean res;
1567                     try {
1568                         res = query.apply(no.getName());
1569                     } catch (Exception e) {
1570                         res = false;
1571                     }
1572                     if (res) {
1573                         String className = safeGetClassName(obj);
1574                         result.add(new ObjectInstance(no.getName(), className));
1575                     }
1576                 }
1577             } finally {
1578                 /*
1579                  * query.setMBeanServer is probably
1580                  * QueryEval.setMBeanServer so put back the old
1581                  * value.  Since that method uses a ThreadLocal
1582                  * variable, this code is only needed for the
1583                  * unusual case where the user creates a custom
1584                  * QueryExp that calls a nested query on another
1585                  * MBeanServer.
1586                  */
1587                 query.setMBeanServer(oldServer);
1588             }
1589         }
1590         return result;
1591     }
1592 
1593     private static String safeGetClassName(DynamicMBean mbean) {
1594         try {
1595             return getClassName(mbean);
1596         } catch (Exception e) {
1597             if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
1598                 MBEANSERVER_LOGGER.logp(Level.FINEST,
1599                         DefaultMBeanServerInterceptor.class.getName(),
1600                         "safeGetClassName",
1601                         "Exception getting MBean class name", e);
1602             }
1603             return null;
1604         }
1605     }
1606 
1607     /**
1608      * Applies the specified queries to the set of ObjectInstances.
1609      */
1610     private Set<ObjectInstance>
1611             filterListOfObjectInstances(Set<ObjectInstance> list,
1612                                         QueryExp query) {
1613         // Null query.
1614         //
1615         if (query == null) {
1616             return list;
1617         } else {
1618             Set<ObjectInstance> result = new HashSet<ObjectInstance>();
1619             // Access the filter.
1620             //
1621             for (ObjectInstance oi : list) {
1622                 boolean res = false;
1623                 MBeanServer oldServer = QueryEval.getMBeanServer();
1624                 query.setMBeanServer(server);
1625                 try {
1626                     res = query.apply(oi.getObjectName());
1627                 } catch (Exception e) {
1628                     res = false;
1629                 } finally {
1630                     /*
1631                      * query.setMBeanServer is probably
1632                      * QueryEval.setMBeanServer so put back the old
1633                      * value.  Since that method uses a ThreadLocal
1634                      * variable, this code is only needed for the
1635                      * unusual case where the user creates a custom
1636                      * QueryExp that calls a nested query on another
1637                      * MBeanServer.
1638                      */
1639                     query.setMBeanServer(oldServer);
1640                 }
1641                 if (res) {
1642                     result.add(oi);
1643                 }
1644             }
1645             return result;
1646         }
1647     }
1648 
1649     /*
1650      * Get the existing wrapper for this listener, name, and mbean, if
1651      * there is one.  Otherwise, if "create" is true, create and
1652      * return one.  Otherwise, return null.
1653      *
1654      * We use a WeakHashMap so that if the only reference to a user
1655      * listener is in listenerWrappers, it can be garbage collected.
1656      * This requires a certain amount of care, because only the key in
1657      * a WeakHashMap is weak; the value is strong.  We need to recover
1658      * the existing wrapper object (not just an object that is equal
1659      * to it), so we would like listenerWrappers to map any
1660      * ListenerWrapper to the canonical ListenerWrapper for that
1661      * (listener,name,mbean) set.  But we do not want this canonical
1662      * wrapper to be referenced strongly.  Therefore we put it inside
1663      * a WeakReference and that is the value in the WeakHashMap.
1664      */
1665     private NotificationListener getListenerWrapper(NotificationListener l,
1666                                                     ObjectName name,
1667                                                     DynamicMBean mbean,
1668                                                     boolean create) {
1669         Object resource = getResource(mbean);
1670         ListenerWrapper wrapper = new ListenerWrapper(l, name, resource);
1671         synchronized (listenerWrappers) {
1672             WeakReference<ListenerWrapper> ref = listenerWrappers.get(wrapper);
1673             if (ref != null) {
1674                 NotificationListener existing = ref.get();
1675                 if (existing != null)
1676                     return existing;
1677             }
1678             if (create) {
1679                 ref = new WeakReference<ListenerWrapper>(wrapper);
1680                 listenerWrappers.put(wrapper, ref);
1681                 return wrapper;
1682             } else
1683                 return null;
1684         }
1685     }
1686 
1687     public Object instantiate(String className) throws ReflectionException,
1688                                                        MBeanException {
1689         throw new UnsupportedOperationException("Not supported yet.");
1690     }
1691 
1692     public Object instantiate(String className, ObjectName loaderName) throws ReflectionException,
1693                                                                               MBeanException,
1694                                                                               InstanceNotFoundException {
1695         throw new UnsupportedOperationException("Not supported yet.");
1696     }
1697 
1698     public Object instantiate(String className, Object[] params,
1699             String[] signature) throws ReflectionException, MBeanException {
1700         throw new UnsupportedOperationException("Not supported yet.");
1701     }
1702 
1703     public Object instantiate(String className, ObjectName loaderName,
1704             Object[] params, String[] signature) throws ReflectionException,
1705                                                         MBeanException,
1706                                                         InstanceNotFoundException {
1707         throw new UnsupportedOperationException("Not supported yet.");
1708     }
1709 
1710     public ObjectInputStream deserialize(ObjectName name, byte[] data) throws InstanceNotFoundException,
1711                                                                               OperationsException {
1712         throw new UnsupportedOperationException("Not supported yet.");
1713     }
1714 
1715     public ObjectInputStream deserialize(String className, byte[] data) throws OperationsException,
1716                                                                                ReflectionException {
1717         throw new UnsupportedOperationException("Not supported yet.");
1718     }
1719 
1720     public ObjectInputStream deserialize(String className, ObjectName loaderName,
1721             byte[] data) throws InstanceNotFoundException, OperationsException,
1722                                 ReflectionException {
1723         throw new UnsupportedOperationException("Not supported yet.");
1724     }
1725 
1726     public ClassLoaderRepository getClassLoaderRepository() {
1727         throw new UnsupportedOperationException("Not supported yet.");
1728     }
1729 
1730     private static class ListenerWrapper implements NotificationListener {
1731         ListenerWrapper(NotificationListener l, ObjectName name,
1732                         Object mbean) {
1733             this.listener = l;
1734             this.name = name;
1735             this.mbean = mbean;
1736         }
1737 
1738         public void handleNotification(Notification notification,
1739                                        Object handback) {
1740             if (notification != null) {
1741                 if (notification.getSource() == mbean)
1742                     notification.setSource(name);
1743             }
1744 
1745             /*
1746              * Listeners are not supposed to throw exceptions.  If
1747              * this one does, we could remove it from the MBean.  It
1748              * might indicate that a connector has stopped working,
1749              * for instance, and there is no point in sending future
1750              * notifications over that connection.  However, this
1751              * seems rather drastic, so instead we propagate the
1752              * exception and let the broadcaster handle it.
1753              */
1754             listener.handleNotification(notification, handback);
1755         }
1756 
1757         @Override
1758         public boolean equals(Object o) {
1759             if (!(o instanceof ListenerWrapper))
1760                 return false;
1761             ListenerWrapper w = (ListenerWrapper) o;
1762             return (w.listener == listener && w.mbean == mbean
1763                     && w.name.equals(name));
1764             /*
1765              * We compare all three, in case the same MBean object
1766              * gets unregistered and then reregistered under a
1767              * different name, or the same name gets assigned to two
1768              * different MBean objects at different times.  We do the
1769              * comparisons in this order to avoid the slow
1770              * ObjectName.equals when possible.
1771              */
1772         }
1773 
1774         @Override
1775         public int hashCode() {
1776             return (System.identityHashCode(listener) ^
1777                     System.identityHashCode(mbean));
1778             /*
1779              * We do not include name.hashCode() in the hash because
1780              * computing it is slow and usually we will not have two
1781              * instances of ListenerWrapper with the same mbean but
1782              * different ObjectNames.  That can happen if the MBean is
1783              * unregistered from one name and reregistered with
1784              * another, and there is no garbage collection between; or
1785              * if the same object is registered under two names (which
1786              * is not recommended because MBeanRegistration will
1787              * break).  But even in these unusual cases the hash code
1788              * does not have to be unique.
1789              */
1790         }
1791 
1792         private NotificationListener listener;
1793         private ObjectName name;
1794         private Object mbean;
1795     }
1796 
1797     // SECURITY CHECKS
1798     //----------------
1799 
1800     private static String getClassName(DynamicMBean mbean) {
1801         if (mbean instanceof DynamicMBean2)
1802             return ((DynamicMBean2) mbean).getClassName();
1803         else
1804             return mbean.getMBeanInfo().getClassName();
1805     }
1806 
1807     private static void checkMBeanPermission(DynamicMBean mbean,
1808                                              String member,
1809                                              ObjectName objectName,
1810                                              String actions) {
1811         SecurityManager sm = System.getSecurityManager();
1812         if (sm != null) {
1813             checkMBeanPermission(safeGetClassName(mbean),
1814                                  member,
1815                                  objectName,
1816                                  actions);
1817         }
1818     }
1819 
1820     private static void checkMBeanPermission(String classname,
1821                                              String member,
1822                                              ObjectName objectName,
1823                                              String actions) {
1824         SecurityManager sm = System.getSecurityManager();
1825         if (sm != null) {
1826             Permission perm = new MBeanPermission(classname,
1827                                                   member,
1828                                                   objectName,
1829                                                   actions);
1830             sm.checkPermission(perm);
1831         }
1832     }
1833 
1834     private static void checkMBeanTrustPermission(final Class<?> theClass)
1835         throws SecurityException {
1836         SecurityManager sm = System.getSecurityManager();
1837         if (sm != null) {
1838             Permission perm = new MBeanTrustPermission("register");
1839             PrivilegedAction<ProtectionDomain> act =
1840                 new PrivilegedAction<ProtectionDomain>() {
1841                     public ProtectionDomain run() {
1842                         return theClass.getProtectionDomain();
1843                     }
1844                 };
1845             ProtectionDomain pd = AccessController.doPrivileged(act);
1846             AccessControlContext acc =
1847                 new AccessControlContext(new ProtectionDomain[] { pd });
1848             sm.checkPermission(perm, acc);
1849         }
1850     }
1851 
1852     // ------------------------------------------------------------------
1853     //
1854     // Dealing with registration of special MBeans in the repository.
1855     //
1856     // ------------------------------------------------------------------
1857 
1858     /**
1859      * A RegistrationContext that makes it possible to perform additional
1860      * post registration actions (or post unregistration actions) outside
1861      * of the repository lock, once postRegister (or postDeregister) has
1862      * been called.
1863      * The method {@code done()} will be called in registerMBean or
1864      * unregisterMBean, at the end.
1865      */
1866     private static interface ResourceContext extends RegistrationContext {
1867         public void done();
1868         /** An empty ResourceContext which does nothing **/
1869         public static final ResourceContext NONE = new ResourceContext() {
1870             public void done() {}
1871             public void registering() {}
1872             public void unregistered() {}
1873         };
1874     }
1875 
1876     /**
1877      * Adds a MBean in the repository,
1878      * sends MBeanServerNotification.REGISTRATION_NOTIFICATION,
1879      * returns ResourceContext for special resources such as ClassLoaders
1880      * or JMXNamespaces. For regular MBean this method returns
1881      * ResourceContext.NONE.
1882      * @return a ResourceContext for special resources such as ClassLoaders
1883      *         or JMXNamespaces.
1884      */
1885     private ResourceContext registerWithRepository(
1886             final Object resource,
1887             final DynamicMBean object,
1888             final ObjectName logicalName)
1889             throws InstanceAlreadyExistsException,
1890             MBeanRegistrationException {
1891 
1892         // Creates a registration context, if needed.
1893         //
1894         final ResourceContext context =
1895                 makeResourceContextFor(resource, logicalName);
1896 
1897 
1898         repository.addMBean(object, logicalName, context);
1899         // May throw InstanceAlreadyExistsException
1900 
1901         // ---------------------
1902         // Send create event
1903         // ---------------------
1904         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1905             MBEANSERVER_LOGGER.logp(Level.FINER,
1906                     DefaultMBeanServerInterceptor.class.getName(),
1907                     "addObject", "Send create notification of object " +
1908                     logicalName.getCanonicalName());
1909         }
1910 
1911         sendNotification(
1912                 MBeanServerNotification.REGISTRATION_NOTIFICATION,
1913                 logicalName);
1914 
1915         return context;
1916     }
1917 
1918     /**
1919      * Removes a MBean in the repository,
1920      * sends MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
1921      * returns ResourceContext for special resources such as ClassLoaders
1922      * or JMXNamespaces, or null. For regular MBean this method returns
1923      * ResourceContext.NONE.
1924      *
1925      * @return a ResourceContext for special resources such as ClassLoaders
1926      *         or JMXNamespaces.
1927      */
1928     private ResourceContext unregisterFromRepository(
1929             final Object resource,
1930             final DynamicMBean object,
1931             final ObjectName logicalName)
1932             throws InstanceNotFoundException {
1933 
1934         // Creates a registration context, if needed.
1935         //
1936         final ResourceContext context =
1937                 makeResourceContextFor(resource, logicalName);
1938 
1939 
1940         repository.remove(logicalName, context);
1941 
1942         // ---------------------
1943         // Send deletion event
1944         // ---------------------
1945         if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1946             MBEANSERVER_LOGGER.logp(Level.FINER,
1947                     DefaultMBeanServerInterceptor.class.getName(),
1948                     "unregisterMBean", "Send delete notification of object " +
1949                     logicalName.getCanonicalName());
1950         }
1951 
1952         sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
1953                 logicalName);
1954         return context;
1955     }
1956 
1957 
1958     /**
1959      * Registers a ClassLoader with the CLR.
1960      * This method is called by the ResourceContext from within the
1961      * repository lock.
1962      * @param loader       The ClassLoader.
1963      * @param logicalName  The ClassLoader MBean ObjectName.
1964      */
1965     private void addClassLoader(ClassLoader loader,
1966             final ObjectName logicalName) {
1967         /**
1968          * Called when the newly registered MBean is a ClassLoader
1969          * If so, tell the ClassLoaderRepository (CLR) about it.  We do
1970          * this even if the loader is a PrivateClassLoader.  In that
1971          * case, the CLR remembers the loader for use when it is
1972          * explicitly named (e.g. as the loader in createMBean) but
1973          * does not add it to the list that is consulted by
1974          * ClassLoaderRepository.loadClass.
1975          */
1976         final ModifiableClassLoaderRepository clr = getInstantiatorCLR();
1977         if (clr == null) {
1978             final RuntimeException wrapped =
1979                     new IllegalArgumentException(
1980                     "Dynamic addition of class loaders" +
1981                     " is not supported");
1982             throw new RuntimeOperationsException(wrapped,
1983                     "Exception occurred trying to register" +
1984                     " the MBean as a class loader");
1985         }
1986         clr.addClassLoader(logicalName, loader);
1987     }
1988 
1989     /**
1990      * Unregisters a ClassLoader from the CLR.
1991      * This method is called by the ResourceContext from within the
1992      * repository lock.
1993      * @param loader       The ClassLoader.
1994      * @param logicalName  The ClassLoader MBean ObjectName.
1995      */
1996     private void removeClassLoader(ClassLoader loader,
1997             final ObjectName logicalName) {
1998         /**
1999          * Removes the  MBean from the default loader repository.
2000          */
2001         if (loader != server.getClass().getClassLoader()) {
2002             final ModifiableClassLoaderRepository clr = getInstantiatorCLR();
2003             if (clr != null) {
2004                 clr.removeClassLoader(logicalName);
2005             }
2006         }
2007     }
2008 
2009 
2010     /**
2011      * Creates a ResourceContext for a ClassLoader MBean.
2012      * The resource context makes it possible to add the ClassLoader to
2013      * (ResourceContext.registering) or resp. remove the ClassLoader from
2014      * (ResourceContext.unregistered) the CLR
2015      * when the associated MBean is added to or resp. removed from the
2016      * repository.
2017      *
2018      * @param loader       The ClassLoader MBean being registered or
2019      *                     unregistered.
2020      * @param logicalName  The name of the ClassLoader MBean.
2021      * @return a ResourceContext that takes in charge the addition or removal
2022      *         of the loader to or from the CLR.
2023      */
2024     private ResourceContext createClassLoaderContext(
2025             final ClassLoader loader,
2026             final ObjectName logicalName) {
2027         return new ResourceContext() {
2028 
2029             public void registering() {
2030                 addClassLoader(loader, logicalName);
2031             }
2032 
2033             public void unregistered() {
2034                 removeClassLoader(loader, logicalName);
2035             }
2036 
2037             public void done() {
2038             }
2039         };
2040     }
2041 
2042     /**
2043      * Creates a ResourceContext for the given resource.
2044      * If the resource does not need a ResourceContext, returns
2045      * ResourceContext.NONE.
2046      * At this time, only ClassLoaders need a ResourceContext.
2047      *
2048      * @param resource     The resource being registered or unregistered.
2049      * @param logicalName  The name of the associated MBean.
2050      * @return
2051      */
2052     private ResourceContext makeResourceContextFor(Object resource,
2053             ObjectName logicalName) {
2054         if (resource instanceof ClassLoader) {
2055             return createClassLoaderContext((ClassLoader) resource,
2056                     logicalName);
2057         }
2058         return ResourceContext.NONE;
2059     }
2060 
2061     private ModifiableClassLoaderRepository getInstantiatorCLR() {
2062         return AccessController.doPrivileged(new PrivilegedAction<ModifiableClassLoaderRepository>() {
2063             @Override
2064             public ModifiableClassLoaderRepository run() {
2065                 return instantiator != null ? instantiator.getClassLoaderRepository() : null;
2066             }
2067         });
2068     }
2069 }