📄 defaultmbeanserverinterceptor.java
字号:
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); synchronized (this) { repository.remove(name); // may throw InstanceNotFoundException } /** * Checks if the unregistered MBean is a ClassLoader * If so, it removes the MBean from the default loader repository. */ Object resource = getResource(instance); if (resource instanceof ClassLoader && resource != server.getClass().getClassLoader()) { final ModifiableClassLoaderRepository clr = instantiator.getClassLoaderRepository(); if (clr != null) clr.removeClassLoader(name); } // --------------------- // Send deletion event // --------------------- if (isTraceOn()) { trace("unregisterMBean", "Send delete notification of object " + name.getCanonicalName()); } sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION, name); if (instance instanceof MBeanRegistration) postDeregisterInvoke((MBeanRegistration) instance); } 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 { // Perform query. // return queryMBeansImpl(name, query); } } private Set<ObjectInstance> queryMBeansImpl(ObjectName name, QueryExp query) { // Query the MBeans on the repository // Set<NamedObject> list = null; synchronized(this) { list = repository.query(name, query); } if (queryByRepo) { // The repository performs the filtering query = null; } return (objectInstancesFromFilteredNamedObjects(list, query)); } public Set<ObjectName> queryNames(ObjectName name, QueryExp query) { Set<ObjectName> queryList; SecurityManager sm = System.getSecurityManager(); if (sm != null) { // Check if the caller has the right to invoke 'queryNames' // checkMBeanPermission((String) null, null, null, "queryNames"); // Perform query without "query". // Set<ObjectInstance> list = queryMBeansImpl(name, null); // Check if the caller has the right to invoke 'queryNames' // 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(), "queryNames"); allowedList.add(oi); } catch (SecurityException e) { // OK: Do not add this ObjectInstance to the list } } // Apply query to allowed MBeans only. // Set<ObjectInstance> queryObjectInstanceList = filterListOfObjectInstances(allowedList, query); queryList = new HashSet<ObjectName>(queryObjectInstanceList.size()); for (ObjectInstance oi : queryObjectInstanceList) { queryList.add(oi.getObjectName()); } } else { // Perform query. // queryList = queryNamesImpl(name, query); } return queryList; } private Set<ObjectName> queryNamesImpl(ObjectName name, QueryExp query) { // Query the MBeans on the repository // Set<NamedObject> list = null; synchronized(this) { list = repository.query(name, query); } if (queryByRepo) { // The repository performs the filtering query = null; } return (objectNamesFromFilteredNamedObjects(list, query)); } public boolean isRegistered(ObjectName name) { if (name == null) { throw new RuntimeOperationsException( new IllegalArgumentException("Object name cannot be null"), "Object name cannot be null"); } name = nonDefaultDomain(name);// /* Permission check */// checkMBeanPermission(null, null, name, "isRegistered"); synchronized(this) { return (repository.contains(name)); } } public String[] getDomains() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { // Check if the caller has the right to invoke 'getDomains' // checkMBeanPermission((String) null, null, null, "getDomains"); // Return domains // String[] domains = repository.getDomains(); // Check if the caller has the right to invoke 'getDomains' // on each specific domain in the list. // List<String> result = new ArrayList<String>(domains.length); for (int i = 0; i < domains.length; i++) { try { ObjectName domain = new ObjectName(domains[i] + ":x=x"); checkMBeanPermission((String) null, null, domain, "getDomains"); result.add(domains[i]); } catch (MalformedObjectNameException e) { // Should never occur... But let's log it just in case. error("getDomains", "Failed to check permission for domain=" + domains[i] + ". Error is: " + e); debugX("getDomains",e); } catch (SecurityException e) { // OK: Do not add this domain to the list } } // Make an array from result. // return result.toArray(new String[result.size()]); } else { return repository.getDomains(); } } public synchronized Integer getMBeanCount() { return (repository.getCount()); } public Object getAttribute(ObjectName name, String attribute) throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException { if (name == null) { throw new RuntimeOperationsException(new IllegalArgumentException("Object name cannot be null"), "Exception occurred trying to invoke the getter on the MBean"); } if (attribute == null) { throw new RuntimeOperationsException(new IllegalArgumentException("Attribute cannot be null"), "Exception occurred trying to invoke the getter on the MBean"); } name = nonDefaultDomain(name); if (isTraceOn()) { trace("getAttribute", "Attribute= " + attribute + ", obj= " + name); } final DynamicMBean instance = getMBean(name); checkMBeanPermission(instance, attribute, name, "getAttribute"); try { return instance.getAttribute(attribute); } catch (AttributeNotFoundException e) { throw e; } catch (Throwable t) { rethrowMaybeMBeanException(t); throw new AssertionError(); // not reached } } public AttributeList getAttributes(ObjectName name, String[] attributes) throws InstanceNotFoundException, ReflectionException { if (name == null) { throw new RuntimeOperationsException(new IllegalArgumentException("ObjectName name cannot be null"), "Exception occurred trying to invoke the getter on the MBean"); } if (attributes == null) { throw new RuntimeOperationsException(new IllegalArgumentException("Attributes cannot be null"), "Exception occurred trying to invoke the getter on the MBean"); } name = nonDefaultDomain(name); if (isTraceOn()) { trace("getAttributes", "Object= " + name); } final DynamicMBean instance = getMBean(name); final String[] allowedAttributes; final SecurityManager sm = System.getSecurityManager(); if (sm == null) allowedAttributes = attributes; else { final String classname = getClassName(instance); // Check if the caller has the right to invoke 'getAttribute' // checkMBeanPermission(classname, null, name, "getAttribute"); // Check if the caller has the right to invoke 'getAttribute' // on each specific attribute // List<String> allowedList = new ArrayList<String>(attributes.length); for (String attr : attributes) { try { checkMBeanPermission(classname, attr, name, "getAttribute"); allowedList.add(attr); } catch (SecurityException e) { // OK: Do not add this attribute to the list } } allowedAttributes = allowedList.toArray(new String[0]); } try { return instance.getAttributes(allowedAttributes);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -