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

Save This Page
Home » openjdk-7 » com.sun.jmx » interceptor » [javadoc | source]