|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package com.sun.jmx.interceptor; |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor { |
|
|
|
|
|
* DefaultMBeanServerInterceptor */ |
|
private final transient MBeanInstantiator instantiator; |
|
|
|
|
|
* DefaultMBeanServerInterceptor */ |
|
private transient MBeanServer server = null; |
|
|
|
|
|
* DefaultMBeanServerInterceptor */ |
|
private final transient MBeanServerDelegate delegate; |
|
|
|
|
|
private final transient Repository repository; |
|
|
|
/** Wrappers for client listeners. */ |
|
|
|
private final transient |
|
WeakHashMap<ListenerWrapper, WeakReference<ListenerWrapper>> |
|
listenerWrappers = |
|
new WeakHashMap<ListenerWrapper, |
|
WeakReference<ListenerWrapper>>(); |
|
|
|
|
|
private final String domain; |
|
|
|
/** The sequence number identifying the notifications sent */ |
|
// Now sequence number is handled by MBeanServerDelegate. |
|
// private int sequenceNumber=0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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) { |
|
|
|
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"); |
|
|
|
|
|
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); |
|
|
|
|
|
Introspector.testCreation(theClass); |
|
|
|
|
|
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) { |
|
|
|
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 { |
|
// Perform query. |
|
|
|
return queryMBeansImpl(name, query); |
|
} |
|
} |
|
|
|
private Set<ObjectInstance> queryMBeansImpl(ObjectName name, |
|
QueryExp query) { |
|
// Query the MBeans on the repository |
|
|
|
Set<NamedObject> list = repository.query(name, query); |
|
|
|
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 = repository.query(name, query); |
|
|
|
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); |
|
|
|
/* No Permission check */ |
|
// isRegistered is always unchecked as per JMX spec. |
|
|
|
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 dom = Util.newObjectName(domains[i] + ":x=x"); |
|
checkMBeanPermission((String) null, null, dom, "getDomains"); |
|
result.add(domains[i]); |
|
} 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 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 (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"getAttribute", |
|
"Attribute = " + attribute + ", ObjectName = " + 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(); |
|
} |
|
} |
|
|
|
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 (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"getAttributes", "ObjectName = " + 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[allowedList.size()]); |
|
} |
|
|
|
try { |
|
return instance.getAttributes(allowedAttributes); |
|
} catch (Throwable t) { |
|
rethrow(t); |
|
throw new AssertionError(); |
|
} |
|
} |
|
|
|
public void setAttribute(ObjectName name, Attribute attribute) |
|
throws InstanceNotFoundException, AttributeNotFoundException, |
|
InvalidAttributeValueException, MBeanException, |
|
ReflectionException { |
|
|
|
if (name == null) { |
|
throw new RuntimeOperationsException(new |
|
IllegalArgumentException("ObjectName name cannot be null"), |
|
"Exception occurred trying to invoke the setter on the MBean"); |
|
} |
|
|
|
if (attribute == null) { |
|
throw new RuntimeOperationsException(new |
|
IllegalArgumentException("Attribute cannot be null"), |
|
"Exception occurred trying to invoke the setter on the MBean"); |
|
} |
|
|
|
name = nonDefaultDomain(name); |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"setAttribute", "ObjectName = " + name + |
|
", Attribute = " + attribute.getName()); |
|
} |
|
|
|
DynamicMBean instance = getMBean(name); |
|
checkMBeanPermission(instance, attribute.getName(), name, "setAttribute"); |
|
|
|
try { |
|
instance.setAttribute(attribute); |
|
} catch (AttributeNotFoundException e) { |
|
throw e; |
|
} catch (InvalidAttributeValueException e) { |
|
throw e; |
|
} catch (Throwable t) { |
|
rethrowMaybeMBeanException(t); |
|
throw new AssertionError(); |
|
} |
|
} |
|
|
|
public AttributeList setAttributes(ObjectName name, |
|
AttributeList attributes) |
|
throws InstanceNotFoundException, ReflectionException { |
|
|
|
if (name == null) { |
|
throw new RuntimeOperationsException(new |
|
IllegalArgumentException("ObjectName name cannot be null"), |
|
"Exception occurred trying to invoke the setter on the MBean"); |
|
} |
|
|
|
if (attributes == null) { |
|
throw new RuntimeOperationsException(new |
|
IllegalArgumentException("AttributeList cannot be null"), |
|
"Exception occurred trying to invoke the setter on the MBean"); |
|
} |
|
|
|
name = nonDefaultDomain(name); |
|
|
|
final DynamicMBean instance = getMBean(name); |
|
final AttributeList allowedAttributes; |
|
final SecurityManager sm = System.getSecurityManager(); |
|
if (sm == null) |
|
allowedAttributes = attributes; |
|
else { |
|
String classname = getClassName(instance); |
|
|
|
// Check if the caller has the right to invoke 'setAttribute' |
|
|
|
checkMBeanPermission(classname, null, name, "setAttribute"); |
|
|
|
// Check if the caller has the right to invoke 'setAttribute' |
|
// on each specific attribute |
|
|
|
allowedAttributes = new AttributeList(attributes.size()); |
|
for (Attribute attribute : attributes.asList()) { |
|
try { |
|
checkMBeanPermission(classname, attribute.getName(), |
|
name, "setAttribute"); |
|
allowedAttributes.add(attribute); |
|
} catch (SecurityException e) { |
|
// OK: Do not add this attribute to the list |
|
} |
|
} |
|
} |
|
try { |
|
return instance.setAttributes(allowedAttributes); |
|
} catch (Throwable t) { |
|
rethrow(t); |
|
throw new AssertionError(); |
|
} |
|
} |
|
|
|
public Object invoke(ObjectName name, String operationName, |
|
Object params[], String signature[]) |
|
throws InstanceNotFoundException, MBeanException, |
|
ReflectionException { |
|
|
|
name = nonDefaultDomain(name); |
|
|
|
DynamicMBean instance = getMBean(name); |
|
checkMBeanPermission(instance, operationName, name, "invoke"); |
|
try { |
|
return instance.invoke(operationName, params, signature); |
|
} catch (Throwable t) { |
|
rethrowMaybeMBeanException(t); |
|
throw new AssertionError(); |
|
} |
|
} |
|
|
|
|
|
spec. */ |
|
private static void rethrow(Throwable t) |
|
throws ReflectionException { |
|
try { |
|
throw t; |
|
} catch (ReflectionException e) { |
|
throw e; |
|
} catch (RuntimeOperationsException e) { |
|
throw e; |
|
} catch (RuntimeErrorException e) { |
|
throw e; |
|
} catch (RuntimeException e) { |
|
throw new RuntimeMBeanException(e, e.toString()); |
|
} catch (Error e) { |
|
throw new RuntimeErrorException(e, e.toString()); |
|
} catch (Throwable t2) { |
|
|
|
throw new RuntimeException("Unexpected exception", t2); |
|
} |
|
} |
|
|
|
private static void rethrowMaybeMBeanException(Throwable t) |
|
throws ReflectionException, MBeanException { |
|
if (t instanceof MBeanException) |
|
throw (MBeanException) t; |
|
rethrow(t); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**/ |
|
private ObjectInstance registerObject(String classname, |
|
Object object, ObjectName name) |
|
throws InstanceAlreadyExistsException, |
|
MBeanRegistrationException, |
|
NotCompliantMBeanException { |
|
|
|
if (object == null) { |
|
final RuntimeException wrapped = |
|
new IllegalArgumentException("Cannot add null object"); |
|
throw new RuntimeOperationsException(wrapped, |
|
"Exception occurred trying to register the MBean"); |
|
} |
|
|
|
DynamicMBean mbean = Introspector.makeDynamicMBean(object); |
|
|
|
return registerDynamicMBean(classname, mbean, name); |
|
} |
|
|
|
private ObjectInstance registerDynamicMBean(String classname, |
|
DynamicMBean mbean, |
|
ObjectName name) |
|
throws InstanceAlreadyExistsException, |
|
MBeanRegistrationException, |
|
NotCompliantMBeanException { |
|
|
|
|
|
name = nonDefaultDomain(name); |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"registerMBean", "ObjectName = " + name); |
|
} |
|
|
|
ObjectName logicalName = preRegister(mbean, server, name); |
|
|
|
// preRegister returned successfully, so from this point on we |
|
|
|
boolean registered = false; |
|
boolean registerFailed = false; |
|
ResourceContext context = null; |
|
|
|
try { |
|
if (mbean instanceof DynamicMBean2) { |
|
try { |
|
((DynamicMBean2) mbean).preRegister2(server, logicalName); |
|
registerFailed = true; |
|
} catch (Exception e) { |
|
if (e instanceof RuntimeException) |
|
throw (RuntimeException) e; |
|
if (e instanceof InstanceAlreadyExistsException) |
|
throw (InstanceAlreadyExistsException) e; |
|
throw new RuntimeException(e); |
|
} |
|
} |
|
|
|
if (logicalName != name && logicalName != null) { |
|
logicalName = |
|
ObjectName.getInstance(nonDefaultDomain(logicalName)); |
|
} |
|
|
|
checkMBeanPermission(classname, null, logicalName, "registerMBean"); |
|
|
|
if (logicalName == null) { |
|
final RuntimeException wrapped = |
|
new IllegalArgumentException("No object name specified"); |
|
throw new RuntimeOperationsException(wrapped, |
|
"Exception occurred trying to register the MBean"); |
|
} |
|
|
|
final Object resource = getResource(mbean); |
|
|
|
// Register the MBean with the repository. |
|
// Returns the resource context that was used. |
|
// The returned context does nothing for regular MBeans. |
|
// For ClassLoader MBeans the context makes it possible to register these |
|
// objects with the appropriate framework artifacts, such as |
|
// the CLR, from within the repository lock. |
|
// In case of success, we also need to call context.done() at the |
|
// end of this method. |
|
|
|
context = registerWithRepository(resource, mbean, logicalName); |
|
|
|
|
|
registerFailed = false; |
|
registered = true; |
|
|
|
} finally { |
|
try { |
|
postRegister(logicalName, mbean, registered, registerFailed); |
|
} finally { |
|
if (registered && context!=null) context.done(); |
|
} |
|
} |
|
return new ObjectInstance(logicalName, classname); |
|
} |
|
|
|
private static void throwMBeanRegistrationException(Throwable t, String where) |
|
throws MBeanRegistrationException { |
|
if (t instanceof RuntimeException) { |
|
throw new RuntimeMBeanException((RuntimeException)t, |
|
"RuntimeException thrown " + where); |
|
} else if (t instanceof Error) { |
|
throw new RuntimeErrorException((Error)t, |
|
"Error thrown " + where); |
|
} else if (t instanceof MBeanRegistrationException) { |
|
throw (MBeanRegistrationException)t; |
|
} else if (t instanceof Exception) { |
|
throw new MBeanRegistrationException((Exception)t, |
|
"Exception thrown " + where); |
|
} else |
|
throw new RuntimeException(t); |
|
} |
|
|
|
private static ObjectName preRegister( |
|
DynamicMBean mbean, MBeanServer mbs, ObjectName name) |
|
throws InstanceAlreadyExistsException, MBeanRegistrationException { |
|
|
|
ObjectName newName = null; |
|
|
|
try { |
|
if (mbean instanceof MBeanRegistration) |
|
newName = ((MBeanRegistration) mbean).preRegister(mbs, name); |
|
} catch (Throwable t) { |
|
throwMBeanRegistrationException(t, "in preRegister method"); |
|
} |
|
|
|
if (newName != null) return newName; |
|
else return name; |
|
} |
|
|
|
private static void postRegister( |
|
ObjectName logicalName, DynamicMBean mbean, |
|
boolean registrationDone, boolean registerFailed) { |
|
|
|
if (registerFailed && mbean instanceof DynamicMBean2) |
|
((DynamicMBean2) mbean).registerFailed(); |
|
try { |
|
if (mbean instanceof MBeanRegistration) |
|
((MBeanRegistration) mbean).postRegister(registrationDone); |
|
} catch (RuntimeException e) { |
|
MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+ |
|
"]: " + "Exception thrown by postRegister: " + |
|
"rethrowing <"+e+">, but keeping the MBean registered"); |
|
throw new RuntimeMBeanException(e, |
|
"RuntimeException thrown in postRegister method: "+ |
|
"rethrowing <"+e+">, but keeping the MBean registered"); |
|
} catch (Error er) { |
|
MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+ |
|
"]: " + "Error thrown by postRegister: " + |
|
"rethrowing <"+er+">, but keeping the MBean registered"); |
|
throw new RuntimeErrorException(er, |
|
"Error thrown in postRegister method: "+ |
|
"rethrowing <"+er+">, but keeping the MBean registered"); |
|
} |
|
} |
|
|
|
private static void preDeregisterInvoke(MBeanRegistration moi) |
|
throws MBeanRegistrationException { |
|
try { |
|
moi.preDeregister(); |
|
} catch (Throwable t) { |
|
throwMBeanRegistrationException(t, "in preDeregister method"); |
|
} |
|
} |
|
|
|
private static void postDeregisterInvoke(ObjectName mbean, |
|
MBeanRegistration moi) { |
|
try { |
|
moi.postDeregister(); |
|
} catch (RuntimeException e) { |
|
MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+ |
|
"]: " + "Exception thrown by postDeregister: " + |
|
"rethrowing <"+e+">, although the MBean is succesfully " + |
|
"unregistered"); |
|
throw new RuntimeMBeanException(e, |
|
"RuntimeException thrown in postDeregister method: "+ |
|
"rethrowing <"+e+ |
|
">, although the MBean is sucessfully unregistered"); |
|
} catch (Error er) { |
|
MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+ |
|
"]: " + "Error thrown by postDeregister: " + |
|
"rethrowing <"+er+">, although the MBean is succesfully " + |
|
"unregistered"); |
|
throw new RuntimeErrorException(er, |
|
"Error thrown in postDeregister method: "+ |
|
"rethrowing <"+er+ |
|
">, although the MBean is sucessfully unregistered"); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private DynamicMBean getMBean(ObjectName name) |
|
throws InstanceNotFoundException { |
|
|
|
if (name == null) { |
|
throw new RuntimeOperationsException(new |
|
IllegalArgumentException("Object name cannot be null"), |
|
"Exception occurred trying to get an MBean"); |
|
} |
|
DynamicMBean obj = repository.retrieve(name); |
|
if (obj == null) { |
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"getMBean", name + " : Found no object"); |
|
} |
|
throw new InstanceNotFoundException(name.toString()); |
|
} |
|
return obj; |
|
} |
|
|
|
private static Object getResource(DynamicMBean mbean) { |
|
if (mbean instanceof DynamicMBean2) |
|
return ((DynamicMBean2) mbean).getResource(); |
|
else |
|
return mbean; |
|
} |
|
|
|
private ObjectName nonDefaultDomain(ObjectName name) { |
|
if (name == null || name.getDomain().length() > 0) |
|
return name; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if one is supplied where it shouldn't be). */ |
|
final String completeName = domain + name; |
|
|
|
return Util.newObjectName(completeName); |
|
} |
|
|
|
public String getDefaultDomain() { |
|
return domain; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void addNotificationListener(ObjectName name, |
|
NotificationListener listener, |
|
NotificationFilter filter, |
|
Object handback) |
|
throws InstanceNotFoundException { |
|
|
|
// ------------------------------ |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"addNotificationListener", "ObjectName = " + name); |
|
} |
|
|
|
DynamicMBean instance = getMBean(name); |
|
checkMBeanPermission(instance, null, name, "addNotificationListener"); |
|
|
|
NotificationBroadcaster broadcaster = |
|
getNotificationBroadcaster(name, instance, |
|
NotificationBroadcaster.class); |
|
|
|
// ------------------ |
|
// Check listener |
|
|
|
if (listener == null) { |
|
throw new RuntimeOperationsException(new |
|
IllegalArgumentException("Null listener"),"Null listener"); |
|
} |
|
|
|
NotificationListener listenerWrapper = |
|
getListenerWrapper(listener, name, instance, true); |
|
broadcaster.addNotificationListener(listenerWrapper, filter, handback); |
|
} |
|
|
|
public void addNotificationListener(ObjectName name, |
|
ObjectName listener, |
|
NotificationFilter filter, |
|
Object handback) |
|
throws InstanceNotFoundException { |
|
|
|
// ------------------------------ |
|
// ------------------------------ |
|
|
|
// ---------------- |
|
// Get listener object |
|
|
|
DynamicMBean instance = getMBean(listener); |
|
Object resource = getResource(instance); |
|
if (!(resource instanceof NotificationListener)) { |
|
throw new RuntimeOperationsException(new |
|
IllegalArgumentException(listener.getCanonicalName()), |
|
"The MBean " + listener.getCanonicalName() + |
|
"does not implement the NotificationListener interface") ; |
|
} |
|
|
|
// ---------------- |
|
// Add a listener on an MBean |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"addNotificationListener", |
|
"ObjectName = " + name + ", Listener = " + listener); |
|
} |
|
server.addNotificationListener(name,(NotificationListener) resource, |
|
filter, handback) ; |
|
} |
|
|
|
public void removeNotificationListener(ObjectName name, |
|
NotificationListener listener) |
|
throws InstanceNotFoundException, ListenerNotFoundException { |
|
removeNotificationListener(name, listener, null, null, true); |
|
} |
|
|
|
public void removeNotificationListener(ObjectName name, |
|
NotificationListener listener, |
|
NotificationFilter filter, |
|
Object handback) |
|
throws InstanceNotFoundException, ListenerNotFoundException { |
|
removeNotificationListener(name, listener, filter, handback, false); |
|
} |
|
|
|
public void removeNotificationListener(ObjectName name, |
|
ObjectName listener) |
|
throws InstanceNotFoundException, ListenerNotFoundException { |
|
NotificationListener instance = getListener(listener); |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"removeNotificationListener", |
|
"ObjectName = " + name + ", Listener = " + listener); |
|
} |
|
server.removeNotificationListener(name, instance); |
|
} |
|
|
|
public void removeNotificationListener(ObjectName name, |
|
ObjectName listener, |
|
NotificationFilter filter, |
|
Object handback) |
|
throws InstanceNotFoundException, ListenerNotFoundException { |
|
|
|
NotificationListener instance = getListener(listener); |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"removeNotificationListener", |
|
"ObjectName = " + name + ", Listener = " + listener); |
|
} |
|
server.removeNotificationListener(name, instance, filter, handback); |
|
} |
|
|
|
private NotificationListener getListener(ObjectName listener) |
|
throws ListenerNotFoundException { |
|
// ---------------- |
|
// Get listener object |
|
|
|
DynamicMBean instance; |
|
try { |
|
instance = getMBean(listener); |
|
} catch (InstanceNotFoundException e) { |
|
throw EnvHelp.initCause( |
|
new ListenerNotFoundException(e.getMessage()), e); |
|
} |
|
|
|
Object resource = getResource(instance); |
|
if (!(resource instanceof NotificationListener)) { |
|
final RuntimeException exc = |
|
new IllegalArgumentException(listener.getCanonicalName()); |
|
final String msg = |
|
"MBean " + listener.getCanonicalName() + " does not " + |
|
"implement " + NotificationListener.class.getName(); |
|
throw new RuntimeOperationsException(exc, msg); |
|
} |
|
return (NotificationListener) resource; |
|
} |
|
|
|
private void removeNotificationListener(ObjectName name, |
|
NotificationListener listener, |
|
NotificationFilter filter, |
|
Object handback, |
|
boolean removeAll) |
|
throws InstanceNotFoundException, ListenerNotFoundException { |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"removeNotificationListener", "ObjectName = " + name); |
|
} |
|
|
|
DynamicMBean instance = getMBean(name); |
|
checkMBeanPermission(instance, null, name, "removeNotificationListener"); |
|
|
|
/* We could simplify the code by assigning broadcaster after |
|
assigning listenerWrapper, but that would change the error |
|
behavior when both the broadcaster and the listener are |
|
erroneous. */ |
|
|
|
Class<? extends NotificationBroadcaster> reqClass = |
|
removeAll ? NotificationBroadcaster.class : NotificationEmitter.class; |
|
NotificationBroadcaster broadcaster = |
|
getNotificationBroadcaster(name, instance, reqClass); |
|
|
|
NotificationListener listenerWrapper = |
|
getListenerWrapper(listener, name, instance, false); |
|
|
|
if (listenerWrapper == null) |
|
throw new ListenerNotFoundException("Unknown listener"); |
|
|
|
if (removeAll) |
|
broadcaster.removeNotificationListener(listenerWrapper); |
|
else { |
|
NotificationEmitter emitter = (NotificationEmitter) broadcaster; |
|
emitter.removeNotificationListener(listenerWrapper, |
|
filter, |
|
handback); |
|
} |
|
} |
|
|
|
private static <T extends NotificationBroadcaster> |
|
T getNotificationBroadcaster(ObjectName name, Object instance, |
|
Class<T> reqClass) { |
|
if (reqClass.isInstance(instance)) |
|
return reqClass.cast(instance); |
|
if (instance instanceof DynamicMBean2) |
|
instance = ((DynamicMBean2) instance).getResource(); |
|
if (reqClass.isInstance(instance)) |
|
return reqClass.cast(instance); |
|
final RuntimeException exc = |
|
new IllegalArgumentException(name.getCanonicalName()); |
|
final String msg = |
|
"MBean " + name.getCanonicalName() + " does not " + |
|
"implement " + reqClass.getName(); |
|
throw new RuntimeOperationsException(exc, msg); |
|
} |
|
|
|
public MBeanInfo getMBeanInfo(ObjectName name) |
|
throws InstanceNotFoundException, IntrospectionException, |
|
ReflectionException { |
|
|
|
// ------------------------------ |
|
// ------------------------------ |
|
|
|
DynamicMBean moi = getMBean(name); |
|
final MBeanInfo mbi; |
|
try { |
|
mbi = moi.getMBeanInfo(); |
|
} catch (RuntimeMBeanException e) { |
|
throw e; |
|
} catch (RuntimeErrorException e) { |
|
throw e; |
|
} catch (RuntimeException e) { |
|
throw new RuntimeMBeanException(e, |
|
"getMBeanInfo threw RuntimeException"); |
|
} catch (Error e) { |
|
throw new RuntimeErrorException(e, "getMBeanInfo threw Error"); |
|
} |
|
if (mbi == null) |
|
throw new JMRuntimeException("MBean " + name + |
|
"has no MBeanInfo"); |
|
|
|
checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo"); |
|
|
|
return mbi; |
|
} |
|
|
|
public boolean isInstanceOf(ObjectName name, String className) |
|
throws InstanceNotFoundException { |
|
|
|
final DynamicMBean instance = getMBean(name); |
|
checkMBeanPermission(instance, null, name, "isInstanceOf"); |
|
|
|
try { |
|
Object resource = getResource(instance); |
|
|
|
final String resourceClassName = |
|
(resource instanceof DynamicMBean) ? |
|
getClassName((DynamicMBean) resource) : |
|
resource.getClass().getName(); |
|
|
|
if (resourceClassName.equals(className)) |
|
return true; |
|
final ClassLoader cl = resource.getClass().getClassLoader(); |
|
|
|
final Class<?> classNameClass = Class.forName(className, false, cl); |
|
if (classNameClass.isInstance(resource)) |
|
return true; |
|
|
|
final Class<?> resourceClass = Class.forName(resourceClassName, false, cl); |
|
return classNameClass.isAssignableFrom(resourceClass); |
|
} catch (Exception x) { |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINEST, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"isInstanceOf", "Exception calling isInstanceOf", x); |
|
} |
|
return false; |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public ClassLoader getClassLoaderFor(ObjectName mbeanName) |
|
throws InstanceNotFoundException { |
|
|
|
DynamicMBean instance = getMBean(mbeanName); |
|
checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor"); |
|
return getResource(instance).getClass().getClassLoader(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public ClassLoader getClassLoader(ObjectName loaderName) |
|
throws InstanceNotFoundException { |
|
|
|
if (loaderName == null) { |
|
checkMBeanPermission((String) null, null, null, "getClassLoader"); |
|
return server.getClass().getClassLoader(); |
|
} |
|
|
|
DynamicMBean instance = getMBean(loaderName); |
|
checkMBeanPermission(instance, null, loaderName, "getClassLoader"); |
|
|
|
Object resource = getResource(instance); |
|
|
|
|
|
if (!(resource instanceof ClassLoader)) |
|
throw new InstanceNotFoundException(loaderName.toString() + |
|
" is not a classloader"); |
|
|
|
return (ClassLoader) resource; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private void sendNotification(String NotifType, ObjectName name) { |
|
|
|
// ------------------------------ |
|
// ------------------------------ |
|
|
|
// --------------------- |
|
// Create notification |
|
|
|
MBeanServerNotification notif = new MBeanServerNotification( |
|
NotifType,MBeanServerDelegate.DELEGATE_NAME,0,name); |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"sendNotification", NotifType + " " + name); |
|
} |
|
|
|
delegate.sendNotification(notif); |
|
} |
|
|
|
|
|
|
|
*/ |
|
private Set<ObjectName> |
|
objectNamesFromFilteredNamedObjects(Set<NamedObject> list, |
|
QueryExp query) { |
|
Set<ObjectName> result = new HashSet<ObjectName>(); |
|
|
|
if (query == null) { |
|
for (NamedObject no : list) { |
|
result.add(no.getName()); |
|
} |
|
} else { |
|
|
|
final MBeanServer oldServer = QueryEval.getMBeanServer(); |
|
query.setMBeanServer(server); |
|
try { |
|
for (NamedObject no : list) { |
|
boolean res; |
|
try { |
|
res = query.apply(no.getName()); |
|
} catch (Exception e) { |
|
res = false; |
|
} |
|
if (res) { |
|
result.add(no.getName()); |
|
} |
|
} |
|
} finally { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
query.setMBeanServer(oldServer); |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private Set<ObjectInstance> |
|
objectInstancesFromFilteredNamedObjects(Set<NamedObject> list, |
|
QueryExp query) { |
|
Set<ObjectInstance> result = new HashSet<ObjectInstance>(); |
|
|
|
if (query == null) { |
|
for (NamedObject no : list) { |
|
final DynamicMBean obj = no.getObject(); |
|
final String className = safeGetClassName(obj); |
|
result.add(new ObjectInstance(no.getName(), className)); |
|
} |
|
} else { |
|
|
|
MBeanServer oldServer = QueryEval.getMBeanServer(); |
|
query.setMBeanServer(server); |
|
try { |
|
for (NamedObject no : list) { |
|
final DynamicMBean obj = no.getObject(); |
|
boolean res; |
|
try { |
|
res = query.apply(no.getName()); |
|
} catch (Exception e) { |
|
res = false; |
|
} |
|
if (res) { |
|
String className = safeGetClassName(obj); |
|
result.add(new ObjectInstance(no.getName(), className)); |
|
} |
|
} |
|
} finally { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
query.setMBeanServer(oldServer); |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
private static String safeGetClassName(DynamicMBean mbean) { |
|
try { |
|
return getClassName(mbean); |
|
} catch (Exception e) { |
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINEST, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"safeGetClassName", |
|
"Exception getting MBean class name", e); |
|
} |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private Set<ObjectInstance> |
|
filterListOfObjectInstances(Set<ObjectInstance> list, |
|
QueryExp query) { |
|
// Null query. |
|
|
|
if (query == null) { |
|
return list; |
|
} else { |
|
Set<ObjectInstance> result = new HashSet<ObjectInstance>(); |
|
// Access the filter. |
|
|
|
for (ObjectInstance oi : list) { |
|
boolean res = false; |
|
MBeanServer oldServer = QueryEval.getMBeanServer(); |
|
query.setMBeanServer(server); |
|
try { |
|
res = query.apply(oi.getObjectName()); |
|
} catch (Exception e) { |
|
res = false; |
|
} finally { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
query.setMBeanServer(oldServer); |
|
} |
|
if (res) { |
|
result.add(oi); |
|
} |
|
} |
|
return result; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private NotificationListener getListenerWrapper(NotificationListener l, |
|
ObjectName name, |
|
DynamicMBean mbean, |
|
boolean create) { |
|
Object resource = getResource(mbean); |
|
ListenerWrapper wrapper = new ListenerWrapper(l, name, resource); |
|
synchronized (listenerWrappers) { |
|
WeakReference<ListenerWrapper> ref = listenerWrappers.get(wrapper); |
|
if (ref != null) { |
|
NotificationListener existing = ref.get(); |
|
if (existing != null) |
|
return existing; |
|
} |
|
if (create) { |
|
ref = new WeakReference<ListenerWrapper>(wrapper); |
|
listenerWrappers.put(wrapper, ref); |
|
return wrapper; |
|
} else |
|
return null; |
|
} |
|
} |
|
|
|
public Object instantiate(String className) throws ReflectionException, |
|
MBeanException { |
|
throw new UnsupportedOperationException("Not supported yet."); |
|
} |
|
|
|
public Object instantiate(String className, ObjectName loaderName) throws ReflectionException, |
|
MBeanException, |
|
InstanceNotFoundException { |
|
throw new UnsupportedOperationException("Not supported yet."); |
|
} |
|
|
|
public Object instantiate(String className, Object[] params, |
|
String[] signature) throws ReflectionException, MBeanException { |
|
throw new UnsupportedOperationException("Not supported yet."); |
|
} |
|
|
|
public Object instantiate(String className, ObjectName loaderName, |
|
Object[] params, String[] signature) throws ReflectionException, |
|
MBeanException, |
|
InstanceNotFoundException { |
|
throw new UnsupportedOperationException("Not supported yet."); |
|
} |
|
|
|
public ObjectInputStream deserialize(ObjectName name, byte[] data) throws InstanceNotFoundException, |
|
OperationsException { |
|
throw new UnsupportedOperationException("Not supported yet."); |
|
} |
|
|
|
public ObjectInputStream deserialize(String className, byte[] data) throws OperationsException, |
|
ReflectionException { |
|
throw new UnsupportedOperationException("Not supported yet."); |
|
} |
|
|
|
public ObjectInputStream deserialize(String className, ObjectName loaderName, |
|
byte[] data) throws InstanceNotFoundException, OperationsException, |
|
ReflectionException { |
|
throw new UnsupportedOperationException("Not supported yet."); |
|
} |
|
|
|
public ClassLoaderRepository getClassLoaderRepository() { |
|
throw new UnsupportedOperationException("Not supported yet."); |
|
} |
|
|
|
private static class ListenerWrapper implements NotificationListener { |
|
ListenerWrapper(NotificationListener l, ObjectName name, |
|
Object mbean) { |
|
this.listener = l; |
|
this.name = name; |
|
this.mbean = mbean; |
|
} |
|
|
|
public void handleNotification(Notification notification, |
|
Object handback) { |
|
if (notification != null) { |
|
if (notification.getSource() == mbean) |
|
notification.setSource(name); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
listener.handleNotification(notification, handback); |
|
} |
|
|
|
@Override |
|
public boolean equals(Object o) { |
|
if (!(o instanceof ListenerWrapper)) |
|
return false; |
|
ListenerWrapper w = (ListenerWrapper) o; |
|
return (w.listener == listener && w.mbean == mbean |
|
&& w.name.equals(name)); |
|
/* |
|
* We compare all three, in case the same MBean object |
|
* gets unregistered and then reregistered under a |
|
* different name, or the same name gets assigned to two |
|
* different MBean objects at different times. We do the |
|
* comparisons in this order to avoid the slow |
|
* ObjectName.equals when possible. |
|
*/ |
|
} |
|
|
|
@Override |
|
public int hashCode() { |
|
return (System.identityHashCode(listener) ^ |
|
System.identityHashCode(mbean)); |
|
/* |
|
* We do not include name.hashCode() in the hash because |
|
* computing it is slow and usually we will not have two |
|
* instances of ListenerWrapper with the same mbean but |
|
* different ObjectNames. That can happen if the MBean is |
|
* unregistered from one name and reregistered with |
|
* another, and there is no garbage collection between; or |
|
* if the same object is registered under two names (which |
|
* is not recommended because MBeanRegistration will |
|
* break). But even in these unusual cases the hash code |
|
* does not have to be unique. |
|
*/ |
|
} |
|
|
|
private NotificationListener listener; |
|
private ObjectName name; |
|
private Object mbean; |
|
} |
|
|
|
// SECURITY CHECKS |
|
//---------------- |
|
|
|
private static String getClassName(DynamicMBean mbean) { |
|
if (mbean instanceof DynamicMBean2) |
|
return ((DynamicMBean2) mbean).getClassName(); |
|
else |
|
return mbean.getMBeanInfo().getClassName(); |
|
} |
|
|
|
private static void checkMBeanPermission(DynamicMBean mbean, |
|
String member, |
|
ObjectName objectName, |
|
String actions) { |
|
SecurityManager sm = System.getSecurityManager(); |
|
if (sm != null) { |
|
checkMBeanPermission(safeGetClassName(mbean), |
|
member, |
|
objectName, |
|
actions); |
|
} |
|
} |
|
|
|
private static void checkMBeanPermission(String classname, |
|
String member, |
|
ObjectName objectName, |
|
String actions) { |
|
SecurityManager sm = System.getSecurityManager(); |
|
if (sm != null) { |
|
Permission perm = new MBeanPermission(classname, |
|
member, |
|
objectName, |
|
actions); |
|
sm.checkPermission(perm); |
|
} |
|
} |
|
|
|
private static void checkMBeanTrustPermission(final Class<?> theClass) |
|
throws SecurityException { |
|
SecurityManager sm = System.getSecurityManager(); |
|
if (sm != null) { |
|
Permission perm = new MBeanTrustPermission("register"); |
|
PrivilegedAction<ProtectionDomain> act = |
|
new PrivilegedAction<ProtectionDomain>() { |
|
public ProtectionDomain run() { |
|
return theClass.getProtectionDomain(); |
|
} |
|
}; |
|
ProtectionDomain pd = AccessController.doPrivileged(act); |
|
AccessControlContext acc = |
|
new AccessControlContext(new ProtectionDomain[] { pd }); |
|
sm.checkPermission(perm, acc); |
|
} |
|
} |
|
|
|
// ------------------------------------------------------------------ |
|
// |
|
// Dealing with registration of special MBeans in the repository. |
|
// |
|
// ------------------------------------------------------------------ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static interface ResourceContext extends RegistrationContext { |
|
public void done(); |
|
|
|
public static final ResourceContext NONE = new ResourceContext() { |
|
public void done() {} |
|
public void registering() {} |
|
public void unregistered() {} |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private ResourceContext registerWithRepository( |
|
final Object resource, |
|
final DynamicMBean object, |
|
final ObjectName logicalName) |
|
throws InstanceAlreadyExistsException, |
|
MBeanRegistrationException { |
|
|
|
// Creates a registration context, if needed. |
|
|
|
final ResourceContext context = |
|
makeResourceContextFor(resource, logicalName); |
|
|
|
|
|
repository.addMBean(object, logicalName, context); |
|
// May throw InstanceAlreadyExistsException |
|
|
|
// --------------------- |
|
// Send create event |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"addObject", "Send create notification of object " + |
|
logicalName.getCanonicalName()); |
|
} |
|
|
|
sendNotification( |
|
MBeanServerNotification.REGISTRATION_NOTIFICATION, |
|
logicalName); |
|
|
|
return context; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private ResourceContext unregisterFromRepository( |
|
final Object resource, |
|
final DynamicMBean object, |
|
final ObjectName logicalName) |
|
throws InstanceNotFoundException { |
|
|
|
// Creates a registration context, if needed. |
|
|
|
final ResourceContext context = |
|
makeResourceContextFor(resource, logicalName); |
|
|
|
|
|
repository.remove(logicalName, context); |
|
|
|
// --------------------- |
|
// Send deletion event |
|
|
|
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) { |
|
MBEANSERVER_LOGGER.logp(Level.FINER, |
|
DefaultMBeanServerInterceptor.class.getName(), |
|
"unregisterMBean", "Send delete notification of object " + |
|
logicalName.getCanonicalName()); |
|
} |
|
|
|
sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION, |
|
logicalName); |
|
return context; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void addClassLoader(ClassLoader loader, |
|
final ObjectName logicalName) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final ModifiableClassLoaderRepository clr = getInstantiatorCLR(); |
|
if (clr == null) { |
|
final RuntimeException wrapped = |
|
new IllegalArgumentException( |
|
"Dynamic addition of class loaders" + |
|
" is not supported"); |
|
throw new RuntimeOperationsException(wrapped, |
|
"Exception occurred trying to register" + |
|
" the MBean as a class loader"); |
|
} |
|
clr.addClassLoader(logicalName, loader); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void removeClassLoader(ClassLoader loader, |
|
final ObjectName logicalName) { |
|
|
|
|
|
*/ |
|
if (loader != server.getClass().getClassLoader()) { |
|
final ModifiableClassLoaderRepository clr = getInstantiatorCLR(); |
|
if (clr != null) { |
|
clr.removeClassLoader(logicalName); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private ResourceContext createClassLoaderContext( |
|
final ClassLoader loader, |
|
final ObjectName logicalName) { |
|
return new ResourceContext() { |
|
|
|
public void registering() { |
|
addClassLoader(loader, logicalName); |
|
} |
|
|
|
public void unregistered() { |
|
removeClassLoader(loader, logicalName); |
|
} |
|
|
|
public void done() { |
|
} |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private ResourceContext makeResourceContextFor(Object resource, |
|
ObjectName logicalName) { |
|
if (resource instanceof ClassLoader) { |
|
return createClassLoaderContext((ClassLoader) resource, |
|
logicalName); |
|
} |
|
return ResourceContext.NONE; |
|
} |
|
|
|
private ModifiableClassLoaderRepository getInstantiatorCLR() { |
|
return AccessController.doPrivileged(new PrivilegedAction<ModifiableClassLoaderRepository>() { |
|
@Override |
|
public ModifiableClassLoaderRepository run() { |
|
return instantiator != null ? instantiator.getClassLoaderRepository() : null; |
|
} |
|
}); |
|
} |
|
} |