/* * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jmx.interceptor; // JMX RIimport static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;import com.sun.jmx.mbeanserver.DynamicMBean2;import com.sun.jmx.mbeanserver.Introspector;import com.sun.jmx.mbeanserver.MBeanInstantiator;import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;import com.sun.jmx.mbeanserver.NamedObject;import com.sun.jmx.mbeanserver.Repository;import com.sun.jmx.mbeanserver.Repository.RegistrationContext;import com.sun.jmx.mbeanserver.Util;import com.sun.jmx.remote.util.EnvHelp; import java.io.ObjectInputStream;import java.lang.ref.WeakReference;import java.security.AccessControlContext;import java.security.AccessController;import java.security.Permission;import java.security.PrivilegedAction;import java.security.ProtectionDomain;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Set;import java.util.WeakHashMap;import java.util.logging.Level; // JMX importimport javax.management.Attribute;import javax.management.AttributeList;import javax.management.AttributeNotFoundException;import javax.management.DynamicMBean;import javax.management.InstanceAlreadyExistsException;import javax.management.InstanceNotFoundException;import javax.management.IntrospectionException;import javax.management.InvalidAttributeValueException;import javax.management.JMRuntimeException;import javax.management.ListenerNotFoundException;import javax.management.MBeanException;import javax.management.MBeanInfo;import javax.management.MBeanPermission;import javax.management.MBeanRegistration;import javax.management.MBeanRegistrationException;import javax.management.MBeanServer;import javax.management.MBeanServerDelegate;import javax.management.MBeanServerNotification;import javax.management.MBeanTrustPermission;import javax.management.NotCompliantMBeanException;import javax.management.Notification;import javax.management.NotificationBroadcaster;import javax.management.NotificationEmitter;import javax.management.NotificationFilter;import javax.management.NotificationListener;import javax.management.ObjectInstance;import javax.management.ObjectName;import javax.management.OperationsException;import javax.management.QueryEval;import javax.management.QueryExp;import javax.management.ReflectionException;import javax.management.RuntimeErrorException;import javax.management.RuntimeMBeanException;import javax.management.RuntimeOperationsException;import javax.management.loading.ClassLoaderRepository; /** * This is the default class for MBean manipulation on the agent side. It * contains the methods necessary for the creation, registration, and * deletion of MBeans as well as the access methods for registered MBeans. * This is the core component of the JMX infrastructure. * <P> * Every MBean which is added to the MBean server becomes manageable: its attributes and operations * become remotely accessible through the connectors/adaptors connected to that MBean server. * A Java object cannot be registered in the MBean server unless it is a JMX compliant MBean. * <P> * When an MBean is registered or unregistered in the MBean server an * {@link javax.management.MBeanServerNotification MBeanServerNotification} * Notification is emitted. To register an object as listener to MBeanServerNotifications * you should call the MBean server method {@link #addNotificationListener addNotificationListener} with <CODE>ObjectName</CODE> * the <CODE>ObjectName</CODE> of the {@link javax.management.MBeanServerDelegate MBeanServerDelegate}. * This <CODE>ObjectName</CODE> is: * <BR> * <CODE>JMImplementation:type=MBeanServerDelegate</CODE>. * * @since 1.5 */public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { /** The MBeanInstantiator object used by the * DefaultMBeanServerInterceptor */ private final transient MBeanInstantiator instantiator; /** The MBean server object that is associated to the * DefaultMBeanServerInterceptor */ private transient MBeanServer server = null; /** The MBean server delegate object that is associated to the * DefaultMBeanServerInterceptor */ private final transient MBeanServerDelegate delegate; /** The Repository object used by the DefaultMBeanServerInterceptor */ private final transient Repository repository; /** Wrappers for client listeners. */ /* See the comment before addNotificationListener below. */ private final transient WeakHashMap<ListenerWrapper, WeakReference<ListenerWrapper>> listenerWrappers = new WeakHashMap<ListenerWrapper, WeakReference<ListenerWrapper>>(); /** The default domain of the object names */ private final String domain; /** The sequence number identifying the notifications sent */ // Now sequence number is handled by MBeanServerDelegate. // private int sequenceNumber=0; /** * Creates a DefaultMBeanServerInterceptor with the specified * repository instance. * <p>Do not forget to call <code>initialize(outer,delegate)</code> * before using this object. * @param outer A pointer to the MBeanServer object that must be * passed to the MBeans when invoking their * {@link javax.management.MBeanRegistration} interface. * @param delegate A pointer to the MBeanServerDelegate associated * with the new MBeanServer. The new MBeanServer must register * this MBean in its MBean repository. * @param instantiator The MBeanInstantiator that will be used to * instantiate MBeans and take care of class loading issues. * @param repository The repository to use for this MBeanServer. */ public DefaultMBeanServerInterceptor(MBeanServer outer, MBeanServerDelegate delegate, MBeanInstantiator instantiator, Repository repository) { if (outer == null) throw new IllegalArgumentException("outer MBeanServer cannot be null"); if (delegate == null) throw new IllegalArgumentException("MBeanServerDelegate cannot be null"); if (instantiator == null) throw new IllegalArgumentException("MBeanInstantiator cannot be null"); if (repository == null) throw new IllegalArgumentException("Repository cannot be null"); this.server = outer; this.delegate = delegate; this.instantiator = instantiator; this.repository = repository; this.domain = repository.getDefaultDomain(); } public ObjectInstance createMBean(String className, ObjectName name) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException { return createMBean(className, name, (Object[]) null, (String[]) null); } public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException { return createMBean(className, name, loaderName, (Object[]) null, (String[]) null); } public ObjectInstance createMBean(String className, ObjectName name, Object[] params, String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException { try { return createMBean(className, name, null, true, params, signature); } catch (InstanceNotFoundException e) { /* Can only happen if loaderName doesn't exist, but we just passed null, so we shouldn't get this exception. */ throw EnvHelp.initCause( new IllegalArgumentException("Unexpected exception: " + e), e); } } public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, Object[] params, String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException { return createMBean(className, name, loaderName, false, params, signature); } private ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, boolean withDefaultLoaderRepository, Object[] params, String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException { Class<?> theClass; if (className == null) { final RuntimeException wrapped = new IllegalArgumentException("The class name cannot be null"); throw new RuntimeOperationsException(wrapped, "Exception occurred during MBean creation"); } if (name != null) { if (name.isPattern()) { final RuntimeException wrapped = new IllegalArgumentException("Invalid name->" + name.toString()); final String msg = "Exception occurred during MBean creation"; throw new RuntimeOperationsException(wrapped, msg); } name = nonDefaultDomain(name); } checkMBeanPermission(className, null, null, "instantiate"); checkMBeanPermission(className, null, name, "registerMBean"); /* Load the appropriate class. */ if (withDefaultLoaderRepository) { if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { MBEANSERVER_LOGGER.logp(Level.FINER, DefaultMBeanServerInterceptor.class.getName(), "createMBean", "ClassName = " + className + ", ObjectName = " + name); } theClass = instantiator.findClassWithDefaultLoaderRepository(className); } else if (loaderName == null) { if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { MBEANSERVER_LOGGER.logp(Level.FINER, DefaultMBeanServerInterceptor.class.getName(), "createMBean", "ClassName = " + className + ", ObjectName = " + name + ", Loader name = null"); } theClass = instantiator.findClass(className, server.getClass().getClassLoader()); } else { loaderName = nonDefaultDomain(loaderName); if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { MBEANSERVER_LOGGER.logp(Level.FINER, DefaultMBeanServerInterceptor.class.getName(), "createMBean", "ClassName = " + className + ", ObjectName = " + name + ", Loader name = " + loaderName); } theClass = instantiator.findClass(className, loaderName); } checkMBeanTrustPermission(theClass); // Check that the MBean can be instantiated by the MBeanServer. Introspector.testCreation(theClass); // Check the JMX MBean compliance of the class Introspector.checkCompliance(theClass); Object moi= instantiator.instantiate(theClass, params, signature, server.getClass().getClassLoader()); final String infoClassName = getNewMBeanClassName(moi); return registerObject(infoClassName, moi, name); } public ObjectInstance registerMBean(Object object, ObjectName name) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { // ------------------------------ // ------------------------------ Class<?> theClass = object.getClass(); Introspector.checkCompliance(theClass); final String infoClassName = getNewMBeanClassName(object); checkMBeanPermission(infoClassName, null, name, "registerMBean"); checkMBeanTrustPermission(theClass); return registerObject(infoClassName, object, name); } private static String getNewMBeanClassName(Object mbeanToRegister) throws NotCompliantMBeanException { if (mbeanToRegister instanceof DynamicMBean) { DynamicMBean mbean = (DynamicMBean) mbeanToRegister; final String name; try { name = mbean.getMBeanInfo().getClassName(); } catch (Exception e) { // Includes case where getMBeanInfo() returns null NotCompliantMBeanException ncmbe = new NotCompliantMBeanException("Bad getMBeanInfo()"); ncmbe.initCause(e); throw ncmbe; } if (name == null) { final String msg = "MBeanInfo has null class name"; throw new NotCompliantMBeanException(msg); } return name; } else return mbeanToRegister.getClass().getName(); } private final Set<ObjectName> beingUnregistered = new HashSet<ObjectName>(); public void unregisterMBean(ObjectName name) throws InstanceNotFoundException, MBeanRegistrationException { if (name == null) { final RuntimeException wrapped = new IllegalArgumentException("Object name cannot be null"); throw new RuntimeOperationsException(wrapped, "Exception occurred trying to unregister the MBean"); } name = nonDefaultDomain(name); /* The semantics of preDeregister are tricky. If it throws an exception, then the unregisterMBean fails. This allows an MBean to refuse to be unregistered. If it returns successfully, then the unregisterMBean can proceed. In this case the preDeregister may have cleaned up some state, and will not expect to be called a second time. So if two threads try to unregister the same MBean at the same time then one of them must wait for the other one to either (a) call preDeregister and get an exception or (b) call preDeregister successfully and unregister the MBean. Suppose thread T1 is unregistering an MBean and thread T2 is trying to unregister the same MBean, so waiting for T1. Then a deadlock is possible if the preDeregister for T1 ends up needing a lock held by T2. Given the semantics just described, there does not seem to be any way to avoid this. This will not happen to code where it is clear for any given MBean what thread may unregister that MBean. On the other hand we clearly do not want a thread that is unregistering MBean A to have to wait for another thread that is unregistering another MBean B (see bug 6318664). A deadlock in this situation could reasonably be considered gratuitous. So holding a global lock across the preDeregister call would be bad. So we have a set of ObjectNames that some thread is currently unregistering. When a thread wants to unregister a name, it must first check if the name is in the set, and if so it must wait. When a thread successfully unregisters a name it removes the name from the set and notifies any waiting threads that the set has changed. This implies that we must be very careful to ensure that the name is removed from the set and waiters notified, no matter what code path is taken. */ synchronized (beingUnregistered) { while (beingUnregistered.contains(name)) { try { beingUnregistered.wait(); } catch (InterruptedException e) { throw new MBeanRegistrationException(e, e.toString()); // pretend the exception came from preDeregister; // in another execution sequence it could have } } beingUnregistered.add(name); } try { exclusiveUnregisterMBean(name); } finally { synchronized (beingUnregistered) { beingUnregistered.remove(name); beingUnregistered.notifyAll(); } } } private void exclusiveUnregisterMBean(ObjectName name) throws InstanceNotFoundException, MBeanRegistrationException { DynamicMBean instance = getMBean(name); // may throw InstanceNotFoundException checkMBeanPermission(instance, null, name, "unregisterMBean"); if (instance instanceof MBeanRegistration) preDeregisterInvoke((MBeanRegistration) instance); final Object resource = getResource(instance); // Unregisters the MBean from the repository. // Returns the resource context that was used. // The returned context does nothing for regular MBeans. // For ClassLoader MBeans and JMXNamespace (and JMXDomain) // MBeans - the context makes it possible to unregister these // objects from the appropriate framework artifacts, such as // the CLR or the dispatcher, from within the repository lock. // In case of success, we also need to call context.done() at the // end of this method. // final ResourceContext context = unregisterFromRepository(resource, instance, name); try { if (instance instanceof MBeanRegistration) postDeregisterInvoke(name,(MBeanRegistration) instance); } finally { context.done(); } } public ObjectInstance getObjectInstance(ObjectName name) throws InstanceNotFoundException { name = nonDefaultDomain(name); DynamicMBean instance = getMBean(name); checkMBeanPermission(instance, null, name, "getObjectInstance"); final String className = getClassName(instance); return new ObjectInstance(name, className); } public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { // Check if the caller has the right to invoke 'queryMBeans' // checkMBeanPermission((String) null, null, null, "queryMBeans"); // Perform query without "query". // Set<ObjectInstance> list = queryMBeansImpl(name, null); // Check if the caller has the right to invoke 'queryMBeans' // on each specific classname/objectname in the list. // Set<ObjectInstance> allowedList = new HashSet<ObjectInstance>(list.size()); for (ObjectInstance oi : list) { try { checkMBeanPermission(oi.getClassName(), null, oi.getObjectName(), "queryMBeans"); allowedList.add(oi); } catch (SecurityException e) { // OK: Do not add this ObjectInstance to the list } } // Apply query to allowed MBeans only. // return filterListOfObjectInstances(allowedList, query); } else {Lines 1–500 of 2064. Load more
/* * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jmx.interceptor; // JMX RI import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER; import com.sun.jmx.mbeanserver.DynamicMBean2; import com.sun.jmx.mbeanserver.Introspector; import com.sun.jmx.mbeanserver.MBeanInstantiator; import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository; import com.sun.jmx.mbeanserver.NamedObject; import com.sun.jmx.mbeanserver.Repository; import com.sun.jmx.mbeanserver.Repository.RegistrationContext; import com.sun.jmx.mbeanserver.Util; import com.sun.jmx.remote.util.EnvHelp; import java.io.ObjectInputStream; import java.lang.ref.WeakReference; import java.security.AccessControlContext; import java.security.AccessController; import java.security.Permission; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.WeakHashMap; import java.util.logging.Level; // JMX import import javax.management.Attribute; import javax.management.AttributeList; import javax.management.AttributeNotFoundException; import javax.management.DynamicMBean; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.IntrospectionException; import javax.management.InvalidAttributeValueException; import javax.management.JMRuntimeException; import javax.management.ListenerNotFoundException; import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.MBeanPermission; import javax.management.MBeanRegistration; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MBeanServerDelegate; import javax.management.MBeanServerNotification; import javax.management.MBeanTrustPermission; import javax.management.NotCompliantMBeanException; import javax.management.Notification; import javax.management.NotificationBroadcaster; import javax.management.NotificationEmitter; import javax.management.NotificationFilter; import javax.management.NotificationListener; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.OperationsException; import javax.management.QueryEval; import javax.management.QueryExp; import javax.management.ReflectionException; import javax.management.RuntimeErrorException; import javax.management.RuntimeMBeanException; import javax.management.RuntimeOperationsException; import javax.management.loading.ClassLoaderRepository; /** * This is the default class for MBean manipulation on the agent side. It * contains the methods necessary for the creation, registration, and * deletion of MBeans as well as the access methods for registered MBeans. * This is the core component of the JMX infrastructure. * <P> * Every MBean which is added to the MBean server becomes manageable: its attributes and operations * become remotely accessible through the connectors/adaptors connected to that MBean server. * A Java object cannot be registered in the MBean server unless it is a JMX compliant MBean. * <P> * When an MBean is registered or unregistered in the MBean server an * {@link javax.management.MBeanServerNotification MBeanServerNotification} * Notification is emitted. To register an object as listener to MBeanServerNotifications * you should call the MBean server method {@link #addNotificationListener addNotificationListener} with <CODE>ObjectName</CODE> * the <CODE>ObjectName</CODE> of the {@link javax.management.MBeanServerDelegate MBeanServerDelegate}. * This <CODE>ObjectName</CODE> is: * <BR> * <CODE>JMImplementation:type=MBeanServerDelegate</CODE>. * * @since 1.5 */ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { /** The MBeanInstantiator object used by the * DefaultMBeanServerInterceptor */ private final transient MBeanInstantiator instantiator; /** The MBean server object that is associated to the * DefaultMBeanServerInterceptor */ private transient MBeanServer server = null; /** The MBean server delegate object that is associated to the * DefaultMBeanServerInterceptor */ private final transient MBeanServerDelegate delegate; /** The Repository object used by the DefaultMBeanServerInterceptor */ private final transient Repository repository; /** Wrappers for client listeners. */ /* See the comment before addNotificationListener below. */ private final transient WeakHashMap<ListenerWrapper, WeakReference<ListenerWrapper>> listenerWrappers = new WeakHashMap<ListenerWrapper, WeakReference<ListenerWrapper>>(); /** The default domain of the object names */ private final String domain; /** The sequence number identifying the notifications sent */ // Now sequence number is handled by MBeanServerDelegate. // private int sequenceNumber=0; /** * Creates a DefaultMBeanServerInterceptor with the specified * repository instance. * <p>Do not forget to call <code>initialize(outer,delegate)</code> * before using this object. * @param outer A pointer to the MBeanServer object that must be * passed to the MBeans when invoking their * {@link javax.management.MBeanRegistration} interface. * @param delegate A pointer to the MBeanServerDelegate associated * with the new MBeanServer. The new MBeanServer must register * this MBean in its MBean repository. * @param instantiator The MBeanInstantiator that will be used to * instantiate MBeans and take care of class loading issues. * @param repository The repository to use for this MBeanServer. */ public DefaultMBeanServerInterceptor(MBeanServer outer, MBeanServerDelegate delegate, MBeanInstantiator instantiator, Repository repository) { if (outer == null) throw new IllegalArgumentException("outer MBeanServer cannot be null"); if (delegate == null) throw new IllegalArgumentException("MBeanServerDelegate cannot be null"); if (instantiator == null) throw new IllegalArgumentException("MBeanInstantiator cannot be null"); if (repository == null) throw new IllegalArgumentException("Repository cannot be null"); this.server = outer; this.delegate = delegate; this.instantiator = instantiator; this.repository = repository; this.domain = repository.getDefaultDomain(); } public ObjectInstance createMBean(String className, ObjectName name) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException { return createMBean(className, name, (Object[]) null, (String[]) null); } public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException { return createMBean(className, name, loaderName, (Object[]) null, (String[]) null); } public ObjectInstance createMBean(String className, ObjectName name, Object[] params, String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException { try { return createMBean(className, name, null, true, params, signature); } catch (InstanceNotFoundException e) { /* Can only happen if loaderName doesn't exist, but we just passed null, so we shouldn't get this exception. */ throw EnvHelp.initCause( new IllegalArgumentException("Unexpected exception: " + e), e); } } public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, Object[] params, String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException { return createMBean(className, name, loaderName, false, params, signature); } private ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, boolean withDefaultLoaderRepository, Object[] params, String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException { Class<?> theClass; if (className == null) { final RuntimeException wrapped = new IllegalArgumentException("The class name cannot be null"); throw new RuntimeOperationsException(wrapped, "Exception occurred during MBean creation"); } if (name != null) { if (name.isPattern()) { final RuntimeException wrapped = new IllegalArgumentException("Invalid name->" + name.toString()); final String msg = "Exception occurred during MBean creation"; throw new RuntimeOperationsException(wrapped, msg); } name = nonDefaultDomain(name); } checkMBeanPermission(className, null, null, "instantiate"); checkMBeanPermission(className, null, name, "registerMBean"); /* Load the appropriate class. */ if (withDefaultLoaderRepository) { if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { MBEANSERVER_LOGGER.logp(Level.FINER, DefaultMBeanServerInterceptor.class.getName(), "createMBean", "ClassName = " + className + ", ObjectName = " + name); } theClass = instantiator.findClassWithDefaultLoaderRepository(className); } else if (loaderName == null) { if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { MBEANSERVER_LOGGER.logp(Level.FINER, DefaultMBeanServerInterceptor.class.getName(), "createMBean", "ClassName = " + className + ", ObjectName = " + name + ", Loader name = null"); } theClass = instantiator.findClass(className, server.getClass().getClassLoader()); } else { loaderName = nonDefaultDomain(loaderName); if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { MBEANSERVER_LOGGER.logp(Level.FINER, DefaultMBeanServerInterceptor.class.getName(), "createMBean", "ClassName = " + className + ", ObjectName = " + name + ", Loader name = " + loaderName); } theClass = instantiator.findClass(className, loaderName); } checkMBeanTrustPermission(theClass); // Check that the MBean can be instantiated by the MBeanServer. Introspector.testCreation(theClass); // Check the JMX MBean compliance of the class Introspector.checkCompliance(theClass); Object moi= instantiator.instantiate(theClass, params, signature, server.getClass().getClassLoader()); final String infoClassName = getNewMBeanClassName(moi); return registerObject(infoClassName, moi, name); } public ObjectInstance registerMBean(Object object, ObjectName name) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { // ------------------------------ // ------------------------------ Class<?> theClass = object.getClass(); Introspector.checkCompliance(theClass); final String infoClassName = getNewMBeanClassName(object); checkMBeanPermission(infoClassName, null, name, "registerMBean"); checkMBeanTrustPermission(theClass); return registerObject(infoClassName, object, name); } private static String getNewMBeanClassName(Object mbeanToRegister) throws NotCompliantMBeanException { if (mbeanToRegister instanceof DynamicMBean) { DynamicMBean mbean = (DynamicMBean) mbeanToRegister; final String name; try { name = mbean.getMBeanInfo().getClassName(); } catch (Exception e) { // Includes case where getMBeanInfo() returns null NotCompliantMBeanException ncmbe = new NotCompliantMBeanException("Bad getMBeanInfo()"); ncmbe.initCause(e); throw ncmbe; } if (name == null) { final String msg = "MBeanInfo has null class name"; throw new NotCompliantMBeanException(msg); } return name; } else return mbeanToRegister.getClass().getName(); } private final Set<ObjectName> beingUnregistered = new HashSet<ObjectName>(); public void unregisterMBean(ObjectName name) throws InstanceNotFoundException, MBeanRegistrationException { if (name == null) { final RuntimeException wrapped = new IllegalArgumentException("Object name cannot be null"); throw new RuntimeOperationsException(wrapped, "Exception occurred trying to unregister the MBean"); } name = nonDefaultDomain(name); /* The semantics of preDeregister are tricky. If it throws an exception, then the unregisterMBean fails. This allows an MBean to refuse to be unregistered. If it returns successfully, then the unregisterMBean can proceed. In this case the preDeregister may have cleaned up some state, and will not expect to be called a second time. So if two threads try to unregister the same MBean at the same time then one of them must wait for the other one to either (a) call preDeregister and get an exception or (b) call preDeregister successfully and unregister the MBean. Suppose thread T1 is unregistering an MBean and thread T2 is trying to unregister the same MBean, so waiting for T1. Then a deadlock is possible if the preDeregister for T1 ends up needing a lock held by T2. Given the semantics just described, there does not seem to be any way to avoid this. This will not happen to code where it is clear for any given MBean what thread may unregister that MBean. On the other hand we clearly do not want a thread that is unregistering MBean A to have to wait for another thread that is unregistering another MBean B (see bug 6318664). A deadlock in this situation could reasonably be considered gratuitous. So holding a global lock across the preDeregister call would be bad. So we have a set of ObjectNames that some thread is currently unregistering. When a thread wants to unregister a name, it must first check if the name is in the set, and if so it must wait. When a thread successfully unregisters a name it removes the name from the set and notifies any waiting threads that the set has changed. This implies that we must be very careful to ensure that the name is removed from the set and waiters notified, no matter what code path is taken. */ synchronized (beingUnregistered) { while (beingUnregistered.contains(name)) { try { beingUnregistered.wait(); } catch (InterruptedException e) { throw new MBeanRegistrationException(e, e.toString()); // pretend the exception came from preDeregister; // in another execution sequence it could have } } beingUnregistered.add(name); } try { exclusiveUnregisterMBean(name); } finally { synchronized (beingUnregistered) { beingUnregistered.remove(name); beingUnregistered.notifyAll(); } } } private void exclusiveUnregisterMBean(ObjectName name) throws InstanceNotFoundException, MBeanRegistrationException { DynamicMBean instance = getMBean(name); // may throw InstanceNotFoundException checkMBeanPermission(instance, null, name, "unregisterMBean"); if (instance instanceof MBeanRegistration) preDeregisterInvoke((MBeanRegistration) instance); final Object resource = getResource(instance); // Unregisters the MBean from the repository. // Returns the resource context that was used. // The returned context does nothing for regular MBeans. // For ClassLoader MBeans and JMXNamespace (and JMXDomain) // MBeans - the context makes it possible to unregister these // objects from the appropriate framework artifacts, such as // the CLR or the dispatcher, from within the repository lock. // In case of success, we also need to call context.done() at the // end of this method. // final ResourceContext context = unregisterFromRepository(resource, instance, name); try { if (instance instanceof MBeanRegistration) postDeregisterInvoke(name,(MBeanRegistration) instance); } finally { context.done(); } } public ObjectInstance getObjectInstance(ObjectName name) throws InstanceNotFoundException { name = nonDefaultDomain(name); DynamicMBean instance = getMBean(name); checkMBeanPermission(instance, null, name, "getObjectInstance"); final String className = getClassName(instance); return new ObjectInstance(name, className); } public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { // Check if the caller has the right to invoke 'queryMBeans' // checkMBeanPermission((String) null, null, null, "queryMBeans"); // Perform query without "query". // Set<ObjectInstance> list = queryMBeansImpl(name, null); // Check if the caller has the right to invoke 'queryMBeans' // on each specific classname/objectname in the list. // Set<ObjectInstance> allowedList = new HashSet<ObjectInstance>(list.size()); for (ObjectInstance oi : list) { try { checkMBeanPermission(oi.getClassName(), null, oi.getObjectName(), "queryMBeans"); allowedList.add(oi); } catch (SecurityException e) { // OK: Do not add this ObjectInstance to the list } } // Apply query to allowed MBeans only. // return filterListOfObjectInstances(allowedList, query); } else {