6323980: Annotations to simplify MBean development
Reviewed-by: jfdenise, dfuchs
This commit is contained in:
parent
5967d518b5
commit
4333dd3520
@ -84,8 +84,13 @@ import com.sun.jmx.mbeanserver.MBeanInstantiator;
|
||||
import com.sun.jmx.mbeanserver.Repository;
|
||||
import com.sun.jmx.mbeanserver.NamedObject;
|
||||
import com.sun.jmx.mbeanserver.Introspector;
|
||||
import com.sun.jmx.mbeanserver.MBeanInjector;
|
||||
import com.sun.jmx.mbeanserver.NotifySupport;
|
||||
import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import javax.management.DynamicWrapperMBean;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
|
||||
/**
|
||||
* This is the default class for MBean manipulation on the agent side. It
|
||||
@ -433,36 +438,26 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
if (instance instanceof MBeanRegistration)
|
||||
preDeregisterInvoke((MBeanRegistration) instance);
|
||||
|
||||
repository.remove(name);
|
||||
// may throw InstanceNotFoundException
|
||||
final Object resource = getResource(instance);
|
||||
|
||||
/**
|
||||
* Checks if the unregistered MBean is a ClassLoader
|
||||
* If so, it removes the MBean from the default loader repository.
|
||||
*/
|
||||
// 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);
|
||||
|
||||
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 (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
|
||||
MBEANSERVER_LOGGER.logp(Level.FINER,
|
||||
DefaultMBeanServerInterceptor.class.getName(),
|
||||
"unregisterMBean", "Send delete notification of object " +
|
||||
name.getCanonicalName());
|
||||
}
|
||||
sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
|
||||
name);
|
||||
|
||||
if (instance instanceof MBeanRegistration)
|
||||
postDeregisterInvoke((MBeanRegistration) instance);
|
||||
|
||||
context.done();
|
||||
}
|
||||
|
||||
public ObjectInstance getObjectInstance(ObjectName name)
|
||||
@ -939,15 +934,22 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
}
|
||||
|
||||
ObjectName logicalName = name;
|
||||
logicalName = preRegister(mbean, server, name);
|
||||
|
||||
// preRegister returned successfully, so from this point on we
|
||||
// must call postRegister(false) if there is any problem.
|
||||
boolean registered = false;
|
||||
boolean registerFailed = false;
|
||||
ResourceContext context = null;
|
||||
|
||||
try {
|
||||
mbean = injectResources(mbean, server, logicalName);
|
||||
|
||||
if (mbean instanceof MBeanRegistration) {
|
||||
MBeanRegistration reg = (MBeanRegistration) mbean;
|
||||
logicalName = preRegisterInvoke(reg, name, server);
|
||||
if (mbean instanceof DynamicMBean2) {
|
||||
try {
|
||||
((DynamicMBean2) mbean).preRegister2(server, logicalName);
|
||||
registerFailed = true; // until we succeed
|
||||
} catch (Exception e) {
|
||||
postRegisterInvoke(reg, false, false);
|
||||
if (e instanceof RuntimeException)
|
||||
throw (RuntimeException) e;
|
||||
if (e instanceof InstanceAlreadyExistsException)
|
||||
@ -960,86 +962,102 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
logicalName =
|
||||
ObjectName.getInstance(nonDefaultDomain(logicalName));
|
||||
}
|
||||
}
|
||||
|
||||
checkMBeanPermission(classname, null, logicalName, "registerMBean");
|
||||
checkMBeanPermission(classname, null, logicalName, "registerMBean");
|
||||
|
||||
final ObjectInstance result;
|
||||
if (logicalName!=null) {
|
||||
result = new ObjectInstance(logicalName, classname);
|
||||
internal_addObject(mbean, logicalName);
|
||||
} else {
|
||||
if (mbean instanceof MBeanRegistration)
|
||||
postRegisterInvoke((MBeanRegistration) mbean, false, true);
|
||||
final RuntimeException wrapped =
|
||||
new IllegalArgumentException("No object name specified");
|
||||
throw new RuntimeOperationsException(wrapped,
|
||||
"Exception occurred trying to register the MBean");
|
||||
}
|
||||
|
||||
if (mbean instanceof MBeanRegistration)
|
||||
postRegisterInvoke((MBeanRegistration) mbean, true, false);
|
||||
|
||||
/**
|
||||
* Checks if the newly registered MBean is a ClassLoader
|
||||
* If so, tell the ClassLoaderRepository (CLR) about it. We do
|
||||
* this even if the object is a PrivateClassLoader. In that
|
||||
* case, the CLR remembers the loader for use when it is
|
||||
* explicitly named (e.g. as the loader in createMBean) but
|
||||
* does not add it to the list that is consulted by
|
||||
* ClassLoaderRepository.loadClass.
|
||||
*/
|
||||
final Object resource = getResource(mbean);
|
||||
if (resource instanceof ClassLoader) {
|
||||
final ModifiableClassLoaderRepository clr =
|
||||
instantiator.getClassLoaderRepository();
|
||||
if (clr == null) {
|
||||
if (logicalName == null) {
|
||||
final RuntimeException wrapped =
|
||||
new IllegalArgumentException(
|
||||
"Dynamic addition of class loaders is not supported");
|
||||
new IllegalArgumentException("No object name specified");
|
||||
throw new RuntimeOperationsException(wrapped,
|
||||
"Exception occurred trying to register the MBean as a class loader");
|
||||
"Exception occurred trying to register the MBean");
|
||||
}
|
||||
clr.addClassLoader(logicalName, (ClassLoader) resource);
|
||||
|
||||
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 and JMXNamespace (and JMXDomain)
|
||||
// MBeans - the context makes it possible to register these
|
||||
// objects with 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.
|
||||
//
|
||||
context = registerWithRepository(resource, mbean, logicalName);
|
||||
|
||||
registerFailed = false;
|
||||
registered = true;
|
||||
} finally {
|
||||
postRegister(mbean, registered, registerFailed);
|
||||
}
|
||||
|
||||
return result;
|
||||
context.done();
|
||||
return new ObjectInstance(logicalName, classname);
|
||||
}
|
||||
|
||||
private static ObjectName preRegisterInvoke(MBeanRegistration moi,
|
||||
ObjectName name,
|
||||
MBeanServer mbs)
|
||||
throws InstanceAlreadyExistsException, MBeanRegistrationException {
|
||||
|
||||
final ObjectName newName;
|
||||
|
||||
private static void throwMBeanRegistrationException(Throwable t, String where)
|
||||
throws MBeanRegistrationException {
|
||||
try {
|
||||
newName = moi.preRegister(mbs, name);
|
||||
throw t;
|
||||
} catch (RuntimeException e) {
|
||||
throw new RuntimeMBeanException(e,
|
||||
"RuntimeException thrown in preRegister method");
|
||||
throw new RuntimeMBeanException(
|
||||
e, "RuntimeException thrown " + where);
|
||||
} catch (Error er) {
|
||||
throw new RuntimeErrorException(er,
|
||||
"Error thrown in preRegister method");
|
||||
throw new RuntimeErrorException(er, "Error thrown " + where);
|
||||
} catch (MBeanRegistrationException r) {
|
||||
throw r;
|
||||
} catch (Exception ex) {
|
||||
throw new MBeanRegistrationException(ex,
|
||||
"Exception thrown in preRegister method");
|
||||
throw new MBeanRegistrationException(ex, "Exception thrown " + where);
|
||||
} catch (Throwable t1) {
|
||||
throw new RuntimeException(t); // neither Error nor Exception??
|
||||
}
|
||||
}
|
||||
|
||||
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 postRegisterInvoke(MBeanRegistration moi,
|
||||
boolean registrationDone,
|
||||
boolean registerFailed) {
|
||||
|
||||
if (registerFailed && moi instanceof DynamicMBean2)
|
||||
((DynamicMBean2) moi).registerFailed();
|
||||
private static DynamicMBean injectResources(
|
||||
DynamicMBean mbean, MBeanServer mbs, ObjectName name)
|
||||
throws MBeanRegistrationException {
|
||||
try {
|
||||
moi.postRegister(registrationDone);
|
||||
Object resource = getResource(mbean);
|
||||
MBeanInjector.inject(resource, mbs, name);
|
||||
if (MBeanInjector.injectsSendNotification(resource)) {
|
||||
NotificationBroadcasterSupport nbs =
|
||||
new NotificationBroadcasterSupport();
|
||||
MBeanInjector.injectSendNotification(resource, nbs);
|
||||
mbean = NotifySupport.wrap(mbean, nbs);
|
||||
}
|
||||
return mbean;
|
||||
} catch (Throwable t) {
|
||||
throwMBeanRegistrationException(t, "injecting @Resources");
|
||||
return null; // not reached
|
||||
}
|
||||
}
|
||||
|
||||
private static void postRegister(
|
||||
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) {
|
||||
throw new RuntimeMBeanException(e,
|
||||
"RuntimeException thrown in postRegister method");
|
||||
@ -1053,17 +1071,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
throws MBeanRegistrationException {
|
||||
try {
|
||||
moi.preDeregister();
|
||||
} catch (RuntimeException e) {
|
||||
throw new RuntimeMBeanException(e,
|
||||
"RuntimeException thrown in preDeregister method");
|
||||
} catch (Error er) {
|
||||
throw new RuntimeErrorException(er,
|
||||
"Error thrown in preDeregister method");
|
||||
} catch (MBeanRegistrationException t) {
|
||||
throw t;
|
||||
} catch (Exception ex) {
|
||||
throw new MBeanRegistrationException(ex,
|
||||
"Exception thrown in preDeregister method");
|
||||
} catch (Throwable t) {
|
||||
throwMBeanRegistrationException(t, "in preDeregister method");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1104,12 +1113,19 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
}
|
||||
|
||||
private static Object getResource(DynamicMBean mbean) {
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
return ((DynamicMBean2) mbean).getResource();
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedObject();
|
||||
else
|
||||
return mbean;
|
||||
}
|
||||
|
||||
private static ClassLoader getResourceLoader(DynamicMBean mbean) {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
|
||||
else
|
||||
return mbean.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
private ObjectName nonDefaultDomain(ObjectName name) {
|
||||
if (name == null || name.getDomain().length() > 0)
|
||||
return name;
|
||||
@ -1123,14 +1139,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
if one is supplied where it shouldn't be). */
|
||||
final String completeName = domain + name;
|
||||
|
||||
try {
|
||||
return new ObjectName(completeName);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
final String msg =
|
||||
"Unexpected default domain problem: " + completeName + ": " +
|
||||
e;
|
||||
throw EnvHelp.initCause(new IllegalArgumentException(msg), e);
|
||||
}
|
||||
return Util.newObjectName(completeName);
|
||||
}
|
||||
|
||||
public String getDefaultDomain() {
|
||||
@ -1211,7 +1220,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
}
|
||||
|
||||
NotificationListener listenerWrapper =
|
||||
getListenerWrapper(listener, name, broadcaster, true);
|
||||
getListenerWrapper(listener, name, instance, true);
|
||||
broadcaster.addNotificationListener(listenerWrapper, filter, handback);
|
||||
}
|
||||
|
||||
@ -1335,7 +1344,6 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(instance, null, name,
|
||||
"removeNotificationListener");
|
||||
Object resource = getResource(instance);
|
||||
|
||||
/* We could simplify the code by assigning broadcaster after
|
||||
assigning listenerWrapper, but that would change the error
|
||||
@ -1348,7 +1356,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
getNotificationBroadcaster(name, instance, reqClass);
|
||||
|
||||
NotificationListener listenerWrapper =
|
||||
getListenerWrapper(listener, name, resource, false);
|
||||
getListenerWrapper(listener, name, instance, false);
|
||||
|
||||
if (listenerWrapper == null)
|
||||
throw new ListenerNotFoundException("Unknown listener");
|
||||
@ -1366,8 +1374,10 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
private static <T extends NotificationBroadcaster>
|
||||
T getNotificationBroadcaster(ObjectName name, Object instance,
|
||||
Class<T> reqClass) {
|
||||
if (instance instanceof DynamicMBean2)
|
||||
instance = ((DynamicMBean2) instance).getResource();
|
||||
if (reqClass.isInstance(instance))
|
||||
return reqClass.cast(instance);
|
||||
if (instance instanceof DynamicWrapperMBean)
|
||||
instance = ((DynamicWrapperMBean) instance).getWrappedObject();
|
||||
if (reqClass.isInstance(instance))
|
||||
return reqClass.cast(instance);
|
||||
final RuntimeException exc =
|
||||
@ -1415,24 +1425,31 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
checkMBeanPermission(instance, null, name, "isInstanceOf");
|
||||
|
||||
try {
|
||||
if (instance instanceof DynamicMBean2) {
|
||||
Object resource = ((DynamicMBean2) instance).getResource();
|
||||
ClassLoader loader = resource.getClass().getClassLoader();
|
||||
Class<?> c = Class.forName(className, false, loader);
|
||||
return c.isInstance(resource);
|
||||
}
|
||||
Object resource = getResource(instance);
|
||||
|
||||
final String cn = getClassName(instance);
|
||||
if (cn.equals(className))
|
||||
final String resourceClassName =
|
||||
(resource instanceof DynamicMBean) ?
|
||||
getClassName((DynamicMBean) resource) :
|
||||
resource.getClass().getName();
|
||||
|
||||
if (resourceClassName.equals(className))
|
||||
return true;
|
||||
final ClassLoader cl = instance.getClass().getClassLoader();
|
||||
final ClassLoader cl = getResourceLoader(instance);
|
||||
|
||||
final Class<?> classNameClass = Class.forName(className, false, cl);
|
||||
if (classNameClass.isInstance(instance))
|
||||
if (classNameClass.isInstance(resource))
|
||||
return true;
|
||||
|
||||
final Class<?> instanceClass = Class.forName(cn, false, cl);
|
||||
return classNameClass.isAssignableFrom(instanceClass);
|
||||
// Ensure that isInstanceOf(NotificationEmitter) is true when
|
||||
// the MBean is a NotificationEmitter by virtue of a @Resource
|
||||
// annotation specifying a SendNotification resource.
|
||||
// This is a hack.
|
||||
if (instance instanceof NotificationBroadcaster &&
|
||||
classNameClass.isAssignableFrom(NotificationEmitter.class))
|
||||
return true;
|
||||
|
||||
final Class<?> resourceClass = Class.forName(resourceClassName, false, cl);
|
||||
return classNameClass.isAssignableFrom(resourceClass);
|
||||
} catch (Exception x) {
|
||||
/* Could be SecurityException or ClassNotFoundException */
|
||||
if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
|
||||
@ -1457,7 +1474,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
|
||||
DynamicMBean instance = getMBean(mbeanName);
|
||||
checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor");
|
||||
return getResource(instance).getClass().getClassLoader();
|
||||
return getResourceLoader(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1488,40 +1505,6 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
return (ClassLoader) resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a MBean in the repository
|
||||
*/
|
||||
private void internal_addObject(DynamicMBean object, ObjectName logicalName)
|
||||
throws InstanceAlreadyExistsException {
|
||||
|
||||
// ------------------------------
|
||||
// ------------------------------
|
||||
|
||||
// Let the repository do the work.
|
||||
|
||||
try {
|
||||
repository.addMBean(object, logicalName);
|
||||
} catch (InstanceAlreadyExistsException e) {
|
||||
if (object instanceof MBeanRegistration) {
|
||||
postRegisterInvoke((MBeanRegistration) object, false, true);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// 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 ) ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an MBeanServerNotifications with the specified type for the
|
||||
* MBean with the specified ObjectName
|
||||
@ -1712,9 +1695,10 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
*/
|
||||
private NotificationListener getListenerWrapper(NotificationListener l,
|
||||
ObjectName name,
|
||||
Object mbean,
|
||||
DynamicMBean mbean,
|
||||
boolean create) {
|
||||
ListenerWrapper wrapper = new ListenerWrapper(l, name, mbean);
|
||||
Object resource = getResource(mbean);
|
||||
ListenerWrapper wrapper = new ListenerWrapper(l, name, resource);
|
||||
synchronized (listenerWrappers) {
|
||||
WeakReference<ListenerWrapper> ref = listenerWrappers.get(wrapper);
|
||||
if (ref != null) {
|
||||
@ -1758,6 +1742,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
listener.handleNotification(notification, handback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof ListenerWrapper))
|
||||
return false;
|
||||
@ -1774,6 +1759,7 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (System.identityHashCode(listener) ^
|
||||
System.identityHashCode(mbean));
|
||||
@ -1851,4 +1837,213 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Dealing with registration of special MBeans in the repository.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A RegistrationContext that makes it possible to perform additional
|
||||
* post registration actions (or post unregistration actions) outside
|
||||
* of the repository lock, once postRegister (or postDeregister) has
|
||||
* been called.
|
||||
* The method {@code done()} will be called in registerMBean or
|
||||
* unregisterMBean, at the end.
|
||||
*/
|
||||
private static interface ResourceContext extends RegistrationContext {
|
||||
public void done();
|
||||
/** An empty ResourceContext which does nothing **/
|
||||
public static final ResourceContext NONE = new ResourceContext() {
|
||||
public void done() {}
|
||||
public void registering() {}
|
||||
public void unregistered() {}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a MBean in the repository,
|
||||
* sends MBeanServerNotification.REGISTRATION_NOTIFICATION,
|
||||
* returns ResourceContext for special resources such as ClassLoaders
|
||||
* or JMXNamespaces. For regular MBean this method returns
|
||||
* ResourceContext.NONE.
|
||||
* @return a ResourceContext for special resources such as ClassLoaders
|
||||
* or JMXNamespaces.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a MBean in the repository,
|
||||
* sends MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
|
||||
* returns ResourceContext for special resources such as ClassLoaders
|
||||
* or JMXNamespaces, or null. For regular MBean this method returns
|
||||
* ResourceContext.NONE.
|
||||
*
|
||||
* @return a ResourceContext for special resources such as ClassLoaders
|
||||
* or JMXNamespaces.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a ClassLoader with the CLR.
|
||||
* This method is called by the ResourceContext from within the
|
||||
* repository lock.
|
||||
* @param loader The ClassLoader.
|
||||
* @param logicalName The ClassLoader MBean ObjectName.
|
||||
*/
|
||||
private void addClassLoader(ClassLoader loader,
|
||||
final ObjectName logicalName) {
|
||||
/**
|
||||
* Called when the newly registered MBean is a ClassLoader
|
||||
* If so, tell the ClassLoaderRepository (CLR) about it. We do
|
||||
* this even if the loader is a PrivateClassLoader. In that
|
||||
* case, the CLR remembers the loader for use when it is
|
||||
* explicitly named (e.g. as the loader in createMBean) but
|
||||
* does not add it to the list that is consulted by
|
||||
* ClassLoaderRepository.loadClass.
|
||||
*/
|
||||
final ModifiableClassLoaderRepository clr =
|
||||
instantiator.getClassLoaderRepository();
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a ClassLoader from the CLR.
|
||||
* This method is called by the ResourceContext from within the
|
||||
* repository lock.
|
||||
* @param loader The ClassLoader.
|
||||
* @param logicalName The ClassLoader MBean ObjectName.
|
||||
*/
|
||||
private void removeClassLoader(ClassLoader loader,
|
||||
final ObjectName logicalName) {
|
||||
/**
|
||||
* Removes the MBean from the default loader repository.
|
||||
*/
|
||||
if (loader != server.getClass().getClassLoader()) {
|
||||
final ModifiableClassLoaderRepository clr =
|
||||
instantiator.getClassLoaderRepository();
|
||||
if (clr != null) {
|
||||
clr.removeClassLoader(logicalName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ResourceContext for a ClassLoader MBean.
|
||||
* The resource context makes it possible to add the ClassLoader to
|
||||
* (ResourceContext.registering) or resp. remove the ClassLoader from
|
||||
* (ResourceContext.unregistered) the CLR
|
||||
* when the associated MBean is added to or resp. removed from the
|
||||
* repository.
|
||||
*
|
||||
* @param loader The ClassLoader MBean being registered or
|
||||
* unregistered.
|
||||
* @param logicalName The name of the ClassLoader MBean.
|
||||
* @return a ResourceContext that takes in charge the addition or removal
|
||||
* of the loader to or from the CLR.
|
||||
*/
|
||||
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() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ResourceContext for the given resource.
|
||||
* If the resource does not need a ResourceContext, returns
|
||||
* ResourceContext.NONE.
|
||||
* At this time, only JMXNamespaces and ClassLoaders need a
|
||||
* ResourceContext.
|
||||
*
|
||||
* @param resource The resource being registered or unregistered.
|
||||
* @param logicalName The name of the associated MBean.
|
||||
* @return
|
||||
*/
|
||||
private ResourceContext makeResourceContextFor(Object resource,
|
||||
ObjectName logicalName) {
|
||||
if (resource instanceof ClassLoader) {
|
||||
return createClassLoaderContext((ClassLoader) resource,
|
||||
logicalName);
|
||||
}
|
||||
return ResourceContext.NONE;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.DynamicWrapperMBean;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
@ -35,17 +35,7 @@ import javax.management.ObjectName;
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface DynamicMBean2 extends DynamicMBean {
|
||||
/**
|
||||
* The resource corresponding to this MBean. This is the object whose
|
||||
* class name should be reflected by the MBean's
|
||||
* getMBeanInfo().getClassName() for example. For a "plain"
|
||||
* DynamicMBean it will be "this". For an MBean that wraps another
|
||||
* object, like javax.management.StandardMBean, it will be the wrapped
|
||||
* object.
|
||||
*/
|
||||
public Object getResource();
|
||||
|
||||
public interface DynamicMBean2 extends DynamicWrapperMBean {
|
||||
/**
|
||||
* The name of this MBean's class, as used by permission checks.
|
||||
* This is typically equal to getResource().getClass().getName().
|
||||
|
@ -25,23 +25,39 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.Description;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.DescriptorFields;
|
||||
import javax.management.DescriptorKey;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
@ -133,8 +149,12 @@ public class Introspector {
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkCompliance(Class mbeanClass)
|
||||
throws NotCompliantMBeanException {
|
||||
public static void checkCompliance(Class<?> mbeanClass)
|
||||
throws NotCompliantMBeanException {
|
||||
|
||||
// Check that @Resource is used correctly (if it used).
|
||||
MBeanInjector.validate(mbeanClass);
|
||||
|
||||
// Is DynamicMBean?
|
||||
//
|
||||
if (DynamicMBean.class.isAssignableFrom(mbeanClass))
|
||||
@ -157,21 +177,39 @@ public class Introspector {
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
mxbeanException = e;
|
||||
}
|
||||
// Is @MBean or @MXBean class?
|
||||
// In fact we find @MBean or @MXBean as a hacky variant of
|
||||
// getStandardMBeanInterface or getMXBeanInterface. If we get here
|
||||
// then nothing worked.
|
||||
final String msg =
|
||||
"MBean class " + mbeanClass.getName() + " does not implement " +
|
||||
"DynamicMBean, neither follows the Standard MBean conventions (" +
|
||||
mbeanException.toString() + ") nor the MXBean conventions (" +
|
||||
mxbeanException.toString() + ")";
|
||||
"DynamicMBean; does not follow the Standard MBean conventions (" +
|
||||
mbeanException.toString() + "); does not follow the MXBean conventions (" +
|
||||
mxbeanException.toString() + "); and does not have or inherit the @" +
|
||||
MBean.class.getSimpleName() + " or @" + MXBean.class.getSimpleName() +
|
||||
" annotation";
|
||||
throw new NotCompliantMBeanException(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a DynamicMBean out of the existing MBean object. The object
|
||||
* may already be a DynamicMBean, or it may be a Standard MBean or
|
||||
* MXBean, possibly defined using {@code @MBean} or {@code @MXBean}.</p>
|
||||
* @param mbean the object to convert to a DynamicMBean.
|
||||
* @param <T> a type parameter defined for implementation convenience
|
||||
* (which would have to be removed if this method were part of the public
|
||||
* API).
|
||||
* @return the converted DynamicMBean.
|
||||
* @throws NotCompliantMBeanException if {@code mbean} is not a compliant
|
||||
* MBean object, including the case where it is null.
|
||||
*/
|
||||
public static <T> DynamicMBean makeDynamicMBean(T mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mbean == null)
|
||||
throw new NotCompliantMBeanException("Null MBean object");
|
||||
if (mbean instanceof DynamicMBean)
|
||||
return (DynamicMBean) mbean;
|
||||
final Class mbeanClass = mbean.getClass();
|
||||
final Class<?> mbeanClass = mbean.getClass();
|
||||
Class<? super T> c = null;
|
||||
try {
|
||||
c = Util.cast(getStandardMBeanInterface(mbeanClass));
|
||||
@ -270,7 +308,7 @@ public class Introspector {
|
||||
* Return <code>null</code> if the MBean is a DynamicMBean,
|
||||
* or if no MBean interface is found.
|
||||
*/
|
||||
public static Class getMBeanInterface(Class baseClass) {
|
||||
public static Class<?> getMBeanInterface(Class<?> baseClass) {
|
||||
// Check if the given class implements the MBean interface
|
||||
// or the Dynamic MBean interface
|
||||
if (isDynamic(baseClass)) return null;
|
||||
@ -291,10 +329,12 @@ public class Introspector {
|
||||
* @throws NotCompliantMBeanException The specified class is
|
||||
* not a JMX compliant Standard MBean.
|
||||
*/
|
||||
public static Class getStandardMBeanInterface(Class baseClass)
|
||||
throws NotCompliantMBeanException {
|
||||
Class current = baseClass;
|
||||
Class mbeanInterface = null;
|
||||
public static <T> Class<? super T> getStandardMBeanInterface(Class<T> baseClass)
|
||||
throws NotCompliantMBeanException {
|
||||
if (baseClass.isAnnotationPresent(MBean.class))
|
||||
return baseClass;
|
||||
Class<? super T> current = baseClass;
|
||||
Class<? super T> mbeanInterface = null;
|
||||
while (current != null) {
|
||||
mbeanInterface =
|
||||
findMBeanInterface(current, current.getName());
|
||||
@ -321,8 +361,10 @@ public class Introspector {
|
||||
* @throws NotCompliantMBeanException The specified class is
|
||||
* not a JMX compliant MXBean.
|
||||
*/
|
||||
public static Class getMXBeanInterface(Class baseClass)
|
||||
public static <T> Class<? super T> getMXBeanInterface(Class<T> baseClass)
|
||||
throws NotCompliantMBeanException {
|
||||
if (hasMXBeanAnnotation(baseClass))
|
||||
return baseClass;
|
||||
try {
|
||||
return MXBeanSupport.findMXBeanInterface(baseClass);
|
||||
} catch (Exception e) {
|
||||
@ -345,19 +387,24 @@ public class Introspector {
|
||||
* ------------------------------------------
|
||||
*/
|
||||
|
||||
static boolean hasMXBeanAnnotation(Class<?> c) {
|
||||
MXBean m = c.getAnnotation(MXBean.class);
|
||||
return (m != null && m.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find the MBean interface corresponding to the class aName
|
||||
* - i.e. <i>aName</i>MBean, from within aClass and its superclasses.
|
||||
**/
|
||||
private static Class findMBeanInterface(Class aClass, String aName) {
|
||||
Class current = aClass;
|
||||
private static <T> Class<? super T> findMBeanInterface(
|
||||
Class<T> aClass, String aName) {
|
||||
Class<? super T> current = aClass;
|
||||
while (current != null) {
|
||||
final Class[] interfaces = current.getInterfaces();
|
||||
final Class<?>[] interfaces = current.getInterfaces();
|
||||
final int len = interfaces.length;
|
||||
for (int i=0;i<len;i++) {
|
||||
final Class inter =
|
||||
implementsMBean(interfaces[i], aName);
|
||||
Class<? super T> inter = Util.cast(interfaces[i]);
|
||||
inter = implementsMBean(inter, aName);
|
||||
if (inter != null) return inter;
|
||||
}
|
||||
current = current.getSuperclass();
|
||||
@ -365,6 +412,48 @@ public class Introspector {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String descriptionForElement(AnnotatedElement elmt) {
|
||||
if (elmt == null)
|
||||
return null;
|
||||
Description d = elmt.getAnnotation(Description.class);
|
||||
if (d == null)
|
||||
return null;
|
||||
return d.value();
|
||||
}
|
||||
|
||||
public static String descriptionForParameter(
|
||||
Annotation[] parameterAnnotations) {
|
||||
for (Annotation a : parameterAnnotations) {
|
||||
if (a instanceof Description)
|
||||
return ((Description) a).value();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String nameForParameter(
|
||||
Annotation[] parameterAnnotations) {
|
||||
for (Annotation a : parameterAnnotations) {
|
||||
Class<? extends Annotation> ac = a.annotationType();
|
||||
// You'd really have to go out of your way to have more than
|
||||
// one @Name annotation, so we don't check for that.
|
||||
if (ac.getSimpleName().equals("Name")) {
|
||||
try {
|
||||
Method value = ac.getMethod("value");
|
||||
if (value.getReturnType() == String.class &&
|
||||
value.getParameterTypes().length == 0) {
|
||||
return (String) value.invoke(a);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MBEANSERVER_LOGGER.log(
|
||||
Level.WARNING,
|
||||
"Unexpected exception getting @" + ac.getName(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Descriptor descriptorForElement(final AnnotatedElement elmt) {
|
||||
if (elmt == null)
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
@ -372,41 +461,18 @@ public class Introspector {
|
||||
return descriptorForAnnotations(annots);
|
||||
}
|
||||
|
||||
public static Descriptor descriptorForAnnotation(Annotation annot) {
|
||||
return descriptorForAnnotations(new Annotation[] {annot});
|
||||
}
|
||||
|
||||
public static Descriptor descriptorForAnnotations(Annotation[] annots) {
|
||||
if (annots.length == 0)
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
Map<String, Object> descriptorMap = new HashMap<String, Object>();
|
||||
for (Annotation a : annots) {
|
||||
Class<? extends Annotation> c = a.annotationType();
|
||||
Method[] elements = c.getMethods();
|
||||
for (Method element : elements) {
|
||||
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
|
||||
if (key != null) {
|
||||
String name = key.value();
|
||||
Object value;
|
||||
try {
|
||||
value = element.invoke(a);
|
||||
} catch (RuntimeException e) {
|
||||
// we don't expect this - except for possibly
|
||||
// security exceptions?
|
||||
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
|
||||
// anyway...
|
||||
//
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// we don't expect this
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
value = annotationToField(value);
|
||||
Object oldValue = descriptorMap.put(name, value);
|
||||
if (oldValue != null && !equals(oldValue, value)) {
|
||||
final String msg =
|
||||
"Inconsistent values for descriptor field " + name +
|
||||
" from annotations: " + value + " :: " + oldValue;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (a instanceof DescriptorFields)
|
||||
addDescriptorFieldsToMap(descriptorMap, (DescriptorFields) a);
|
||||
addAnnotationFieldsToMap(descriptorMap, a);
|
||||
}
|
||||
|
||||
if (descriptorMap.isEmpty())
|
||||
@ -415,6 +481,62 @@ public class Introspector {
|
||||
return new ImmutableDescriptor(descriptorMap);
|
||||
}
|
||||
|
||||
private static void addDescriptorFieldsToMap(
|
||||
Map<String, Object> descriptorMap, DescriptorFields df) {
|
||||
for (String field : df.value()) {
|
||||
int eq = field.indexOf('=');
|
||||
if (eq < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"@DescriptorFields string must contain '=': " +
|
||||
field);
|
||||
}
|
||||
String name = field.substring(0, eq);
|
||||
String value = field.substring(eq + 1);
|
||||
addToMap(descriptorMap, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addAnnotationFieldsToMap(
|
||||
Map<String, Object> descriptorMap, Annotation a) {
|
||||
Class<? extends Annotation> c = a.annotationType();
|
||||
Method[] elements = c.getMethods();
|
||||
for (Method element : elements) {
|
||||
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
|
||||
if (key != null) {
|
||||
String name = key.value();
|
||||
Object value;
|
||||
try {
|
||||
value = element.invoke(a);
|
||||
} catch (RuntimeException e) {
|
||||
// we don't expect this - except for possibly
|
||||
// security exceptions?
|
||||
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
|
||||
// anyway...
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// we don't expect this
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
if (!key.omitIfDefault() ||
|
||||
!equals(value, element.getDefaultValue())) {
|
||||
value = annotationToField(value);
|
||||
addToMap(descriptorMap, name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addToMap(
|
||||
Map<String, Object> descriptorMap, String name, Object value) {
|
||||
Object oldValue = descriptorMap.put(name, value);
|
||||
if (oldValue != null && !equals(oldValue, value)) {
|
||||
final String msg =
|
||||
"Inconsistent values for descriptor field " + name +
|
||||
" from annotations: " + value + " :: " + oldValue;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a NotCompliantMBeanException or a SecurityException.
|
||||
* @param notCompliant the class which was under examination
|
||||
@ -473,8 +595,13 @@ public class Introspector {
|
||||
// The only other possibility is that the value is another
|
||||
// annotation, or that the language has evolved since this code
|
||||
// was written. We don't allow for either of those currently.
|
||||
// If it is indeed another annotation, then x will be a proxy
|
||||
// with an unhelpful name like $Proxy2. So we extract the
|
||||
// proxy's interface to use that in the exception message.
|
||||
if (Proxy.isProxyClass(c))
|
||||
c = c.getInterfaces()[0]; // array "can't be empty"
|
||||
throw new IllegalArgumentException("Illegal type for annotation " +
|
||||
"element: " + x.getClass().getName());
|
||||
"element using @DescriptorKey: " + c.getName());
|
||||
}
|
||||
|
||||
// This must be consistent with the check for duplicate field values in
|
||||
@ -490,15 +617,15 @@ public class Introspector {
|
||||
* @param c The interface to be tested
|
||||
* @param clName The name of the class implementing this interface
|
||||
*/
|
||||
private static Class implementsMBean(Class c, String clName) {
|
||||
private static <T> Class<? super T> implementsMBean(Class<T> c, String clName) {
|
||||
String clMBeanName = clName + "MBean";
|
||||
if (c.getName().equals(clMBeanName)) {
|
||||
return c;
|
||||
}
|
||||
Class[] interfaces = c.getInterfaces();
|
||||
Class<?>[] interfaces = c.getInterfaces();
|
||||
for (int i = 0;i < interfaces.length; i++) {
|
||||
if (interfaces[i].getName().equals(clMBeanName))
|
||||
return interfaces[i];
|
||||
return Util.cast(interfaces[i]);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -33,6 +33,10 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.ManagedAttribute;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
|
||||
/**
|
||||
@ -125,18 +129,26 @@ class MBeanAnalyzer<M> {
|
||||
for (Method m : methods) {
|
||||
final String name = m.getName();
|
||||
final int nParams = m.getParameterTypes().length;
|
||||
final boolean managedOp = m.isAnnotationPresent(ManagedOperation.class);
|
||||
final boolean managedAttr = m.isAnnotationPresent(ManagedAttribute.class);
|
||||
if (managedOp && managedAttr) {
|
||||
throw new NotCompliantMBeanException("Method " + name +
|
||||
" has both @ManagedOperation and @ManagedAttribute");
|
||||
}
|
||||
|
||||
final M cm = introspector.mFrom(m);
|
||||
|
||||
String attrName = "";
|
||||
if (name.startsWith("get"))
|
||||
attrName = name.substring(3);
|
||||
else if (name.startsWith("is")
|
||||
&& m.getReturnType() == boolean.class)
|
||||
attrName = name.substring(2);
|
||||
if (!managedOp) {
|
||||
if (name.startsWith("get"))
|
||||
attrName = name.substring(3);
|
||||
else if (name.startsWith("is")
|
||||
&& m.getReturnType() == boolean.class)
|
||||
attrName = name.substring(2);
|
||||
}
|
||||
|
||||
if (attrName.length() != 0 && nParams == 0
|
||||
&& m.getReturnType() != void.class) {
|
||||
&& m.getReturnType() != void.class && !managedOp) {
|
||||
// It's a getter
|
||||
// Check we don't have both isX and getX
|
||||
AttrMethods<M> am = attrMap.get(attrName);
|
||||
@ -153,7 +165,7 @@ class MBeanAnalyzer<M> {
|
||||
attrMap.put(attrName, am);
|
||||
} else if (name.startsWith("set") && name.length() > 3
|
||||
&& nParams == 1 &&
|
||||
m.getReturnType() == void.class) {
|
||||
m.getReturnType() == void.class && !managedOp) {
|
||||
// It's a setter
|
||||
attrName = name.substring(3);
|
||||
AttrMethods<M> am = attrMap.get(attrName);
|
||||
@ -166,6 +178,9 @@ class MBeanAnalyzer<M> {
|
||||
}
|
||||
am.setter = cm;
|
||||
attrMap.put(attrName, am);
|
||||
} else if (managedAttr) {
|
||||
throw new NotCompliantMBeanException("Method " + name +
|
||||
" has @ManagedAttribute but is not a valid getter or setter");
|
||||
} else {
|
||||
// It's an operation
|
||||
List<M> cms = opMap.get(name);
|
||||
|
291
jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java
Normal file
291
jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.annotation.Resource;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import static com.sun.jmx.mbeanserver.Util.newMap;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.management.SendNotification;
|
||||
|
||||
public class MBeanInjector {
|
||||
private static Class<?>[] injectedClasses = {
|
||||
MBeanServer.class, ObjectName.class, SendNotification.class,
|
||||
};
|
||||
|
||||
public static void inject(Object mbean, MBeanServer mbs, ObjectName name)
|
||||
throws Exception {
|
||||
ClassInjector injector = injectorForClass(mbean.getClass());
|
||||
injector.inject(mbean, MBeanServer.class, mbs);
|
||||
injector.inject(mbean, ObjectName.class, name);
|
||||
}
|
||||
|
||||
public static boolean injectsSendNotification(Object mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
ClassInjector injector = injectorForClass(mbean.getClass());
|
||||
return injector.injects(SendNotification.class);
|
||||
}
|
||||
|
||||
public static void injectSendNotification(Object mbean, SendNotification sn)
|
||||
throws Exception {
|
||||
ClassInjector injector = injectorForClass(mbean.getClass());
|
||||
injector.inject(mbean, SendNotification.class, sn);
|
||||
}
|
||||
|
||||
public static void validate(Class<?> c) throws NotCompliantMBeanException {
|
||||
injectorForClass(c);
|
||||
}
|
||||
|
||||
private static class ClassInjector {
|
||||
private Map<Class<?>, List<Field>> fields;
|
||||
private Map<Class<?>, List<Method>> methods;
|
||||
|
||||
ClassInjector(Class<?> c) throws NotCompliantMBeanException {
|
||||
fields = newMap();
|
||||
methods = newMap();
|
||||
|
||||
Class<?> sup = c.getSuperclass();
|
||||
ClassInjector supInjector;
|
||||
if (sup == null) {
|
||||
supInjector = null;
|
||||
} else {
|
||||
supInjector = injectorForClass(sup);
|
||||
fields.putAll(supInjector.fields);
|
||||
methods.putAll(supInjector.methods);
|
||||
}
|
||||
|
||||
addMembers(c);
|
||||
eliminateOverriddenMethods();
|
||||
|
||||
// If we haven't added any new fields or methods to what we
|
||||
// inherited, then we can share the parent's maps.
|
||||
if (supInjector != null) {
|
||||
if (fields.equals(supInjector.fields))
|
||||
fields = supInjector.fields;
|
||||
if (methods.equals(supInjector.methods))
|
||||
methods = supInjector.methods;
|
||||
}
|
||||
}
|
||||
|
||||
boolean injects(Class<?> c) {
|
||||
return (fields.get(c) != null || methods.get(c) != null);
|
||||
}
|
||||
|
||||
<T> void inject(Object instance, Class<T> type, T resource)
|
||||
throws Exception {
|
||||
List<Field> fs = fields.get(type);
|
||||
if (fs != null) {
|
||||
for (Field f : fs)
|
||||
f.set(instance, resource);
|
||||
}
|
||||
List<Method> ms = methods.get(type);
|
||||
if (ms != null) {
|
||||
for (Method m : ms) {
|
||||
try {
|
||||
m.invoke(instance, resource);
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof Error)
|
||||
throw (Error) cause;
|
||||
else
|
||||
throw (Exception) cause;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void eliminateOverriddenMethods() {
|
||||
/* Covariant overriding is unlikely, but it is possible that the
|
||||
* parent has a @Resource method that we override with another
|
||||
* @Resource method. We don't want to invoke both methods,
|
||||
* because polymorphism means we would actually invoke the same
|
||||
* method twice.
|
||||
*/
|
||||
for (Map.Entry<Class<?>, List<Method>> entry : methods.entrySet()) {
|
||||
List<Method> list = entry.getValue();
|
||||
list = MBeanAnalyzer.eliminateCovariantMethods(list);
|
||||
entry.setValue(list);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find Fields or Methods within the given Class that we can inject
|
||||
* resource references into. Suppose we want to know if a Field can get
|
||||
* a reference to an ObjectName. We'll accept fields like this:
|
||||
*
|
||||
* @Resource
|
||||
* private transient ObjectName name;
|
||||
*
|
||||
* or like this:
|
||||
*
|
||||
* @Resource(type = ObjectName.class)
|
||||
* private transient Object name;
|
||||
*
|
||||
* but not like this:
|
||||
*
|
||||
* @Resource
|
||||
* private transient Object name;
|
||||
*
|
||||
* (Plain @Resource is equivalent to @Resource(type = Object.class).)
|
||||
*
|
||||
* We don't want to inject into everything that might possibly accept
|
||||
* an ObjectName reference, because examples like the last one above
|
||||
* could also accept an MBeanServer reference or any other sort of
|
||||
* reference.
|
||||
*
|
||||
* So we accept a Field if it has a @Resource annotation and either
|
||||
* (a) its type is ObjectName or a subclass and its @Resource type is
|
||||
* compatible with ObjectName (e.g. it is Object); or
|
||||
* (b) its type is compatible with ObjectName and its @Resource type
|
||||
* is exactly ObjectName. Fields that meet these criteria will not
|
||||
* meet the same criteria with respect to other types such as MBeanServer.
|
||||
*
|
||||
* The same logic applies mutatis mutandis to Methods such as this:
|
||||
*
|
||||
* @Resource
|
||||
* private void setObjectName1(ObjectName name)
|
||||
* @Resource(type = Object.class)
|
||||
* private void setObjectName2(Object name)
|
||||
*/
|
||||
private void addMembers(final Class<?> c)
|
||||
throws NotCompliantMBeanException {
|
||||
AccessibleObject[][] memberArrays =
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<AccessibleObject[][]>() {
|
||||
public AccessibleObject[][] run() {
|
||||
return new AccessibleObject[][] {
|
||||
c.getDeclaredFields(), c.getDeclaredMethods()
|
||||
};
|
||||
}
|
||||
});
|
||||
for (AccessibleObject[] members : memberArrays) {
|
||||
for (final AccessibleObject member : members) {
|
||||
Resource res = member.getAnnotation(Resource.class);
|
||||
if (res == null)
|
||||
continue;
|
||||
|
||||
final Field field;
|
||||
final Method method;
|
||||
final Class<?> memberType;
|
||||
final int modifiers;
|
||||
if (member instanceof Field) {
|
||||
field = (Field) member;
|
||||
memberType = field.getType();
|
||||
modifiers = field.getModifiers();
|
||||
method = null;
|
||||
} else {
|
||||
field = null;
|
||||
method = (Method) member;
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
if (paramTypes.length != 1) {
|
||||
throw new NotCompliantMBeanException(
|
||||
"@Resource method must have exactly 1 " +
|
||||
"parameter: " + method);
|
||||
}
|
||||
if (method.getReturnType() != void.class) {
|
||||
throw new NotCompliantMBeanException(
|
||||
"@Resource method must return void: " +
|
||||
method);
|
||||
}
|
||||
memberType = paramTypes[0];
|
||||
modifiers = method.getModifiers();
|
||||
}
|
||||
|
||||
if (Modifier.isStatic(modifiers)) {
|
||||
throw new NotCompliantMBeanException(
|
||||
"@Resource method or field cannot be static: " +
|
||||
member);
|
||||
}
|
||||
|
||||
for (Class<?> injectedClass : injectedClasses) {
|
||||
Class<?>[] types = {memberType, res.type()};
|
||||
boolean accept = false;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (types[i] == injectedClass &&
|
||||
types[1 - i].isAssignableFrom(injectedClass)) {
|
||||
accept = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (accept) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
member.setAccessible(true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
addToMap(fields, injectedClass, field);
|
||||
addToMap(methods, injectedClass, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <K, V> void addToMap(Map<K, List<V>> map, K key, V value) {
|
||||
if (value == null)
|
||||
return;
|
||||
List<V> list = map.get(key);
|
||||
if (list == null)
|
||||
list = Collections.singletonList(value);
|
||||
else {
|
||||
if (list.size() == 1)
|
||||
list = new ArrayList<V>(list);
|
||||
list.add(value);
|
||||
}
|
||||
map.put(key, list);
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized ClassInjector injectorForClass(Class<?> c)
|
||||
throws NotCompliantMBeanException {
|
||||
WeakReference<ClassInjector> wr = injectorMap.get(c);
|
||||
ClassInjector ci = (wr == null) ? null : wr.get();
|
||||
if (ci == null) {
|
||||
ci = new ClassInjector(c);
|
||||
injectorMap.put(c, new WeakReference<ClassInjector>(ci));
|
||||
}
|
||||
return ci;
|
||||
}
|
||||
|
||||
private static Map<Class<?>, WeakReference<ClassInjector>> injectorMap =
|
||||
new WeakHashMap<Class<?>, WeakReference<ClassInjector>>();
|
||||
}
|
@ -36,20 +36,28 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.Description;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.ManagedAttribute;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationBroadcaster;
|
||||
import javax.management.NotificationInfo;
|
||||
import javax.management.NotificationInfos;
|
||||
import javax.management.ReflectionException;
|
||||
|
||||
/**
|
||||
@ -153,6 +161,25 @@ abstract class MBeanIntrospector<M> {
|
||||
abstract MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
||||
M getter, M setter) throws IntrospectionException;
|
||||
|
||||
final String getAttributeDescription(
|
||||
String attributeName, String defaultDescription,
|
||||
Method getter, Method setter) throws IntrospectionException {
|
||||
String g = Introspector.descriptionForElement(getter);
|
||||
String s = Introspector.descriptionForElement(setter);
|
||||
if (g == null) {
|
||||
if (s == null)
|
||||
return defaultDescription;
|
||||
else
|
||||
return s;
|
||||
} else if (s == null || g.equals(s)) {
|
||||
return g;
|
||||
} else {
|
||||
throw new IntrospectionException(
|
||||
"Inconsistent @Description on getter and setter for " +
|
||||
"attribute " + attributeName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an MBeanOperationInfo for the given operation based on
|
||||
* the M it was derived from.
|
||||
@ -184,8 +211,12 @@ abstract class MBeanIntrospector<M> {
|
||||
}
|
||||
|
||||
void checkCompliance(Class<?> mbeanType) throws NotCompliantMBeanException {
|
||||
if (!mbeanType.isInterface()) {
|
||||
throw new NotCompliantMBeanException("Not an interface: " +
|
||||
if (!mbeanType.isInterface() &&
|
||||
!mbeanType.isAnnotationPresent(MBean.class) &&
|
||||
!Introspector.hasMXBeanAnnotation(mbeanType)) {
|
||||
throw new NotCompliantMBeanException("Not an interface and " +
|
||||
"does not have @" + MBean.class.getSimpleName() +
|
||||
" or @" + MXBean.class.getSimpleName() + " annotation: " +
|
||||
mbeanType.getName());
|
||||
}
|
||||
}
|
||||
@ -194,7 +225,12 @@ abstract class MBeanIntrospector<M> {
|
||||
* Get the methods to be analyzed to build the MBean interface.
|
||||
*/
|
||||
List<Method> getMethods(final Class<?> mbeanType) throws Exception {
|
||||
return Arrays.asList(mbeanType.getMethods());
|
||||
if (mbeanType.isInterface())
|
||||
return Arrays.asList(mbeanType.getMethods());
|
||||
|
||||
final List<Method> methods = newList();
|
||||
getAnnotatedMethods(mbeanType, methods);
|
||||
return methods;
|
||||
}
|
||||
|
||||
final PerInterface<M> getPerInterface(Class<?> mbeanInterface)
|
||||
@ -232,8 +268,11 @@ abstract class MBeanIntrospector<M> {
|
||||
MBeanAnalyzer<M> analyzer) throws IntrospectionException {
|
||||
final MBeanInfoMaker maker = new MBeanInfoMaker();
|
||||
analyzer.visit(maker);
|
||||
final String description =
|
||||
final String defaultDescription =
|
||||
"Information on the management interface of the MBean";
|
||||
String description = Introspector.descriptionForElement(mbeanInterface);
|
||||
if (description == null)
|
||||
description = defaultDescription;
|
||||
return maker.makeMBeanInfo(mbeanInterface, description);
|
||||
}
|
||||
|
||||
@ -407,7 +446,15 @@ abstract class MBeanIntrospector<M> {
|
||||
throws NotCompliantMBeanException {
|
||||
MBeanInfo mbi =
|
||||
getClassMBeanInfo(resource.getClass(), perInterface);
|
||||
MBeanNotificationInfo[] notifs = findNotifications(resource);
|
||||
MBeanNotificationInfo[] notifs;
|
||||
try {
|
||||
notifs = findNotifications(resource);
|
||||
} catch (RuntimeException e) {
|
||||
NotCompliantMBeanException x =
|
||||
new NotCompliantMBeanException(e.getMessage());
|
||||
x.initCause(e);
|
||||
throw x;
|
||||
}
|
||||
Descriptor d = getSpecificMBeanDescriptor();
|
||||
boolean anyNotifs = (notifs != null && notifs.length > 0);
|
||||
if (!anyNotifs && ImmutableDescriptor.EMPTY_DESCRIPTOR.equals(d))
|
||||
@ -460,13 +507,43 @@ abstract class MBeanIntrospector<M> {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add to "methods" every public method that has the @ManagedAttribute
|
||||
* or @ManagedOperation annotation, in the given class or any of
|
||||
* its superclasses or superinterfaces.
|
||||
*
|
||||
* We always add superclass or superinterface methods first, so that
|
||||
* the stable sort used by eliminateCovariantMethods will put the
|
||||
* method from the most-derived class last. This means that we will
|
||||
* see the version of the @ManagedAttribute (or ...Operation) annotation
|
||||
* from that method, which might have a different description or whatever.
|
||||
*/
|
||||
private static void getAnnotatedMethods(Class<?> c, List<Method> methods)
|
||||
throws Exception {
|
||||
Class<?> sup = c.getSuperclass();
|
||||
if (sup != null)
|
||||
getAnnotatedMethods(sup, methods);
|
||||
Class<?>[] intfs = c.getInterfaces();
|
||||
for (Class<?> intf : intfs)
|
||||
getAnnotatedMethods(intf, methods);
|
||||
for (Method m : c.getMethods()) {
|
||||
// We are careful not to add m if it is inherited from a parent
|
||||
// class or interface, because duplicate methods lead to nasty
|
||||
// behaviour in eliminateCovariantMethods.
|
||||
if (m.getDeclaringClass() == c &&
|
||||
(m.isAnnotationPresent(ManagedAttribute.class) ||
|
||||
m.isAnnotationPresent(ManagedOperation.class)))
|
||||
methods.add(m);
|
||||
}
|
||||
}
|
||||
|
||||
static MBeanNotificationInfo[] findNotifications(Object moi) {
|
||||
if (!(moi instanceof NotificationBroadcaster))
|
||||
return null;
|
||||
MBeanNotificationInfo[] mbn =
|
||||
((NotificationBroadcaster) moi).getNotificationInfo();
|
||||
if (mbn == null || mbn.length == 0)
|
||||
return null;
|
||||
return findNotificationsFromAnnotations(moi.getClass());
|
||||
MBeanNotificationInfo[] result =
|
||||
new MBeanNotificationInfo[mbn.length];
|
||||
for (int i = 0; i < mbn.length; i++) {
|
||||
@ -478,11 +555,81 @@ abstract class MBeanIntrospector<M> {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MBeanNotificationInfo[] findNotificationsFromAnnotations(
|
||||
Class<?> mbeanClass) {
|
||||
Class<?> c = getAnnotatedNotificationInfoClass(mbeanClass);
|
||||
if (c == null)
|
||||
return null;
|
||||
NotificationInfo ni = c.getAnnotation(NotificationInfo.class);
|
||||
NotificationInfos nis = c.getAnnotation(NotificationInfos.class);
|
||||
List<NotificationInfo> list = newList();
|
||||
if (ni != null)
|
||||
list.add(ni);
|
||||
if (nis != null)
|
||||
list.addAll(Arrays.asList(nis.value()));
|
||||
if (list.isEmpty())
|
||||
return null;
|
||||
List<MBeanNotificationInfo> mbnis = newList();
|
||||
for (NotificationInfo x : list) {
|
||||
// The Descriptor includes any fields explicitly specified by
|
||||
// x.descriptorFields(), plus any fields from the contained
|
||||
// @Description annotation.
|
||||
Descriptor d = new ImmutableDescriptor(x.descriptorFields());
|
||||
d = ImmutableDescriptor.union(
|
||||
d, Introspector.descriptorForAnnotation(x.description()));
|
||||
MBeanNotificationInfo mbni = new MBeanNotificationInfo(
|
||||
x.types(), x.notificationClass().getName(),
|
||||
x.description().value(), d);
|
||||
mbnis.add(mbni);
|
||||
}
|
||||
return mbnis.toArray(new MBeanNotificationInfo[mbnis.size()]);
|
||||
}
|
||||
|
||||
private static final Map<Class<?>, WeakReference<Class<?>>>
|
||||
annotatedNotificationInfoClasses = newWeakHashMap();
|
||||
|
||||
private static Class<?> getAnnotatedNotificationInfoClass(Class<?> baseClass) {
|
||||
synchronized (annotatedNotificationInfoClasses) {
|
||||
WeakReference<Class<?>> wr =
|
||||
annotatedNotificationInfoClasses.get(baseClass);
|
||||
if (wr != null)
|
||||
return wr.get();
|
||||
Class<?> c = null;
|
||||
if (baseClass.isAnnotationPresent(NotificationInfo.class) ||
|
||||
baseClass.isAnnotationPresent(NotificationInfos.class)) {
|
||||
c = baseClass;
|
||||
} else {
|
||||
Class<?>[] intfs = baseClass.getInterfaces();
|
||||
for (Class<?> intf : intfs) {
|
||||
Class<?> c1 = getAnnotatedNotificationInfoClass(intf);
|
||||
if (c1 != null) {
|
||||
if (c != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Class " + baseClass.getName() + " inherits " +
|
||||
"@NotificationInfo(s) from both " +
|
||||
c.getName() + " and " + c1.getName());
|
||||
}
|
||||
c = c1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Record the result of the search. If no @NotificationInfo(s)
|
||||
// were found, c is null, and we store a WeakReference(null).
|
||||
// This prevents us from having to search again and fail again.
|
||||
annotatedNotificationInfoClasses.put(baseClass,
|
||||
new WeakReference<Class<?>>(c));
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
private static MBeanConstructorInfo[] findConstructors(Class<?> c) {
|
||||
Constructor[] cons = c.getConstructors();
|
||||
MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length];
|
||||
for (int i = 0; i < cons.length; i++) {
|
||||
final String descr = "Public constructor of the MBean";
|
||||
String descr = "Public constructor of the MBean";
|
||||
Description d = cons[i].getAnnotation(Description.class);
|
||||
if (d != null)
|
||||
descr = d.value();
|
||||
mbc[i] = new MBeanConstructorInfo(descr, cons[i]);
|
||||
}
|
||||
return mbc;
|
||||
|
@ -263,10 +263,14 @@ public abstract class MBeanSupport<M>
|
||||
return resource.getClass().getName();
|
||||
}
|
||||
|
||||
public final Object getResource() {
|
||||
public final Object getWrappedObject() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public final ClassLoader getWrappedClassLoader() {
|
||||
return resource.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
public final Class<?> getMBeanInterface() {
|
||||
return perInterface.getMBeanInterface();
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.Description;
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.IntrospectionException;
|
||||
@ -43,6 +44,7 @@ import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
|
||||
@ -180,7 +182,10 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
final boolean isWritable = (setter != null);
|
||||
final boolean isIs = isReadable && getName(getter).startsWith("is");
|
||||
|
||||
final String description = attributeName;
|
||||
final String description = getAttributeDescription(
|
||||
attributeName, attributeName,
|
||||
getter == null ? null : getter.getMethod(),
|
||||
setter == null ? null : setter.getMethod());
|
||||
|
||||
final OpenType<?> openType;
|
||||
final Type originalType;
|
||||
@ -229,13 +234,17 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
MBeanOperationInfo getMBeanOperationInfo(String operationName,
|
||||
ConvertingMethod operation) {
|
||||
final Method method = operation.getMethod();
|
||||
final String description = operationName;
|
||||
String description = operationName;
|
||||
/* Ideally this would be an empty string, but
|
||||
OMBOperationInfo constructor forbids that. Also, we
|
||||
could consult an annotation to get a useful
|
||||
description. */
|
||||
OMBOperationInfo constructor forbids that. */
|
||||
Description d = method.getAnnotation(Description.class);
|
||||
if (d != null)
|
||||
description = d.value();
|
||||
|
||||
final int impact = MBeanOperationInfo.UNKNOWN;
|
||||
int impact = MBeanOperationInfo.UNKNOWN;
|
||||
ManagedOperation annot = method.getAnnotation(ManagedOperation.class);
|
||||
if (annot != null)
|
||||
impact = annot.impact().getCode();
|
||||
|
||||
final OpenType<?> returnType = operation.getOpenReturnType();
|
||||
final Type originalReturnType = operation.getGenericReturnType();
|
||||
@ -247,8 +256,15 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
boolean openParameterTypes = true;
|
||||
Annotation[][] annots = method.getParameterAnnotations();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
final String paramName = "p" + i;
|
||||
final String paramDescription = paramName;
|
||||
String paramName = Introspector.nameForParameter(annots[i]);
|
||||
if (paramName == null)
|
||||
paramName = "p" + i;
|
||||
|
||||
String paramDescription =
|
||||
Introspector.descriptionForParameter(annots[i]);
|
||||
if (paramDescription == null)
|
||||
paramDescription = paramName;
|
||||
|
||||
final OpenType<?> openType = paramTypes[i];
|
||||
final Type originalType = originalParamTypes[i];
|
||||
Descriptor descriptor =
|
||||
|
@ -161,7 +161,7 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
|
||||
synchronized (lock) {
|
||||
this.mxbeanLookup = MXBeanLookup.Plain.lookupFor(server);
|
||||
this.mxbeanLookup.addReference(name, getResource());
|
||||
this.mxbeanLookup.addReference(name, getWrappedObject());
|
||||
this.objectName = name;
|
||||
}
|
||||
}
|
||||
@ -170,7 +170,7 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
public void unregister() {
|
||||
synchronized (lock) {
|
||||
if (mxbeanLookup != null) {
|
||||
if (mxbeanLookup.removeReference(objectName, getResource()))
|
||||
if (mxbeanLookup.removeReference(objectName, getWrappedObject()))
|
||||
objectName = null;
|
||||
}
|
||||
// XXX: need to revisit the whole register/unregister logic in
|
||||
|
186
jdk/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java
Normal file
186
jdk/src/share/classes/com/sun/jmx/mbeanserver/NotifySupport.java
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.DynamicWrapperMBean;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanRegistration;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
|
||||
/**
|
||||
* Create wrappers for DynamicMBean that implement NotificationEmitter
|
||||
* and SendNotification.
|
||||
*/
|
||||
public class NotifySupport
|
||||
implements DynamicMBean2, NotificationEmitter, MBeanRegistration {
|
||||
|
||||
private final DynamicMBean mbean;
|
||||
private final NotificationBroadcasterSupport nbs;
|
||||
|
||||
public static DynamicMBean wrap(
|
||||
DynamicMBean mbean, NotificationBroadcasterSupport nbs) {
|
||||
return new NotifySupport(mbean, nbs);
|
||||
}
|
||||
|
||||
private NotifySupport(DynamicMBean mbean, NotificationBroadcasterSupport nbs) {
|
||||
this.mbean = mbean;
|
||||
this.nbs = nbs;
|
||||
}
|
||||
|
||||
public static NotificationBroadcasterSupport getNB(DynamicMBean mbean) {
|
||||
if (mbean instanceof NotifySupport)
|
||||
return ((NotifySupport) mbean).nbs;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
return ((DynamicMBean2) mbean).getClassName();
|
||||
Object w = mbean;
|
||||
if (w instanceof DynamicWrapperMBean)
|
||||
w = ((DynamicWrapperMBean) w).getWrappedObject();
|
||||
return w.getClass().getName();
|
||||
}
|
||||
|
||||
public void preRegister2(MBeanServer mbs, ObjectName name) throws Exception {
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
((DynamicMBean2) mbean).preRegister2(mbs, name);
|
||||
}
|
||||
|
||||
public void registerFailed() {
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
((DynamicMBean2) mbean).registerFailed();
|
||||
}
|
||||
|
||||
public Object getWrappedObject() {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedObject();
|
||||
else
|
||||
return mbean;
|
||||
}
|
||||
|
||||
public ClassLoader getWrappedClassLoader() {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
|
||||
else
|
||||
return mbean.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
public Object getAttribute(String attribute) throws AttributeNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
return mbean.getAttribute(attribute);
|
||||
}
|
||||
|
||||
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
mbean.setAttribute(attribute);
|
||||
}
|
||||
|
||||
public AttributeList setAttributes(AttributeList attributes) {
|
||||
return mbean.setAttributes(attributes);
|
||||
}
|
||||
|
||||
public Object invoke(String actionName, Object[] params, String[] signature)
|
||||
throws MBeanException, ReflectionException {
|
||||
return mbean.invoke(actionName, params, signature);
|
||||
}
|
||||
|
||||
public MBeanInfo getMBeanInfo() {
|
||||
return mbean.getMBeanInfo();
|
||||
}
|
||||
|
||||
public AttributeList getAttributes(String[] attributes) {
|
||||
return mbean.getAttributes(attributes);
|
||||
}
|
||||
|
||||
public void removeNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback) throws ListenerNotFoundException {
|
||||
nbs.removeNotificationListener(listener, filter, handback);
|
||||
}
|
||||
|
||||
public void removeNotificationListener(NotificationListener listener)
|
||||
throws ListenerNotFoundException {
|
||||
nbs.removeNotificationListener(listener);
|
||||
}
|
||||
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
return nbs.getNotificationInfo();
|
||||
}
|
||||
|
||||
public void addNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback) {
|
||||
nbs.addNotificationListener(listener, filter, handback);
|
||||
}
|
||||
|
||||
public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
|
||||
if (mbr() != null)
|
||||
return mbr().preRegister(server, name);
|
||||
else
|
||||
return name;
|
||||
}
|
||||
|
||||
public void postRegister(Boolean registrationDone) {
|
||||
if (mbr() != null)
|
||||
mbr().postRegister(registrationDone);
|
||||
}
|
||||
|
||||
public void preDeregister() throws Exception {
|
||||
if (mbr() != null)
|
||||
mbr().preDeregister();
|
||||
}
|
||||
|
||||
public void postDeregister() {
|
||||
if (mbr() != null)
|
||||
mbr().postDeregister();
|
||||
}
|
||||
|
||||
private MBeanRegistration mbr() {
|
||||
if (mbean instanceof MBeanRegistration)
|
||||
return (MBeanRegistration) mbean;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import com.sun.jmx.defaults.ServiceName;
|
||||
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -39,7 +40,6 @@ import java.util.Set;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
@ -52,6 +52,27 @@ import javax.management.RuntimeOperationsException;
|
||||
*/
|
||||
public class Repository {
|
||||
|
||||
/**
|
||||
* An interface that allows the caller to get some control
|
||||
* over the registration.
|
||||
* @see #addMBean
|
||||
* @see #remove
|
||||
*/
|
||||
public interface RegistrationContext {
|
||||
/**
|
||||
* Called by {@link #addMBean}.
|
||||
* Can throw a RuntimeOperationsException to cancel the
|
||||
* registration.
|
||||
*/
|
||||
public void registering();
|
||||
|
||||
/**
|
||||
* Called by {@link #remove}.
|
||||
* Any exception thrown by this method will be ignored.
|
||||
*/
|
||||
public void unregistered();
|
||||
}
|
||||
|
||||
// Private fields -------------------------------------------->
|
||||
|
||||
/**
|
||||
@ -115,7 +136,6 @@ public class Repository {
|
||||
/**
|
||||
* Builds a new ObjectNamePattern object from an ObjectName pattern
|
||||
* constituents.
|
||||
* @param domain pattern.getDomain().
|
||||
* @param propertyListPattern pattern.isPropertyListPattern().
|
||||
* @param propertyValuePattern pattern.isPropertyValuePattern().
|
||||
* @param canonicalProps pattern.getCanonicalKeyPropertyListString().
|
||||
@ -216,16 +236,6 @@ public class Repository {
|
||||
}
|
||||
}
|
||||
|
||||
private void addNewDomMoi(final DynamicMBean object, final String dom,
|
||||
final ObjectName name) {
|
||||
final Map<String,NamedObject> moiTb =
|
||||
new HashMap<String,NamedObject>();
|
||||
moiTb.put(name.getCanonicalKeyPropertyListString(),
|
||||
new NamedObject(name, object));
|
||||
domainTb.put(dom, moiTb);
|
||||
nbElements++;
|
||||
}
|
||||
|
||||
/** Match a string against a shell-style pattern. The only pattern
|
||||
characters recognised are <code>?</code>, standing for any one
|
||||
character, and <code>*</code>, standing for any string of
|
||||
@ -306,6 +316,50 @@ public class Repository {
|
||||
}
|
||||
}
|
||||
|
||||
private void addNewDomMoi(final DynamicMBean object,
|
||||
final String dom,
|
||||
final ObjectName name,
|
||||
final RegistrationContext context) {
|
||||
final Map<String,NamedObject> moiTb =
|
||||
new HashMap<String,NamedObject>();
|
||||
final String key = name.getCanonicalKeyPropertyListString();
|
||||
addMoiToTb(object,name,key,moiTb,context);
|
||||
domainTb.put(dom, moiTb);
|
||||
nbElements++;
|
||||
}
|
||||
|
||||
private void registering(RegistrationContext context) {
|
||||
if (context == null) return;
|
||||
try {
|
||||
context.registering();
|
||||
} catch (RuntimeOperationsException x) {
|
||||
throw x;
|
||||
} catch (RuntimeException x) {
|
||||
throw new RuntimeOperationsException(x);
|
||||
}
|
||||
}
|
||||
|
||||
private void unregistering(RegistrationContext context, ObjectName name) {
|
||||
if (context == null) return;
|
||||
try {
|
||||
context.unregistered();
|
||||
} catch (Exception x) {
|
||||
// shouldn't come here...
|
||||
MBEANSERVER_LOGGER.log(Level.FINE,
|
||||
"Unexpected exception while unregistering "+name,
|
||||
x);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMoiToTb(final DynamicMBean object,
|
||||
final ObjectName name,
|
||||
final String key,
|
||||
final Map<String,NamedObject> moiTb,
|
||||
final RegistrationContext context) {
|
||||
registering(context);
|
||||
moiTb.put(key,new NamedObject(name, object));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the named object contained in repository
|
||||
* from the given objectname.
|
||||
@ -355,12 +409,12 @@ public class Repository {
|
||||
domainTb = new HashMap<String,Map<String,NamedObject>>(5);
|
||||
|
||||
if (domain != null && domain.length() != 0)
|
||||
this.domain = domain;
|
||||
this.domain = domain.intern(); // we use == domain later on...
|
||||
else
|
||||
this.domain = ServiceName.DOMAIN;
|
||||
|
||||
// Creates an new hastable for the default domain
|
||||
domainTb.put(this.domain.intern(), new HashMap<String,NamedObject>());
|
||||
// Creates a new hashtable for the default domain
|
||||
domainTb.put(this.domain, new HashMap<String,NamedObject>());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -395,10 +449,21 @@ public class Repository {
|
||||
/**
|
||||
* Stores an MBean associated with its object name in the repository.
|
||||
*
|
||||
* @param object MBean to be stored in the repository.
|
||||
* @param name MBean object name.
|
||||
* @param object MBean to be stored in the repository.
|
||||
* @param name MBean object name.
|
||||
* @param context A registration context. If non null, the repository
|
||||
* will call {@link RegistrationContext#registering()
|
||||
* context.registering()} from within the repository
|
||||
* lock, when it has determined that the {@code object}
|
||||
* can be stored in the repository with that {@code name}.
|
||||
* If {@link RegistrationContext#registering()
|
||||
* context.registering()} throws an exception, the
|
||||
* operation is abandonned, the MBean is not added to the
|
||||
* repository, and a {@link RuntimeOperationsException}
|
||||
* is thrown.
|
||||
*/
|
||||
public void addMBean(final DynamicMBean object, ObjectName name)
|
||||
public void addMBean(final DynamicMBean object, ObjectName name,
|
||||
final RegistrationContext context)
|
||||
throws InstanceAlreadyExistsException {
|
||||
|
||||
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
|
||||
@ -431,7 +496,7 @@ public class Repository {
|
||||
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
// Domain cannot be JMImplementation if entry does not exists
|
||||
// Domain cannot be JMImplementation if entry does not exist
|
||||
if ( !to_default_domain &&
|
||||
dom.equals("JMImplementation") &&
|
||||
domainTb.containsKey("JMImplementation")) {
|
||||
@ -440,21 +505,21 @@ public class Repository {
|
||||
"Repository: domain name cannot be JMImplementation"));
|
||||
}
|
||||
|
||||
// If domain not already exists, add it to the hash table
|
||||
// If domain does not already exist, add it to the hash table
|
||||
final Map<String,NamedObject> moiTb = domainTb.get(dom);
|
||||
if (moiTb == null) {
|
||||
addNewDomMoi(object, dom, name);
|
||||
addNewDomMoi(object, dom, name, context);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add instance if not already present
|
||||
String cstr = name.getCanonicalKeyPropertyListString();
|
||||
NamedObject elmt= moiTb.get(cstr);
|
||||
if (elmt != null) {
|
||||
throw new InstanceAlreadyExistsException(name.toString());
|
||||
} else {
|
||||
nbElements++;
|
||||
moiTb.put(cstr, new NamedObject(name, object));
|
||||
// Add instance if not already present
|
||||
String cstr = name.getCanonicalKeyPropertyListString();
|
||||
NamedObject elmt= moiTb.get(cstr);
|
||||
if (elmt != null) {
|
||||
throw new InstanceAlreadyExistsException(name.toString());
|
||||
} else {
|
||||
nbElements++;
|
||||
addMoiToTb(object,name,cstr,moiTb,context);
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
@ -533,7 +598,7 @@ public class Repository {
|
||||
// ":*", ":[key=value],*" : names in defaultDomain
|
||||
// "domain:*", "domain:[key=value],*" : names in the specified domain
|
||||
|
||||
// Surely one of the most frequent case ... query on the whole world
|
||||
// Surely one of the most frequent cases ... query on the whole world
|
||||
ObjectName name;
|
||||
if (pattern == null ||
|
||||
pattern.getCanonicalName().length() == 0 ||
|
||||
@ -546,8 +611,7 @@ public class Repository {
|
||||
|
||||
// If pattern is not a pattern, retrieve this mbean !
|
||||
if (!name.isPattern()) {
|
||||
final NamedObject no;
|
||||
no = retrieveNamedObject(name);
|
||||
final NamedObject no = retrieveNamedObject(name);
|
||||
if (no != null) result.add(no);
|
||||
return result;
|
||||
}
|
||||
@ -577,12 +641,22 @@ public class Repository {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!name.isDomainPattern()) {
|
||||
final Map<String,NamedObject> moiTb = domainTb.get(name.getDomain());
|
||||
if (moiTb == null) return Collections.emptySet();
|
||||
if (allNames)
|
||||
result.addAll(moiTb.values());
|
||||
else
|
||||
addAllMatching(moiTb, result, namePattern);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Pattern matching in the domain name (*, ?)
|
||||
char[] dom2Match = name.getDomain().toCharArray();
|
||||
for (String domain : domainTb.keySet()) {
|
||||
char[] theDom = domain.toCharArray();
|
||||
for (String dom : domainTb.keySet()) {
|
||||
char[] theDom = dom.toCharArray();
|
||||
if (wildmatch(theDom, dom2Match)) {
|
||||
final Map<String,NamedObject> moiTb = domainTb.get(domain);
|
||||
final Map<String,NamedObject> moiTb = domainTb.get(dom);
|
||||
if (allNames)
|
||||
result.addAll(moiTb.values());
|
||||
else
|
||||
@ -599,11 +673,21 @@ public class Repository {
|
||||
* Removes an MBean from the repository.
|
||||
*
|
||||
* @param name name of the MBean to remove.
|
||||
* @param context A registration context. If non null, the repository
|
||||
* will call {@link RegistrationContext#unregistered()
|
||||
* context.unregistered()} from within the repository
|
||||
* lock, just after the mbean associated with
|
||||
* {@code name} is removed from the repository.
|
||||
* If {@link RegistrationContext#unregistered()
|
||||
* context.unregistered()} is not expected to throw any
|
||||
* exception. If it does, the exception is logged
|
||||
* and swallowed.
|
||||
*
|
||||
* @exception InstanceNotFoundException The MBean does not exist in
|
||||
* the repository.
|
||||
*/
|
||||
public void remove(final ObjectName name)
|
||||
public void remove(final ObjectName name,
|
||||
final RegistrationContext context)
|
||||
throws InstanceNotFoundException {
|
||||
|
||||
// Debugging stuff
|
||||
@ -645,6 +729,9 @@ public class Repository {
|
||||
if (dom == domain)
|
||||
domainTb.put(domain, new HashMap<String,NamedObject>());
|
||||
}
|
||||
|
||||
unregistering(context,name);
|
||||
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import javax.management.IntrospectionException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationBroadcaster;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
@ -118,22 +119,32 @@ class StandardMBeanIntrospector extends MBeanIntrospector<Method> {
|
||||
|
||||
@Override
|
||||
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
||||
Method getter, Method setter) {
|
||||
Method getter, Method setter) throws IntrospectionException {
|
||||
|
||||
final String description = "Attribute exposed for management";
|
||||
try {
|
||||
return new MBeanAttributeInfo(attributeName, description,
|
||||
getter, setter);
|
||||
} catch (IntrospectionException e) {
|
||||
throw new RuntimeException(e); // should not happen
|
||||
}
|
||||
String description = getAttributeDescription(
|
||||
attributeName, "Attribute exposed for management",
|
||||
getter, setter);
|
||||
return new MBeanAttributeInfo(attributeName, description,
|
||||
getter, setter);
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanOperationInfo getMBeanOperationInfo(String operationName,
|
||||
Method operation) {
|
||||
final String description = "Operation exposed for management";
|
||||
return new MBeanOperationInfo(description, operation);
|
||||
final String defaultDescription = "Operation exposed for management";
|
||||
String description = Introspector.descriptionForElement(operation);
|
||||
if (description == null)
|
||||
description = defaultDescription;
|
||||
|
||||
int impact = MBeanOperationInfo.UNKNOWN;
|
||||
ManagedOperation annot = operation.getAnnotation(ManagedOperation.class);
|
||||
if (annot != null)
|
||||
impact = annot.impact().getCode();
|
||||
|
||||
MBeanOperationInfo mboi = new MBeanOperationInfo(description, operation);
|
||||
return new MBeanOperationInfo(
|
||||
mboi.getName(), mboi.getDescription(), mboi.getSignature(),
|
||||
mboi.getReturnType(), impact, mboi.getDescriptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,26 +41,24 @@ import javax.management.openmbean.MXBeanMappingFactory;
|
||||
public class StandardMBeanSupport extends MBeanSupport<Method> {
|
||||
|
||||
/**
|
||||
<p>Construct a Standard MBean that wraps the given resource using the
|
||||
given Standard MBean interface.</p>
|
||||
|
||||
@param resource the underlying resource for the new MBean.
|
||||
|
||||
@param mbeanInterface the interface to be used to determine
|
||||
the MBean's management interface.
|
||||
|
||||
@param <T> a type parameter that allows the compiler to check
|
||||
that {@code resource} implements {@code mbeanInterface},
|
||||
provided that {@code mbeanInterface} is a class constant like
|
||||
{@code SomeMBean.class}.
|
||||
|
||||
@throws IllegalArgumentException if {@code resource} is null or
|
||||
if it does not implement the class {@code mbeanInterface} or if
|
||||
that class is not a valid Standard MBean interface.
|
||||
*/
|
||||
public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterface)
|
||||
* <p>Construct a Standard MBean that wraps the given resource using the
|
||||
* given Standard MBean interface.</p>
|
||||
*
|
||||
* @param resource the underlying resource for the new MBean.
|
||||
* @param mbeanInterfaceType the class or interface to be used to determine
|
||||
* the MBean's management interface. An interface if this is a
|
||||
* classic Standard MBean; a class if this is a {@code @ManagedResource}.
|
||||
* @param <T> a type parameter that allows the compiler to check
|
||||
* that {@code resource} implements {@code mbeanInterfaceType},
|
||||
* provided that {@code mbeanInterfaceType} is a class constant like
|
||||
* {@code SomeMBean.class}.
|
||||
* @throws IllegalArgumentException if {@code resource} is null or
|
||||
* if it does not implement the class {@code mbeanInterfaceType} or if
|
||||
* that class is not a valid Standard MBean interface.
|
||||
*/
|
||||
public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterfaceType)
|
||||
throws NotCompliantMBeanException {
|
||||
super(resource, mbeanInterface, (MXBeanMappingFactory) null);
|
||||
super(resource, mbeanInterfaceType, (MXBeanMappingFactory) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -86,13 +84,14 @@ public class StandardMBeanSupport extends MBeanSupport<Method> {
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo() {
|
||||
MBeanInfo mbi = super.getMBeanInfo();
|
||||
Class<?> resourceClass = getResource().getClass();
|
||||
if (StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass))
|
||||
Class<?> resourceClass = getWrappedObject().getClass();
|
||||
if (!getMBeanInterface().isInterface() ||
|
||||
StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass))
|
||||
return mbi;
|
||||
return new MBeanInfo(mbi.getClassName(), mbi.getDescription(),
|
||||
mbi.getAttributes(), mbi.getConstructors(),
|
||||
mbi.getOperations(),
|
||||
MBeanIntrospector.findNotifications(getResource()),
|
||||
MBeanIntrospector.findNotifications(getWrappedObject()),
|
||||
mbi.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
@ -71,6 +72,10 @@ public class Util {
|
||||
return new LinkedHashMap<K, V>();
|
||||
}
|
||||
|
||||
static <K, V> WeakHashMap<K, V> newWeakHashMap() {
|
||||
return new WeakHashMap<K, V>();
|
||||
}
|
||||
|
||||
static <E> Set<E> newSet() {
|
||||
return new HashSet<E>();
|
||||
}
|
||||
|
@ -192,6 +192,7 @@ class BinaryRelQueryExp extends QueryEval implements QueryExp {
|
||||
return "(" + exp1 + ") " + relOpString() + " (" + exp2 + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
String toQueryString() {
|
||||
return exp1 + " " + relOpString() + " " + exp2;
|
||||
}
|
||||
|
180
jdk/src/share/classes/javax/management/Description.java
Normal file
180
jdk/src/share/classes/javax/management/Description.java
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* <p>The textual description of an MBean or part of an MBean. This
|
||||
* description is intended to be displayed to users to help them
|
||||
* understand what the MBean does. Ultimately it will be the value of
|
||||
* the {@code getDescription()} method of an {@link MBeanInfo}, {@link
|
||||
* MBeanAttributeInfo}, or similar.</p>
|
||||
*
|
||||
* <p>This annotation applies to Standard MBean interfaces and to
|
||||
* MXBean interfaces, as well as to MBean classes defined using the
|
||||
* {@link MBean @MBean} or {@link MXBean @MXBean} annotations. For
|
||||
* example, a Standard MBean might be defined like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* <b>{@code @Description}</b>("Application configuration")
|
||||
* public interface ConfigurationMBean {
|
||||
* <b>{@code @Description}</b>("Cache size in bytes")
|
||||
* public int getCacheSize();
|
||||
* public void setCacheSize(int size);
|
||||
*
|
||||
* <b>{@code @Description}</b>("Last time the configuration was changed, " +
|
||||
* "in milliseconds since 1 Jan 1970")
|
||||
* public long getLastChangedTime();
|
||||
*
|
||||
* <b>{@code @Description}</b>("Save the configuration to a file")
|
||||
* public void save(
|
||||
* <b>{@code @Description}</b>("Optional name of the file, or null for the default name")
|
||||
* String fileName);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The {@code MBeanInfo} for this MBean will have a {@link
|
||||
* MBeanInfo#getDescription() getDescription()} that is {@code
|
||||
* "Application configuration"}. It will contain an {@code
|
||||
* MBeanAttributeInfo} for the {@code CacheSize} attribute that is
|
||||
* defined by the methods {@code getCacheSize} and {@code
|
||||
* setCacheSize}, and another {@code MBeanAttributeInfo} for {@code
|
||||
* LastChangedTime}. The {@link MBeanAttributeInfo#getDescription()
|
||||
* getDescription()} for {@code CacheSize} will be {@code "Cache size
|
||||
* in bytes"}. Notice that there is no need to add a
|
||||
* {@code @Description} to both {@code getCacheSize} and {@code
|
||||
* setCacheSize} - either alone will do. But if you do add a
|
||||
* {@code @Description} to both, it must be the same.</p>
|
||||
*
|
||||
* <p>The {@code MBeanInfo} will also contain an {@link
|
||||
* MBeanOperationInfo} where {@link
|
||||
* MBeanOperationInfo#getDescription() getDescription()} is {@code
|
||||
* "Save the configuration to a file"}. This {@code
|
||||
* MBeanOperationInfo} will contain an {@link MBeanParameterInfo}
|
||||
* where {@link MBeanParameterInfo#getDescription() getDescription()}
|
||||
* is {@code "Optional name of the file, or null for the default
|
||||
* name"}.</p>
|
||||
*
|
||||
* <p>The {@code @Description} annotation can also be applied to the
|
||||
* public constructors of the implementation class. Continuing the
|
||||
* above example, the {@code Configuration} class implementing {@code
|
||||
* ConfigurationMBean} might look like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public class Configuration implements ConfigurationMBean {
|
||||
* <b>{@code @Description}</b>("A Configuration MBean with the default file name")
|
||||
* public Configuration() {
|
||||
* this(DEFAULT_FILE_NAME);
|
||||
* }
|
||||
*
|
||||
* <b>{@code @Description}</b>("A Configuration MBean with a specified file name")
|
||||
* public Configuration(
|
||||
* <b>{@code @Description}</b>("Name of the file the configuration is stored in")
|
||||
* String fileName) {...}
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The {@code @Description} annotation also works in MBeans that
|
||||
* are defined using the {@code @MBean} or {@code @MXBean} annotation
|
||||
* on classes. Here is an alternative implementation of {@code
|
||||
* Configuration} that does not use an {@code ConfigurationMBean}
|
||||
* interface.</p>
|
||||
*
|
||||
* <pre>
|
||||
* <b>{@code @MBean}</b>
|
||||
* <b>{@code @Description}</b>("Application configuration")
|
||||
* public class Configuration {
|
||||
* <b>{@code @Description}</b>("A Configuration MBean with the default file name")
|
||||
* public Configuration() {
|
||||
* this(DEFAULT_FILE_NAME);
|
||||
* }
|
||||
*
|
||||
* <b>{@code @Description}</b>("A Configuration MBean with a specified file name")
|
||||
* public Configuration(
|
||||
* <b>{@code @Description}</b>("Name of the file the configuration is stored in")
|
||||
* String fileName) {...}
|
||||
*
|
||||
* <b>{@code @ManagedAttribute}</b>
|
||||
* <b>{@code @Description}</b>("Cache size in bytes")
|
||||
* public int getCacheSize() {...}
|
||||
* <b>{@code @ManagedAttribute}</b>
|
||||
* public void setCacheSize(int size) {...}
|
||||
*
|
||||
* <b>{@code @ManagedOperation}</b>
|
||||
* <b>{@code @Description}</b>("Last time the configuration was changed, " +
|
||||
* "in milliseconds since 1 Jan 1970")
|
||||
* public long getLastChangedTime() {...}
|
||||
*
|
||||
* <b>{@code @ManagedOperation}</b>
|
||||
* <b>{@code @Description}</b>("Save the configuration to a file")
|
||||
* public void save(
|
||||
* <b>{@code @Description}</b>("Optional name of the file, or null for the default name")
|
||||
* String fileName) {...}
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER,
|
||||
ElementType.TYPE})
|
||||
public @interface Description {
|
||||
/**
|
||||
* <p>The description.</p>
|
||||
*/
|
||||
String value();
|
||||
|
||||
/**
|
||||
* <p>The base name for the {@link ResourceBundle} in which the key given in
|
||||
* the {@code descriptionResourceKey} field can be found, for example
|
||||
* {@code "com.example.myapp.MBeanResources"}. If a non-default value
|
||||
* is supplied for this element, it will appear in the
|
||||
* <a href="Descriptor.html#descriptionResourceBundleBaseName"><!--
|
||||
* -->{@code Descriptor}</a> for the annotated item.</p>
|
||||
*/
|
||||
@DescriptorKey(
|
||||
value = "descriptionResourceBundleBaseName", omitIfDefault = true)
|
||||
String bundleBaseName() default "";
|
||||
|
||||
/**
|
||||
* <p>A resource key for the description of this element. In
|
||||
* conjunction with the {@link #bundleBaseName bundleBaseName},
|
||||
* this can be used to find a localized version of the description.
|
||||
* If a non-default value
|
||||
* is supplied for this element, it will appear in the
|
||||
* <a href="Descriptor.html#descriptionResourceKey"><!--
|
||||
* -->{@code Descriptor}</a> for the annotated item.</p>
|
||||
*/
|
||||
@DescriptorKey(value = "descriptionResourceKey", omitIfDefault = true)
|
||||
String key() default "";
|
||||
}
|
@ -38,6 +38,7 @@ import java.util.Arrays;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanParameterInfoSupport;
|
||||
@ -117,21 +118,19 @@ import javax.management.openmbean.OpenType;
|
||||
* deprecation, for example {@code "1.3 Replaced by the Capacity
|
||||
* attribute"}.</td>
|
||||
*
|
||||
* <tr><td>descriptionResource<br>BundleBaseName</td><td>String</td><td>Any</td>
|
||||
* <tr id="descriptionResourceBundleBaseName">
|
||||
* <td>descriptionResource<br>BundleBaseName</td><td>String</td><td>Any</td>
|
||||
*
|
||||
* <td>The base name for the {@link ResourceBundle} in which the key given in
|
||||
* the {@code descriptionResourceKey} field can be found, for example
|
||||
* {@code "com.example.myapp.MBeanResources"}. The meaning of this
|
||||
* field is defined by this specification but the field is not set or
|
||||
* used by the JMX API itself.</td>
|
||||
* {@code "com.example.myapp.MBeanResources"}.</td>
|
||||
*
|
||||
* <tr><td>descriptionResourceKey</td><td>String</td><td>Any</td>
|
||||
* <tr id="descriptionResourceKey">
|
||||
* <td>descriptionResourceKey</td><td>String</td><td>Any</td>
|
||||
*
|
||||
* <td>A resource key for the description of this element. In
|
||||
* conjunction with the {@code descriptionResourceBundleBaseName},
|
||||
* this can be used to find a localized version of the description.
|
||||
* The meaning of this field is defined by this specification but the
|
||||
* field is not set or used by the JMX API itself.</td>
|
||||
* this can be used to find a localized version of the description.</td>
|
||||
*
|
||||
* <tr><td>enabled</td><td>String</td>
|
||||
* <td>MBeanAttributeInfo<br>MBeanNotificationInfo<br>MBeanOperationInfo</td>
|
||||
@ -216,6 +215,14 @@ import javax.management.openmbean.OpenType;
|
||||
* StandardMBean} class will have this field in its MBeanInfo
|
||||
* Descriptor.</td>
|
||||
*
|
||||
* <tr><td id="mxbeanMappingFactoryClass"><i>mxbeanMappingFactoryClass</i>
|
||||
* </td><td>String</td>
|
||||
* <td>MBeanInfo</td>
|
||||
*
|
||||
* <td>The name of the {@link MXBeanMappingFactory} class that was used for this
|
||||
* MXBean, if it was not the {@linkplain MXBeanMappingFactory#DEFAULT default}
|
||||
* one.</td>
|
||||
*
|
||||
* <tr><td><a name="openType"><i>openType</i></a><td>{@link OpenType}</td>
|
||||
* <td>MBeanAttributeInfo<br>MBeanOperationInfo<br>MBeanParameterInfo</td>
|
||||
*
|
||||
|
137
jdk/src/share/classes/javax/management/DescriptorFields.java
Normal file
137
jdk/src/share/classes/javax/management/DescriptorFields.java
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Annotation that adds fields to a {@link Descriptor}. This can be the
|
||||
* Descriptor for an MBean, or for an attribute, operation, or constructor
|
||||
* in an MBean, or for a parameter of an operation or constructor.</p>
|
||||
*
|
||||
* <p>Consider this Standard MBean interface, for example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public interface CacheControlMBean {
|
||||
* <b>@DescriptorFields("units=bytes")</b>
|
||||
* public long getCacheSize();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>When a Standard MBean is made using this interface, the usual rules
|
||||
* mean that it will have an attribute called {@code CacheSize} of type
|
||||
* {@code long}. The {@code DescriptorFields} annotation will ensure
|
||||
* that the {@link MBeanAttributeInfo} for this attribute will have a
|
||||
* {@code Descriptor} that has a field called {@code units} with
|
||||
* corresponding value {@code bytes}.</p>
|
||||
*
|
||||
* <p>Similarly, if the interface looks like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public interface CacheControlMBean {
|
||||
* <b>@DescriptorFields({"units=bytes", "since=1.5"})</b>
|
||||
* public long getCacheSize();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>then the resulting {@code Descriptor} will contain the following
|
||||
* fields:</p>
|
||||
*
|
||||
* <table border="2">
|
||||
* <tr><th>Name</th><th>Value</th></tr>
|
||||
* <tr><td>units</td><td>"bytes"</td></tr>
|
||||
* <tr><td>since</td><td>"1.5"</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>The {@code @DescriptorFields} annotation can be applied to:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>a Standard MBean or MXBean interface;
|
||||
* <li>a method in such an interface;
|
||||
* <li>a parameter of a method in a Standard MBean or MXBean interface
|
||||
* when that method is an operation (not a getter or setter for an attribute);
|
||||
* <li>a public constructor in the class that implements a Standard MBean
|
||||
* or MXBean;
|
||||
* <li>a parameter in such a constructor.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Other uses of the annotation will either fail to compile or be
|
||||
* ignored.</p>
|
||||
*
|
||||
* <p>Interface annotations are checked only on the exact interface
|
||||
* that defines the management interface of a Standard MBean or an
|
||||
* MXBean, not on its parent interfaces. Method annotations are
|
||||
* checked only in the most specific interface in which the method
|
||||
* appears; in other words, if a child interface overrides a method
|
||||
* from a parent interface, only {@code @DescriptorFields} annotations in
|
||||
* the method in the child interface are considered.
|
||||
*
|
||||
* <p>The Descriptor fields contributed in this way must be consistent
|
||||
* with each other and with any fields contributed by {@link
|
||||
* DescriptorKey @DescriptorKey} annotations. That is, two
|
||||
* different annotations, or two members of the same annotation, must
|
||||
* not define a different value for the same Descriptor field. Fields
|
||||
* from annotations on a getter method must also be consistent with
|
||||
* fields from annotations on the corresponding setter method.</p>
|
||||
*
|
||||
* <p>The Descriptor resulting from these annotations will be merged
|
||||
* with any Descriptor fields provided by the implementation, such as
|
||||
* the <a href="Descriptor.html#immutableInfo">{@code
|
||||
* immutableInfo}</a> field for an MBean. The fields from the annotations
|
||||
* must be consistent with these fields provided by the implementation.</p>
|
||||
*
|
||||
* <h4>{@literal @DescriptorFields and @DescriptorKey}</h4>
|
||||
*
|
||||
* <p>The {@link DescriptorKey @DescriptorKey} annotation provides
|
||||
* another way to use annotations to define Descriptor fields.
|
||||
* <code>@DescriptorKey</code> requires more work but is also more
|
||||
* robust, because there is less risk of mistakes such as misspelling
|
||||
* the name of the field or giving an invalid value.
|
||||
* <code>@DescriptorFields</code> is more convenient but includes
|
||||
* those risks. <code>@DescriptorFields</code> is more
|
||||
* appropriate for occasional use, but for a Descriptor field that you
|
||||
* add in many places, you should consider a purpose-built annotation
|
||||
* using <code>@DescriptorKey</code>.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
@Documented
|
||||
@Inherited // for @MBean and @MXBean classes
|
||||
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD,
|
||||
ElementType.PARAMETER, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DescriptorFields {
|
||||
/**
|
||||
* <p>The descriptor fields. Each element of the string looks like
|
||||
* {@code "name=value"}.</p>
|
||||
*/
|
||||
public String[] value();
|
||||
}
|
@ -33,6 +33,11 @@ import java.lang.annotation.*;
|
||||
* an MBean, or for an attribute, operation, or constructor in an
|
||||
* MBean, or for a parameter of an operation or constructor.</p>
|
||||
*
|
||||
* <p>(The {@link DescriptorFields @DescriptorFields} annotation
|
||||
* provides another way to add fields to a {@code Descriptor}. See
|
||||
* the documentation for that annotation for a comparison of the
|
||||
* two possibilities.)</p>
|
||||
*
|
||||
* <p>Consider this annotation for example:</p>
|
||||
*
|
||||
* <pre>
|
||||
@ -57,7 +62,7 @@ import java.lang.annotation.*;
|
||||
* <p>When a Standard MBean is made from the {@code CacheControlMBean},
|
||||
* the usual rules mean that it will have an attribute called
|
||||
* {@code CacheSize} of type {@code long}. The {@code @Units}
|
||||
* attribute, given the above definition, will ensure that the
|
||||
* annotation, given the above definition, will ensure that the
|
||||
* {@link MBeanAttributeInfo} for this attribute will have a
|
||||
* {@code Descriptor} that has a field called {@code units} with
|
||||
* corresponding value {@code bytes}.</p>
|
||||
@ -125,12 +130,13 @@ import java.lang.annotation.*;
|
||||
* the method in the child interface are considered.
|
||||
*
|
||||
* <p>The Descriptor fields contributed in this way by different
|
||||
* annotations on the same program element must be consistent. That
|
||||
* is, two different annotations, or two members of the same
|
||||
* annotation, must not define a different value for the same
|
||||
* Descriptor field. Fields from annotations on a getter method must
|
||||
* also be consistent with fields from annotations on the
|
||||
* corresponding setter method.</p>
|
||||
* annotations on the same program element must be consistent with
|
||||
* each other and with any fields contributed by a {@link
|
||||
* DescriptorFields @DescriptorFields} annotation. That is, two
|
||||
* different annotations, or two members of the same annotation, must
|
||||
* not define a different value for the same Descriptor field. Fields
|
||||
* from annotations on a getter method must also be consistent with
|
||||
* fields from annotations on the corresponding setter method.</p>
|
||||
*
|
||||
* <p>The Descriptor resulting from these annotations will be merged
|
||||
* with any Descriptor fields provided by the implementation, such as
|
||||
@ -169,4 +175,36 @@ import java.lang.annotation.*;
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface DescriptorKey {
|
||||
String value();
|
||||
|
||||
/**
|
||||
* <p>Do not include this field in the Descriptor if the annotation
|
||||
* element has its default value. For example, suppose {@code @Units} is
|
||||
* defined like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* @Documented
|
||||
* @Target(ElementType.METHOD)
|
||||
* @Retention(RetentionPolicy.RUNTIME)
|
||||
* public @interface Units {
|
||||
* @DescriptorKey("units")
|
||||
* String value();
|
||||
*
|
||||
* <b>@DescriptorKey(value = "descriptionResourceKey",
|
||||
* omitIfDefault = true)</b>
|
||||
* String resourceKey() default "";
|
||||
*
|
||||
* <b>@DescriptorKey(value = "descriptionResourceBundleBaseName",
|
||||
* omitIfDefault = true)</b>
|
||||
* String resourceBundleBaseName() default "";
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Then consider a usage such as {@code @Units("bytes")} or
|
||||
* {@code @Units(value = "bytes", resourceKey = "")}, where the
|
||||
* {@code resourceKey} and {@code resourceBundleBaseNames} elements
|
||||
* have their default values. In this case the Descriptor resulting
|
||||
* from these annotations will not include a {@code descriptionResourceKey}
|
||||
* or {@code descriptionResourceBundleBaseName} field.</p>
|
||||
*/
|
||||
boolean omitIfDefault() default false;
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2005 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
|
||||
/**
|
||||
* <p>An MBean can implement this interface to affect how the MBeanServer's
|
||||
* {@link MBeanServer#getClassLoaderFor getClassLoaderFor} and
|
||||
* {@link MBeanServer#isInstanceOf isInstanceOf} methods behave.
|
||||
* If these methods should refer to a wrapped object rather than the
|
||||
* MBean object itself, then the {@link #getWrappedObject} method should
|
||||
* return that wrapped object.</p>
|
||||
*
|
||||
* @see MBeanServer#getClassLoaderFor
|
||||
* @see MBeanServer#isInstanceOf
|
||||
*/
|
||||
public interface DynamicWrapperMBean extends DynamicMBean {
|
||||
/**
|
||||
* <p>The resource corresponding to this MBean. This is the object whose
|
||||
* class name should be reflected by the MBean's
|
||||
* {@link MBeanServer#getMBeanInfo getMBeanInfo()}.<!--
|
||||
* -->{@link MBeanInfo#getClassName getClassName()} for example. For a "plain"
|
||||
* DynamicMBean it will be "this". For an MBean that wraps another
|
||||
* object, in the manner of {@link javax.management.StandardMBean}, it will be the
|
||||
* wrapped object.</p>
|
||||
*
|
||||
* @return The resource corresponding to this MBean.
|
||||
*/
|
||||
public Object getWrappedObject();
|
||||
|
||||
/**
|
||||
* <p>The {@code ClassLoader} for this MBean, which can be used to
|
||||
* retrieve resources associated with the MBean for example. Usually,
|
||||
* it will be
|
||||
* {@link #getWrappedObject()}.{@code getClass().getClassLoader()}.
|
||||
*
|
||||
* @return The {@code ClassLoader} for this MBean.
|
||||
*/
|
||||
public ClassLoader getWrappedClassLoader();
|
||||
}
|
105
jdk/src/share/classes/javax/management/Impact.java
Normal file
105
jdk/src/share/classes/javax/management/Impact.java
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
|
||||
/**
|
||||
* <p>Defines the impact of an MBean operation, in particular whether it
|
||||
* has an effect on the MBean or simply returns information. This enum
|
||||
* is used in the {@link ManagedOperation @ManagedOperation} annotation.
|
||||
* Its {@link #getCode()} method can be used to get an {@code int} suitable
|
||||
* for use as the {@code impact} parameter in an {@link MBeanOperationInfo}
|
||||
* constructor.</p>
|
||||
*/
|
||||
public enum Impact {
|
||||
/**
|
||||
* The operation is read-like: it returns information but does not change
|
||||
* any state.
|
||||
* @see MBeanOperationInfo#INFO
|
||||
*/
|
||||
INFO(MBeanOperationInfo.INFO),
|
||||
|
||||
/**
|
||||
* The operation is write-like: it has an effect but does not return
|
||||
* any information from the MBean.
|
||||
* @see MBeanOperationInfo#ACTION
|
||||
*/
|
||||
ACTION(MBeanOperationInfo.ACTION),
|
||||
|
||||
/**
|
||||
* The operation is both read-like and write-like: it has an effect,
|
||||
* and it also returns information from the MBean.
|
||||
* @see MBeanOperationInfo#ACTION_INFO
|
||||
*/
|
||||
ACTION_INFO(MBeanOperationInfo.ACTION_INFO),
|
||||
|
||||
/**
|
||||
* The impact of the operation is unknown or cannot be expressed
|
||||
* using one of the other values.
|
||||
* @see MBeanOperationInfo#UNKNOWN
|
||||
*/
|
||||
UNKNOWN(MBeanOperationInfo.UNKNOWN);
|
||||
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* An instance of this enumeration, with the corresponding {@code int}
|
||||
* code used by the {@link MBeanOperationInfo} constructors.
|
||||
*
|
||||
* @param code the code used by the {@code MBeanOperationInfo} constructors.
|
||||
*/
|
||||
Impact(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* The equivalent {@code int} code used by the {@link MBeanOperationInfo}
|
||||
* constructors.
|
||||
* @return the {@code int} code.
|
||||
*/
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code Impact} value corresponding to the given {@code int}
|
||||
* code. The {@code code} is the value that would be used in an
|
||||
* {@code MBeanOperationInfo} constructor.
|
||||
*
|
||||
* @param code the {@code int} code.
|
||||
*
|
||||
* @return an {@code Impact} value {@code x} such that
|
||||
* {@code code == x.}{@link #getCode()}, or {@code Impact.UNKNOWN}
|
||||
* if there is no such value.
|
||||
*/
|
||||
public static Impact forCode(int code) {
|
||||
switch (code) {
|
||||
case MBeanOperationInfo.ACTION: return ACTION;
|
||||
case MBeanOperationInfo.INFO: return INFO;
|
||||
case MBeanOperationInfo.ACTION_INFO: return ACTION_INFO;
|
||||
default: return UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@
|
||||
package javax.management;
|
||||
|
||||
import com.sun.jmx.mbeanserver.Introspector;
|
||||
import com.sun.jmx.mbeanserver.MBeanInjector;
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
@ -130,6 +131,7 @@ public class JMX {
|
||||
* </pre>
|
||||
*
|
||||
* @see javax.management.JMX.ProxyOptions
|
||||
* @see javax.management.StandardMBean.Options
|
||||
*/
|
||||
public static class MBeanOptions implements Serializable, Cloneable {
|
||||
private static final long serialVersionUID = -6380842449318177843L;
|
||||
@ -739,4 +741,28 @@ public class JMX {
|
||||
// exactly the string "MXBean" since that would mean there
|
||||
// was no package name, which is pretty unlikely in practice.
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Test if an MBean can emit notifications. An MBean can emit
|
||||
* notifications if either it implements {@link NotificationBroadcaster}
|
||||
* (perhaps through its child interface {@link NotificationEmitter}), or
|
||||
* it uses <a href="MBeanRegistration.html#injection">resource
|
||||
* injection</a> to obtain an instance of {@link SendNotification}
|
||||
* through which it can send notifications.</p>
|
||||
*
|
||||
* @param mbean an MBean object.
|
||||
* @return true if the given object is a valid MBean that can emit
|
||||
* notifications; false if the object is a valid MBean but that
|
||||
* cannot emit notifications.
|
||||
* @throws NotCompliantMBeanException if the given object is not
|
||||
* a valid MBean.
|
||||
*/
|
||||
public static boolean isNotificationSource(Object mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mbean instanceof NotificationBroadcaster)
|
||||
return true;
|
||||
Object resource = (mbean instanceof DynamicWrapperMBean) ?
|
||||
((DynamicWrapperMBean) mbean).getWrappedObject() : mbean;
|
||||
return (MBeanInjector.injectsSendNotification(resource));
|
||||
}
|
||||
}
|
||||
|
68
jdk/src/share/classes/javax/management/MBean.java
Normal file
68
jdk/src/share/classes/javax/management/MBean.java
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Indicates that the annotated class is a Standard MBean. A Standard
|
||||
* MBean class can be defined as in this example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* {@code @MBean}
|
||||
* public class Configuration {
|
||||
* {@link ManagedAttribute @ManagedAttribute}
|
||||
* public int getCacheSize() {...}
|
||||
* {@code @ManagedAttribute}
|
||||
* public void setCacheSize(int size);
|
||||
*
|
||||
* {@code @ManagedAttribute}
|
||||
* public long getLastChangedTime();
|
||||
*
|
||||
* {@link ManagedOperation @ManagedOperation}
|
||||
* public void save();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The class must be public. Public methods within the class can be
|
||||
* annotated with {@code @ManagedOperation} to indicate that they are
|
||||
* MBean operations. Public getter and setter methods within the class
|
||||
* can be annotated with {@code @ManagedAttribute} to indicate that they define
|
||||
* MBean attributes.</p>
|
||||
*
|
||||
* <p>If the MBean is to be an MXBean rather than a Standard MBean, then
|
||||
* the {@link MXBean @MXBean} annotation must be used instead of
|
||||
* {@code @MBean}.</p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Inherited
|
||||
public @interface MBean {
|
||||
}
|
@ -46,25 +46,30 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
new MBeanOperationInfo[0];
|
||||
|
||||
/**
|
||||
* Indicates that the operation is read-like,
|
||||
* it basically returns information.
|
||||
* Indicates that the operation is read-like:
|
||||
* it returns information but does not change any state.
|
||||
* @see Impact#INFO
|
||||
*/
|
||||
public static final int INFO = 0;
|
||||
|
||||
/**
|
||||
* Indicates that the operation is a write-like,
|
||||
* and would modify the MBean in some way, typically by writing some value
|
||||
* or changing a configuration.
|
||||
* Indicates that the operation is write-like: it has an effect but does
|
||||
* not return any information from the MBean.
|
||||
* @see Impact#ACTION
|
||||
*/
|
||||
public static final int ACTION = 1;
|
||||
|
||||
/**
|
||||
* Indicates that the operation is both read-like and write-like.
|
||||
* Indicates that the operation is both read-like and write-like:
|
||||
* it has an effect, and it also returns information from the MBean.
|
||||
* @see Impact#ACTION_INFO
|
||||
*/
|
||||
public static final int ACTION_INFO = 2;
|
||||
|
||||
/**
|
||||
* Indicates that the operation has an "unknown" nature.
|
||||
* Indicates that the impact of the operation is unknown or cannot be
|
||||
* expressed using one of the other values.
|
||||
* @see Impact#UNKNOWN
|
||||
*/
|
||||
public static final int UNKNOWN = 3;
|
||||
|
||||
@ -120,8 +125,9 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
* describing the parameters(arguments) of the method. This may be
|
||||
* null with the same effect as a zero-length array.
|
||||
* @param type The type of the method's return value.
|
||||
* @param impact The impact of the method, one of <CODE>INFO,
|
||||
* ACTION, ACTION_INFO, UNKNOWN</CODE>.
|
||||
* @param impact The impact of the method, one of
|
||||
* {@link #INFO}, {@link #ACTION}, {@link #ACTION_INFO},
|
||||
* {@link #UNKNOWN}.
|
||||
*/
|
||||
public MBeanOperationInfo(String name,
|
||||
String description,
|
||||
@ -140,8 +146,9 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
* describing the parameters(arguments) of the method. This may be
|
||||
* null with the same effect as a zero-length array.
|
||||
* @param type The type of the method's return value.
|
||||
* @param impact The impact of the method, one of <CODE>INFO,
|
||||
* ACTION, ACTION_INFO, UNKNOWN</CODE>.
|
||||
* @param impact The impact of the method, one of
|
||||
* {@link #INFO}, {@link #ACTION}, {@link #ACTION_INFO},
|
||||
* {@link #UNKNOWN}.
|
||||
* @param descriptor The descriptor for the operation. This may be null
|
||||
* which is equivalent to an empty descriptor.
|
||||
*
|
||||
@ -319,9 +326,14 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
Descriptor d = Introspector.descriptorForAnnotations(annots[i]);
|
||||
final String pn = "p" + (i + 1);
|
||||
params[i] =
|
||||
new MBeanParameterInfo(pn, classes[i].getName(), "", d);
|
||||
String description = Introspector.descriptionForParameter(annots[i]);
|
||||
if (description == null)
|
||||
description = "";
|
||||
String name = Introspector.nameForParameter(annots[i]);
|
||||
if (name == null)
|
||||
name = "p" + (i + 1);
|
||||
params[i] = new MBeanParameterInfo(
|
||||
name, classes[i].getName(), description, d);
|
||||
}
|
||||
|
||||
return params;
|
||||
|
@ -27,9 +27,101 @@ package javax.management;
|
||||
|
||||
|
||||
/**
|
||||
* Can be implemented by an MBean in order to
|
||||
* <p>Can be implemented by an MBean in order to
|
||||
* carry out operations before and after being registered or unregistered from
|
||||
* the MBean server.
|
||||
* the MBean Server. An MBean can also implement this interface in order
|
||||
* to get a reference to the MBean Server and/or its name within that
|
||||
* MBean Server.</p>
|
||||
*
|
||||
* <h4 id="injection">Resource injection</h4>
|
||||
*
|
||||
* <p>As an alternative to implementing {@code MBeanRegistration}, if all that
|
||||
* is needed is the MBean Server or ObjectName then an MBean can use
|
||||
* <em>resource injection</em>.</p>
|
||||
*
|
||||
* <p>If a field in the MBean object has type {@link ObjectName} and has
|
||||
* the {@link javax.annotation.Resource @Resource} annotation,
|
||||
* then the {@code ObjectName} under which the MBean is registered is
|
||||
* assigned to that field during registration. Likewise, if a field has type
|
||||
* {@link MBeanServer} and the <code>@Resource</code> annotation, then it will
|
||||
* be set to the {@code MBeanServer} in which the MBean is registered.</p>
|
||||
*
|
||||
* <p>For example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public Configuration implements ConfigurationMBean {
|
||||
* @Resource
|
||||
* private volatile MBeanServer mbeanServer;
|
||||
* @Resource
|
||||
* private volatile ObjectName objectName;
|
||||
* ...
|
||||
* void unregisterSelf() throws Exception {
|
||||
* mbeanServer.unregisterMBean(objectName);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Resource injection can also be used on fields of type
|
||||
* {@link SendNotification} to simplify notification sending. Such a field
|
||||
* will get a reference to an object of type {@code SendNotification} when
|
||||
* the MBean is registered, and it can use this reference to send notifications.
|
||||
* For example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public Configuration implements ConfigurationMBean {
|
||||
* @Resource
|
||||
* private volatile SendNotification sender;
|
||||
* ...
|
||||
* private void updated() {
|
||||
* Notification n = new Notification(...);
|
||||
* sender.sendNotification(n);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>A field to be injected must not be static. It is recommended that
|
||||
* such fields be declared {@code volatile}.</p>
|
||||
*
|
||||
* <p>It is also possible to use the <code>@Resource</code> annotation on
|
||||
* methods. Such a method must have a {@code void} return type and a single
|
||||
* argument of the appropriate type, for example {@code ObjectName}.</p>
|
||||
*
|
||||
* <p>Any number of fields and methods may have the <code>@Resource</code>
|
||||
* annotation. All fields and methods with type {@code ObjectName}
|
||||
* (for example) will receive the same {@code ObjectName} value.</p>
|
||||
*
|
||||
* <p>Resource injection is available for all types of MBeans, not just
|
||||
* Standard MBeans.</p>
|
||||
*
|
||||
* <p>If an MBean implements the {@link DynamicWrapperMBean} interface then
|
||||
* resource injection happens on the object returned by that interface's
|
||||
* {@link DynamicWrapperMBean#getWrappedObject() getWrappedObject()} method
|
||||
* rather than on the MBean object itself.
|
||||
*
|
||||
* <p>Resource injection happens after the {@link #preRegister preRegister}
|
||||
* method is called (if any), and before the MBean is actually registered
|
||||
* in the MBean Server. If a <code>@Resource</code> method throws
|
||||
* an exception, the effect is the same as if {@code preRegister} had
|
||||
* thrown the exception. In particular it will prevent the MBean from being
|
||||
* registered.</p>
|
||||
*
|
||||
* <p>Resource injection can be used on a field or method where the type
|
||||
* is a parent of the injected type, if the injected type is explicitly
|
||||
* specified in the <code>@Resource</code> annotation. For example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* @Resource(type = MBeanServer.class)
|
||||
* private volatile MBeanServerConnection mbsc;
|
||||
* </pre>
|
||||
*
|
||||
* <p>Formally, suppose <em>R</em> is the type in the <code>@Resource</code>
|
||||
* annotation and <em>T</em> is the type of the method parameter or field.
|
||||
* Then one of <em>R</em> and <em>T</em> must be a subtype of the other
|
||||
* (or they must be the same type). Injection happens if this subtype
|
||||
* is {@code MBeanServer}, {@code ObjectName}, or {@code SendNotification}.
|
||||
* Otherwise the <code>@Resource</code> annotation is ignored.</p>
|
||||
*
|
||||
* <p>Resource injection in MBeans is new in version 2.0 of the JMX API.</p>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
@ -38,12 +130,12 @@ public interface MBeanRegistration {
|
||||
|
||||
/**
|
||||
* Allows the MBean to perform any operations it needs before
|
||||
* being registered in the MBean server. If the name of the MBean
|
||||
* being registered in the MBean Server. If the name of the MBean
|
||||
* is not specified, the MBean can provide a name for its
|
||||
* registration. If any exception is raised, the MBean will not be
|
||||
* registered in the MBean server.
|
||||
* registered in the MBean Server.
|
||||
*
|
||||
* @param server The MBean server in which the MBean will be registered.
|
||||
* @param server The MBean Server in which the MBean will be registered.
|
||||
*
|
||||
* @param name The object name of the MBean. This name is null if
|
||||
* the name parameter to one of the <code>createMBean</code> or
|
||||
@ -57,7 +149,7 @@ public interface MBeanRegistration {
|
||||
* the returned value.
|
||||
*
|
||||
* @exception java.lang.Exception This exception will be caught by
|
||||
* the MBean server and re-thrown as an {@link
|
||||
* the MBean Server and re-thrown as an {@link
|
||||
* MBeanRegistrationException}.
|
||||
*/
|
||||
public ObjectName preRegister(MBeanServer server,
|
||||
|
@ -61,7 +61,7 @@ import javax.management.loading.ClassLoaderRepository;
|
||||
* <CODE>ObjectName</CODE> is: <BR>
|
||||
* <CODE>JMImplementation:type=MBeanServerDelegate</CODE>.</p>
|
||||
*
|
||||
* <p>An object obtained from the {@link
|
||||
* <p id="security">An object obtained from the {@link
|
||||
* MBeanServerFactory#createMBeanServer(String) createMBeanServer} or
|
||||
* {@link MBeanServerFactory#newMBeanServer(String) newMBeanServer}
|
||||
* methods of the {@link MBeanServerFactory} class applies security
|
||||
@ -661,13 +661,16 @@ public interface MBeanServer extends MBeanServerConnection {
|
||||
ReflectionException;
|
||||
|
||||
/**
|
||||
* <p>Return the {@link java.lang.ClassLoader} that was used for
|
||||
* loading the class of the named MBean.</p>
|
||||
* <p>Return the {@link java.lang.ClassLoader} that was used for loading
|
||||
* the class of the named MBean. If the MBean implements the {@link
|
||||
* DynamicWrapperMBean} interface, then the returned value is the
|
||||
* result of the {@link DynamicWrapperMBean#getWrappedClassLoader()}
|
||||
* method.</p>
|
||||
*
|
||||
* @param mbeanName The ObjectName of the MBean.
|
||||
*
|
||||
* @return The ClassLoader used for that MBean. If <var>l</var>
|
||||
* is the MBean's actual ClassLoader, and <var>r</var> is the
|
||||
* is the value specified by the rules above, and <var>r</var> is the
|
||||
* returned value, then either:
|
||||
*
|
||||
* <ul>
|
||||
|
@ -839,6 +839,12 @@ public interface MBeanServerConnection {
|
||||
*
|
||||
* <p>Otherwise, the result is false.</p>
|
||||
*
|
||||
* <p>If the MBean implements the {@link DynamicWrapperMBean}
|
||||
* interface, then in the above rules X is the result of the MBean's {@link
|
||||
* DynamicWrapperMBean#getWrappedObject() getWrappedObject()} method and L
|
||||
* is the result of its {@link DynamicWrapperMBean#getWrappedClassLoader()
|
||||
* getWrappedClassLoader()} method.
|
||||
*
|
||||
* @param name The <CODE>ObjectName</CODE> of the MBean.
|
||||
* @param className The name of the class.
|
||||
*
|
||||
|
@ -27,6 +27,7 @@ package javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@ -57,11 +58,13 @@ import javax.management.openmbean.TabularDataSupport;
|
||||
import javax.management.openmbean.TabularType;
|
||||
|
||||
/**
|
||||
<p>Annotation to mark an interface explicitly as being an MXBean
|
||||
interface, or as not being an MXBean interface. By default, an
|
||||
<p>Annotation to mark a class or interface explicitly as being an MXBean,
|
||||
or as not being an MXBean. By default, an
|
||||
interface is an MXBean interface if its name ends with {@code
|
||||
MXBean}, as in {@code SomethingMXBean}. The following interfaces
|
||||
are MXBean interfaces:</p>
|
||||
MXBean}, as in {@code SomethingMXBean}. A class is never an MXBean by
|
||||
default.</p>
|
||||
|
||||
<p>The following interfaces are MXBean interfaces:</p>
|
||||
|
||||
<pre>
|
||||
public interface WhatsitMXBean {}
|
||||
@ -82,6 +85,11 @@ import javax.management.openmbean.TabularType;
|
||||
public interface MisleadingMXBean {}
|
||||
</pre>
|
||||
|
||||
<p>A class can be annotated with {@code @MXBean} to indicate that it
|
||||
is an MXBean. In this case, its methods should have <code>@{@link
|
||||
ManagedAttribute}</code> or <code>@{@link ManagedOperation}</code>
|
||||
annotations, as described for <code>@{@link MBean}</code>.</p>
|
||||
|
||||
<h3 id="MXBean-spec">MXBean specification</h3>
|
||||
|
||||
<p>The MXBean concept provides a simple way to code an MBean
|
||||
@ -1246,9 +1254,24 @@ public interface Node {
|
||||
@since 1.6
|
||||
*/
|
||||
|
||||
/*
|
||||
* This annotation is @Inherited because if an MXBean is defined as a
|
||||
* class using annotations, then its subclasses are also MXBeans.
|
||||
* For example:
|
||||
* @MXBean
|
||||
* public class Super {
|
||||
* @ManagedAttribute
|
||||
* public String getName() {...}
|
||||
* }
|
||||
* public class Sub extends Super {}
|
||||
* Here Sub is an MXBean.
|
||||
*
|
||||
* The @Inherited annotation has no effect when applied to an interface.
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Inherited
|
||||
public @interface MXBean {
|
||||
/**
|
||||
True if the annotated interface is an MXBean interface.
|
||||
|
64
jdk/src/share/classes/javax/management/ManagedAttribute.java
Normal file
64
jdk/src/share/classes/javax/management/ManagedAttribute.java
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Indicates that a method in an MBean class defines an MBean attribute.
|
||||
* This annotation must be applied to a public method of a public class
|
||||
* that is itself annotated with an {@link MBean @MBean} or
|
||||
* {@link MXBean @MXBean} annotation, or inherits such an annotation from
|
||||
* a superclass.</p>
|
||||
*
|
||||
* <p>The annotated method must be a getter or setter. In other words,
|
||||
* it must look like one of the following...</p>
|
||||
*
|
||||
* <pre>
|
||||
* <i>T</i> get<i>Foo</i>()
|
||||
* void set<i>Foo</i>(<i>T</i> param)
|
||||
* </pre>
|
||||
*
|
||||
* <p>...where <i>{@code T}</i> is any type and <i>{@code Foo}</i> is the
|
||||
* name of the attribute. For any attribute <i>{@code Foo}</i>, if only
|
||||
* a {@code get}<i>{@code Foo}</i> method has a {@code ManagedAttribute}
|
||||
* annotation, then <i>{@code Foo}</i> is a read-only attribute. If only
|
||||
* a {@code set}<i>{@code Foo}</i> method has a {@code ManagedAttribute}
|
||||
* annotation, then <i>{@code Foo}</i> is a write-only attribute. If
|
||||
* both {@code get}<i>{@code Foo}</i> and {@code set}<i>{@code Foo}</i>
|
||||
* methods have the annotation, then <i>{@code Foo}</i> is a read-write
|
||||
* attribute. In this last case, the type <i>{@code T}</i> must be the
|
||||
* same in both methods.</p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface ManagedAttribute {
|
||||
}
|
67
jdk/src/share/classes/javax/management/ManagedOperation.java
Normal file
67
jdk/src/share/classes/javax/management/ManagedOperation.java
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Indicates that a method in an MBean class defines an MBean operation.
|
||||
* This annotation can be applied to:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>A public method of a public class
|
||||
* that is itself annotated with an {@link MBean @MBean} or
|
||||
* {@link MXBean @MXBean} annotation, or inherits such an annotation from
|
||||
* a superclass.</li>
|
||||
* <li>A method of an MBean or MXBean interface.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Every method in an MBean or MXBean interface defines an MBean
|
||||
* operation even without this annotation, but the annotation allows
|
||||
* you to specify the impact of the operation:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public interface ConfigurationMBean {
|
||||
* {@code @ManagedOperation}(impact = {@link Impact#ACTION Impact.ACTION})
|
||||
* public void save();
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface ManagedOperation {
|
||||
/**
|
||||
* <p>The impact of this operation, as shown by
|
||||
* {@link MBeanOperationInfo#getImpact()}.
|
||||
*/
|
||||
Impact impact() default Impact.UNKNOWN;
|
||||
}
|
@ -91,6 +91,7 @@ class NotQueryExp extends QueryEval implements QueryExp {
|
||||
return "not (" + exp + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
String toQueryString() {
|
||||
return "not (" + Query.toString(exp) + ")";
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ import com.sun.jmx.remote.util.ClassLogger;
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public class NotificationBroadcasterSupport implements NotificationEmitter {
|
||||
public class NotificationBroadcasterSupport
|
||||
implements NotificationEmitter, SendNotification {
|
||||
/**
|
||||
* Constructs a NotificationBroadcasterSupport where each listener is invoked by the
|
||||
* thread sending the notification. This constructor is equivalent to
|
||||
|
117
jdk/src/share/classes/javax/management/NotificationInfo.java
Normal file
117
jdk/src/share/classes/javax/management/NotificationInfo.java
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Specifies the kinds of notification an MBean can emit. In both the
|
||||
* following examples, the MBean emits notifications of type
|
||||
* {@code "com.example.notifs.create"} and of type
|
||||
* {@code "com.example.notifs.destroy"}:</p>
|
||||
*
|
||||
* <pre>
|
||||
* // Example one: a Standard MBean
|
||||
* {@code @NotificationInfo}(types={"com.example.notifs.create",
|
||||
* "com.example.notifs.destroy"})
|
||||
* public interface CacheMBean {...}
|
||||
*
|
||||
* public class Cache implements CacheMBean {...}
|
||||
* </pre>
|
||||
*
|
||||
* <pre>
|
||||
* // Example two: an annotated MBean
|
||||
* {@link MBean @MBean}
|
||||
* {@code @NotificationInfo}(types={"com.example.notifs.create",
|
||||
* "com.example.notifs.destroy"})
|
||||
* public class Cache {...}
|
||||
* </pre>
|
||||
*
|
||||
* <p>Each {@code @NotificationInfo} produces an {@link
|
||||
* MBeanNotificationInfo} inside the {@link MBeanInfo} of each MBean
|
||||
* to which the annotation applies.</p>
|
||||
*
|
||||
* <p>If you need to specify different notification classes, or different
|
||||
* descriptions for different notification types, then you can group
|
||||
* several {@code @NotificationInfo} annotations into a containing
|
||||
* {@link NotificationInfos @NotificationInfos} annotation.
|
||||
*
|
||||
* <p>The {@code NotificationInfo} and {@code NotificationInfos}
|
||||
* annotations can be applied to the MBean implementation class, or to
|
||||
* any parent class or interface. These annotations on a class take
|
||||
* precedence over annotations on any superclass or superinterface.
|
||||
* If an MBean does not have these annotations on its class or any
|
||||
* superclass, then superinterfaces are examined. It is an error for
|
||||
* more than one superinterface to have these annotations, unless one
|
||||
* of them is a child of all the others.</p>
|
||||
*/
|
||||
@Documented
|
||||
@Inherited
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NotificationInfo {
|
||||
/**
|
||||
* <p>The {@linkplain Notification#getType() notification types}
|
||||
* that this MBean can emit.</p>
|
||||
*/
|
||||
String[] types();
|
||||
|
||||
/**
|
||||
* <p>The class that emitted notifications will have. It is recommended
|
||||
* that this be {@link Notification}, or one of its standard subclasses
|
||||
* in the JMX API.</p>
|
||||
*/
|
||||
Class<? extends Notification> notificationClass() default Notification.class;
|
||||
|
||||
/**
|
||||
* <p>The description of this notification. For example:
|
||||
*
|
||||
* <pre>
|
||||
* {@code @NotificationInfo}(
|
||||
* types={"com.example.notifs.create"},
|
||||
* description={@code @Description}("object created"))
|
||||
* </pre>
|
||||
*/
|
||||
Description description() default @Description("");
|
||||
|
||||
/**
|
||||
* <p>Additional descriptor fields for the derived {@code
|
||||
* MBeanNotificationInfo}. They are specified in the same way as
|
||||
* for the {@link DescriptorFields @DescriptorFields} annotation,
|
||||
* for example:</p>
|
||||
* <pre>
|
||||
* {@code @NotificationInfo}(
|
||||
* types={"com.example.notifs.create"},
|
||||
* descriptorFields={"severity=6"})
|
||||
* </pre>
|
||||
*/
|
||||
String[] descriptorFields() default {};
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.management.remote.JMXConnectionNotification;
|
||||
|
||||
/**
|
||||
* <p>Specifies the kinds of notification an MBean can emit, when this
|
||||
* cannot be represented by a single {@link NotificationInfo
|
||||
* @NotificationInfo} annotation.</p>
|
||||
*
|
||||
* <p>For example, this annotation specifies that an MBean can emit
|
||||
* {@link AttributeChangeNotification} and {@link
|
||||
* JMXConnectionNotification}:</p>
|
||||
*
|
||||
* <pre>
|
||||
* {@code @NotificationInfos}(
|
||||
* {@code @NotificationInfo}(
|
||||
* types = {{@link AttributeChangeNotification#ATTRIBUTE_CHANGE}},
|
||||
* notificationClass = AttributeChangeNotification.class),
|
||||
* {@code @NotificationInfo}(
|
||||
* types = {{@link JMXConnectionNotification#OPENED},
|
||||
* {@link JMXConnectionNotification#CLOSED}},
|
||||
* notificationClass = JMXConnectionNotification.class)
|
||||
* )
|
||||
* </pre>
|
||||
*
|
||||
* <p>If an MBean has both {@code NotificationInfo} and {@code
|
||||
* NotificationInfos} on the same class or interface, the effect is
|
||||
* the same as if the {@code NotificationInfo} were moved inside the
|
||||
* {@code NotificationInfos}.</p>
|
||||
*/
|
||||
@Documented
|
||||
@Inherited
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NotificationInfos {
|
||||
/**
|
||||
* <p>The {@link NotificationInfo} annotations.</p>
|
||||
*/
|
||||
NotificationInfo[] value();
|
||||
}
|
38
jdk/src/share/classes/javax/management/SendNotification.java
Normal file
38
jdk/src/share/classes/javax/management/SendNotification.java
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management;
|
||||
|
||||
/**
|
||||
* Interface implemented by objects that can be asked to send a notification.
|
||||
*/
|
||||
public interface SendNotification {
|
||||
/**
|
||||
* Sends a notification.
|
||||
*
|
||||
* @param notification The notification to send.
|
||||
*/
|
||||
public void sendNotification(Notification notification);
|
||||
}
|
@ -25,6 +25,9 @@
|
||||
|
||||
package javax.management;
|
||||
|
||||
import com.sun.jmx.mbeanserver.MBeanInjector;
|
||||
import static javax.management.JMX.MBeanOptions;
|
||||
|
||||
/**
|
||||
* <p>An MBean whose management interface is determined by reflection
|
||||
* on a Java interface, and that emits notifications.</p>
|
||||
@ -62,7 +65,7 @@ package javax.management;
|
||||
* @since 1.6
|
||||
*/
|
||||
public class StandardEmitterMBean extends StandardMBean
|
||||
implements NotificationEmitter {
|
||||
implements NotificationEmitter, SendNotification {
|
||||
|
||||
private final NotificationEmitter emitter;
|
||||
private final MBeanNotificationInfo[] notificationInfo;
|
||||
@ -76,9 +79,10 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
* for {@code implementation} and {@code emitter} to be the same object.</p>
|
||||
*
|
||||
* <p>If {@code emitter} is an instance of {@code
|
||||
* NotificationBroadcasterSupport} then the MBean's {@link #sendNotification
|
||||
* SendNotification} (for example, a {@link NotificationBroadcasterSupport}),
|
||||
* then the MBean's {@link #sendNotification
|
||||
* sendNotification} method will call {@code emitter.}{@link
|
||||
* NotificationBroadcasterSupport#sendNotification sendNotification}.</p>
|
||||
* SendNotification#sendNotification sendNotification}.</p>
|
||||
*
|
||||
* <p>The array returned by {@link #getNotificationInfo()} on the
|
||||
* new MBean is a copy of the array returned by
|
||||
@ -90,20 +94,18 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
*
|
||||
* @param implementation the implementation of the MBean interface.
|
||||
* @param mbeanInterface a Standard MBean interface.
|
||||
* @param emitter the object that will handle notifications.
|
||||
* @param emitter the object that will handle notifications. If null,
|
||||
* a new {@code NotificationEmitter} will be constructed that also
|
||||
* implements {@link SendNotification}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the {@code mbeanInterface}
|
||||
* does not follow JMX design patterns for Management Interfaces, or
|
||||
* if the given {@code implementation} does not implement the
|
||||
* specified interface, or if {@code emitter} is null.
|
||||
* specified interface.
|
||||
*/
|
||||
public <T> StandardEmitterMBean(T implementation, Class<T> mbeanInterface,
|
||||
NotificationEmitter emitter) {
|
||||
super(implementation, mbeanInterface, false);
|
||||
if (emitter == null)
|
||||
throw new IllegalArgumentException("Null emitter");
|
||||
this.emitter = emitter;
|
||||
this.notificationInfo = emitter.getNotificationInfo();
|
||||
this(implementation, mbeanInterface, false, emitter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,9 +120,10 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
* same object.</p>
|
||||
*
|
||||
* <p>If {@code emitter} is an instance of {@code
|
||||
* NotificationBroadcasterSupport} then the MBean's {@link #sendNotification
|
||||
* SendNotification} (for example, a {@link NotificationBroadcasterSupport}),
|
||||
* then the MBean's {@link #sendNotification
|
||||
* sendNotification} method will call {@code emitter.}{@link
|
||||
* NotificationBroadcasterSupport#sendNotification sendNotification}.</p>
|
||||
* SendNotification#sendNotification sendNotification}.</p>
|
||||
*
|
||||
* <p>The array returned by {@link #getNotificationInfo()} on the
|
||||
* new MBean is a copy of the array returned by
|
||||
@ -134,21 +137,69 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
* @param mbeanInterface a Standard MBean interface.
|
||||
* @param isMXBean If true, the {@code mbeanInterface} parameter
|
||||
* names an MXBean interface and the resultant MBean is an MXBean.
|
||||
* @param emitter the object that will handle notifications.
|
||||
* @param emitter the object that will handle notifications. If null,
|
||||
* a new {@code NotificationEmitter} will be constructed that also
|
||||
* implements {@link SendNotification}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the {@code mbeanInterface}
|
||||
* does not follow JMX design patterns for Management Interfaces, or
|
||||
* if the given {@code implementation} does not implement the
|
||||
* specified interface, or if {@code emitter} is null.
|
||||
* specified interface.
|
||||
*/
|
||||
public <T> StandardEmitterMBean(T implementation, Class<T> mbeanInterface,
|
||||
boolean isMXBean,
|
||||
NotificationEmitter emitter) {
|
||||
super(implementation, mbeanInterface, isMXBean);
|
||||
this(implementation, mbeanInterface,
|
||||
isMXBean ? MBeanOptions.MXBEAN : null, emitter);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make an MBean whose management interface is specified by {@code
|
||||
* mbeanInterface}, with the given implementation and options, and where
|
||||
* notifications are handled by the given {@code NotificationEmitter}.
|
||||
* Options select whether to make a Standard MBean or an MXBean, and
|
||||
* whether the result of {@link #getWrappedObject()} is the {@code
|
||||
* StandardEmitterMBean} object or the given implementation. The resultant
|
||||
* MBean implements the {@code NotificationEmitter} interface by forwarding
|
||||
* its methods to {@code emitter}. It is legal and useful for {@code
|
||||
* implementation} and {@code emitter} to be the same object.</p>
|
||||
*
|
||||
* <p>If {@code emitter} is an instance of {@code
|
||||
* SendNotification} (for example, a {@link NotificationBroadcasterSupport}),
|
||||
* then the MBean's {@link #sendNotification
|
||||
* sendNotification} method will call {@code emitter.}{@link
|
||||
* SendNotification#sendNotification sendNotification}.</p>
|
||||
*
|
||||
* <p>The array returned by {@link #getNotificationInfo()} on the
|
||||
* new MBean is a copy of the array returned by
|
||||
* {@code emitter.}{@link NotificationBroadcaster#getNotificationInfo
|
||||
* getNotificationInfo()} at the time of construction. If the array
|
||||
* returned by {@code emitter.getNotificationInfo()} later changes,
|
||||
* that will have no effect on this object's
|
||||
* {@code getNotificationInfo()}.</p>
|
||||
*
|
||||
* @param implementation the implementation of the MBean interface.
|
||||
* @param mbeanInterface a Standard MBean interface.
|
||||
* @param options MBeanOptions that control the operation of the resulting
|
||||
* MBean.
|
||||
* @param emitter the object that will handle notifications. If null,
|
||||
* a new {@code NotificationEmitter} will be constructed that also
|
||||
* implements {@link SendNotification}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the {@code mbeanInterface}
|
||||
* does not follow JMX design patterns for Management Interfaces, or
|
||||
* if the given {@code implementation} does not implement the
|
||||
* specified interface.
|
||||
*/
|
||||
public <T> StandardEmitterMBean(T implementation, Class<T> mbeanInterface,
|
||||
MBeanOptions options,
|
||||
NotificationEmitter emitter) {
|
||||
super(implementation, mbeanInterface, options);
|
||||
if (emitter == null)
|
||||
throw new IllegalArgumentException("Null emitter");
|
||||
emitter = defaultEmitter();
|
||||
this.emitter = emitter;
|
||||
this.notificationInfo = emitter.getNotificationInfo();
|
||||
injectEmitter();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,9 +210,10 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
* by forwarding its methods to {@code emitter}.</p>
|
||||
*
|
||||
* <p>If {@code emitter} is an instance of {@code
|
||||
* NotificationBroadcasterSupport} then the MBean's {@link #sendNotification
|
||||
* SendNotification} (for example, a {@link NotificationBroadcasterSupport}),
|
||||
* then the MBean's {@link #sendNotification
|
||||
* sendNotification} method will call {@code emitter.}{@link
|
||||
* NotificationBroadcasterSupport#sendNotification sendNotification}.</p>
|
||||
* SendNotification#sendNotification sendNotification}.</p>
|
||||
*
|
||||
* <p>The array returned by {@link #getNotificationInfo()} on the
|
||||
* new MBean is a copy of the array returned by
|
||||
@ -175,20 +227,17 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
* the given {@code mbeanInterface}.</p>
|
||||
*
|
||||
* @param mbeanInterface a StandardMBean interface.
|
||||
* @param emitter the object that will handle notifications.
|
||||
* @param emitter the object that will handle notifications. If null,
|
||||
* a new {@code NotificationEmitter} will be constructed that also
|
||||
* implements {@link SendNotification}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the {@code mbeanInterface}
|
||||
* does not follow JMX design patterns for Management Interfaces, or
|
||||
* if {@code this} does not implement the specified interface, or
|
||||
* if {@code emitter} is null.
|
||||
* if {@code this} does not implement the specified interface.
|
||||
*/
|
||||
protected StandardEmitterMBean(Class<?> mbeanInterface,
|
||||
NotificationEmitter emitter) {
|
||||
super(mbeanInterface, false);
|
||||
if (emitter == null)
|
||||
throw new IllegalArgumentException("Null emitter");
|
||||
this.emitter = emitter;
|
||||
this.notificationInfo = emitter.getNotificationInfo();
|
||||
this(mbeanInterface, false, emitter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,9 +249,10 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
* forwarding its methods to {@code emitter}.</p>
|
||||
*
|
||||
* <p>If {@code emitter} is an instance of {@code
|
||||
* NotificationBroadcasterSupport} then the MBean's {@link #sendNotification
|
||||
* SendNotification} (for example, a {@link NotificationBroadcasterSupport}),
|
||||
* then the MBean's {@link #sendNotification
|
||||
* sendNotification} method will call {@code emitter.}{@link
|
||||
* NotificationBroadcasterSupport#sendNotification sendNotification}.</p>
|
||||
* SendNotification#sendNotification sendNotification}.</p>
|
||||
*
|
||||
* <p>The array returned by {@link #getNotificationInfo()} on the
|
||||
* new MBean is a copy of the array returned by
|
||||
@ -218,20 +268,86 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
* @param mbeanInterface a StandardMBean interface.
|
||||
* @param isMXBean If true, the {@code mbeanInterface} parameter
|
||||
* names an MXBean interface and the resultant MBean is an MXBean.
|
||||
* @param emitter the object that will handle notifications.
|
||||
* @param emitter the object that will handle notifications. If null,
|
||||
* a new {@code NotificationEmitter} will be constructed that also
|
||||
* implements {@link SendNotification}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the {@code mbeanInterface}
|
||||
* does not follow JMX design patterns for Management Interfaces, or
|
||||
* if {@code this} does not implement the specified interface, or
|
||||
* if {@code emitter} is null.
|
||||
* if {@code this} does not implement the specified interface.
|
||||
*/
|
||||
protected StandardEmitterMBean(Class<?> mbeanInterface, boolean isMXBean,
|
||||
NotificationEmitter emitter) {
|
||||
super(mbeanInterface, isMXBean);
|
||||
this(mbeanInterface, isMXBean ? MBeanOptions.MXBEAN : null, emitter);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make an MBean whose management interface is specified by {@code
|
||||
* mbeanInterface}, with the given options, and where notifications are
|
||||
* handled by the given {@code NotificationEmitter}. This constructor can
|
||||
* be used to make either Standard MBeans or MXBeans. The resultant MBean
|
||||
* implements the {@code NotificationEmitter} interface by forwarding its
|
||||
* methods to {@code emitter}.</p>
|
||||
*
|
||||
* <p>If {@code emitter} is an instance of {@code
|
||||
* SendNotification} (for example, a {@link NotificationBroadcasterSupport}),
|
||||
* then the MBean's {@link #sendNotification
|
||||
* sendNotification} method will call {@code emitter.}{@link
|
||||
* SendNotification#sendNotification sendNotification}.</p>
|
||||
*
|
||||
* <p>The array returned by {@link #getNotificationInfo()} on the
|
||||
* new MBean is a copy of the array returned by
|
||||
* {@code emitter.}{@link NotificationBroadcaster#getNotificationInfo
|
||||
* getNotificationInfo()} at the time of construction. If the array
|
||||
* returned by {@code emitter.getNotificationInfo()} later changes,
|
||||
* that will have no effect on this object's
|
||||
* {@code getNotificationInfo()}.</p>
|
||||
*
|
||||
* <p>This constructor must be called from a subclass that implements
|
||||
* the given {@code mbeanInterface}.</p>
|
||||
*
|
||||
* @param mbeanInterface a StandardMBean interface.
|
||||
* @param options MBeanOptions that control the operation of the resulting
|
||||
* MBean.
|
||||
* @param emitter the object that will handle notifications. If null,
|
||||
* a new {@code NotificationEmitter} will be constructed that also
|
||||
* implements {@link SendNotification}.
|
||||
*
|
||||
* @throws IllegalArgumentException if the {@code mbeanInterface}
|
||||
* does not follow JMX design patterns for Management Interfaces, or
|
||||
* if {@code this} does not implement the specified interface.
|
||||
*/
|
||||
protected StandardEmitterMBean(Class<?> mbeanInterface, MBeanOptions options,
|
||||
NotificationEmitter emitter) {
|
||||
super(mbeanInterface, options);
|
||||
if (emitter == null)
|
||||
throw new IllegalArgumentException("Null emitter");
|
||||
emitter = defaultEmitter();
|
||||
this.emitter = emitter;
|
||||
this.notificationInfo = emitter.getNotificationInfo();
|
||||
injectEmitter();
|
||||
}
|
||||
|
||||
private NotificationEmitter defaultEmitter() {
|
||||
MBeanNotificationInfo[] mbnis = getNotificationInfo();
|
||||
// Will be null unless getNotificationInfo() is overridden,
|
||||
// since the notificationInfo field has not been set at this point.
|
||||
if (mbnis == null)
|
||||
mbnis = getMBeanInfo().getNotifications();
|
||||
return new NotificationBroadcasterSupport(mbnis);
|
||||
}
|
||||
|
||||
private void injectEmitter() {
|
||||
if (emitter instanceof SendNotification) {
|
||||
try {
|
||||
Object resource = getImplementation();
|
||||
SendNotification send = (SendNotification) emitter;
|
||||
MBeanInjector.injectSendNotification(resource, send);
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeNotificationListener(NotificationListener listener)
|
||||
@ -259,10 +375,10 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
/**
|
||||
* <p>Sends a notification.</p>
|
||||
*
|
||||
* <p>If the {@code emitter} parameter to the constructor was an
|
||||
* instance of {@code NotificationBroadcasterSupport} then this
|
||||
* method will call {@code emitter.}{@link
|
||||
* NotificationBroadcasterSupport#sendNotification
|
||||
* <p>If the {@code emitter} parameter to the constructor was
|
||||
* an instance of {@link SendNotification}, such as {@link
|
||||
* NotificationBroadcasterSupport}, then this method will call {@code
|
||||
* emitter.}{@link SendNotification#sendNotification
|
||||
* sendNotification}.</p>
|
||||
*
|
||||
* @param n the notification to send.
|
||||
@ -271,13 +387,12 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
* constructor was not a {@code NotificationBroadcasterSupport}.
|
||||
*/
|
||||
public void sendNotification(Notification n) {
|
||||
if (emitter instanceof NotificationBroadcasterSupport)
|
||||
((NotificationBroadcasterSupport) emitter).sendNotification(n);
|
||||
if (emitter instanceof SendNotification)
|
||||
((SendNotification) emitter).sendNotification(n);
|
||||
else {
|
||||
final String msg =
|
||||
"Cannot sendNotification when emitter is not an " +
|
||||
"instance of NotificationBroadcasterSupport: " +
|
||||
emitter.getClass().getName();
|
||||
"instance of SendNotification: " + emitter.getClass().getName();
|
||||
throw new ClassCastException(msg);
|
||||
}
|
||||
}
|
||||
@ -292,6 +407,7 @@ public class StandardEmitterMBean extends StandardMBean
|
||||
* @param info The default MBeanInfo derived by reflection.
|
||||
* @return the MBeanNotificationInfo[] for the new MBeanInfo.
|
||||
*/
|
||||
@Override
|
||||
MBeanNotificationInfo[] getNotifications(MBeanInfo info) {
|
||||
return getNotificationInfo();
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ package javax.management;
|
||||
|
||||
import com.sun.jmx.mbeanserver.DescriptorCache;
|
||||
import com.sun.jmx.mbeanserver.Introspector;
|
||||
import com.sun.jmx.mbeanserver.MBeanInjector;
|
||||
import com.sun.jmx.mbeanserver.MBeanSupport;
|
||||
import com.sun.jmx.mbeanserver.MXBeanSupport;
|
||||
import com.sun.jmx.mbeanserver.StandardMBeanSupport;
|
||||
@ -125,7 +126,78 @@ import static javax.management.JMX.MBeanOptions;
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
public class StandardMBean implements DynamicWrapperMBean, MBeanRegistration {
|
||||
|
||||
/**
|
||||
* <p>Options controlling the behavior of {@code StandardMBean} instances.</p>
|
||||
*/
|
||||
public static class Options extends JMX.MBeanOptions {
|
||||
private static final long serialVersionUID = 5107355471177517164L;
|
||||
|
||||
private boolean wrappedVisible;
|
||||
|
||||
/**
|
||||
* <p>Construct an {@code Options} object where all options have
|
||||
* their default values.</p>
|
||||
*/
|
||||
public Options() {}
|
||||
|
||||
@Override
|
||||
public Options clone() {
|
||||
return (Options) super.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Defines whether the {@link StandardMBean#getWrappedObject()
|
||||
* getWrappedObject} method returns the wrapped object.</p>
|
||||
*
|
||||
* <p>If this option is true, then {@code getWrappedObject()} will return
|
||||
* the same object as {@link StandardMBean#getImplementation()
|
||||
* getImplementation}. Otherwise, it will return the
|
||||
* StandardMBean instance itself. The setting of this option
|
||||
* affects the behavior of {@link MBeanServer#getClassLoaderFor
|
||||
* MBeanServer.getClassLoaderFor} and {@link MBeanServer#isInstanceOf
|
||||
* MBeanServer.isInstanceOf}. The default value is false for
|
||||
* compatibility reasons, but true is a better value for most new code.</p>
|
||||
*
|
||||
* @return true if this StandardMBean's {@link
|
||||
* StandardMBean#getWrappedObject getWrappedObject} returns the wrapped
|
||||
* object.
|
||||
*/
|
||||
public boolean isWrappedObjectVisible() {
|
||||
return this.wrappedVisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set the {@link #isWrappedObjectVisible WrappedObjectVisible} option
|
||||
* to the given value.</p>
|
||||
* @param visible the new value.
|
||||
*/
|
||||
public void setWrappedObjectVisible(boolean visible) {
|
||||
this.wrappedVisible = visible;
|
||||
}
|
||||
|
||||
// Canonical objects for each of (MXBean,!MXBean) x (WVisible,!WVisible)
|
||||
private static final Options[] CANONICALS = {
|
||||
new Options(), new Options(), new Options(), new Options(),
|
||||
};
|
||||
static {
|
||||
CANONICALS[1].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
|
||||
CANONICALS[2].setWrappedObjectVisible(true);
|
||||
CANONICALS[3].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
|
||||
CANONICALS[3].setWrappedObjectVisible(true);
|
||||
}
|
||||
@Override
|
||||
MBeanOptions[] canonicals() {
|
||||
return CANONICALS;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean same(MBeanOptions opts) {
|
||||
return (super.same(opts) && opts instanceof Options &&
|
||||
((Options) opts).wrappedVisible == wrappedVisible);
|
||||
}
|
||||
}
|
||||
|
||||
private final static DescriptorCache descriptors =
|
||||
DescriptorCache.getInstance(JMX.proof);
|
||||
@ -347,7 +419,7 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
* the management interface associated with the given
|
||||
* implementation.
|
||||
* @param options MBeanOptions that control the operation of the resulting
|
||||
* MBean, as documented in the {@link MBeanOptions} class.
|
||||
* MBean.
|
||||
* @param <T> Allows the compiler to check
|
||||
* that {@code implementation} does indeed implement the class
|
||||
* described by {@code mbeanInterface}. The compiler can only
|
||||
@ -381,7 +453,7 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
* @param mbeanInterface The Management Interface exported by this
|
||||
* MBean.
|
||||
* @param options MBeanOptions that control the operation of the resulting
|
||||
* MBean, as documented in the {@link MBeanOptions} class.
|
||||
* MBean.
|
||||
*
|
||||
* @exception IllegalArgumentException if the <var>mbeanInterface</var>
|
||||
* does not follow JMX design patterns for Management Interfaces, or
|
||||
@ -441,7 +513,67 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
* @see #setImplementation
|
||||
**/
|
||||
public Object getImplementation() {
|
||||
return mbean.getResource();
|
||||
return mbean.getWrappedObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the wrapped implementation object or return this object.</p>
|
||||
*
|
||||
* <p>For compatibility reasons, this method only returns the wrapped
|
||||
* implementation object if the {@link Options#isWrappedObjectVisible
|
||||
* WrappedObjectVisible} option was specified when this StandardMBean
|
||||
* was created. Otherwise it returns {@code this}.</p>
|
||||
*
|
||||
* <p>If you want the MBeanServer's {@link MBeanServer#getClassLoaderFor
|
||||
* getClassLoaderFor} and {@link MBeanServer#isInstanceOf
|
||||
* isInstanceOf} methods to refer to the wrapped implementation and
|
||||
* not this StandardMBean object, then you must set the
|
||||
* {@code WrappedObjectVisible} option, for example using:</p>
|
||||
*
|
||||
* <pre>
|
||||
* StandardMBean.Options opts = new StandardMBean.Options();
|
||||
* opts.setWrappedObjectVisible(true);
|
||||
* StandardMBean mbean = new StandardMBean(impl, MyMBean.class, opts);
|
||||
* </pre>
|
||||
*
|
||||
* @return The wrapped implementation object, or this StandardMBean
|
||||
* instance.
|
||||
*/
|
||||
public Object getWrappedObject() {
|
||||
if (options instanceof Options &&
|
||||
((Options) options).isWrappedObjectVisible())
|
||||
return getImplementation();
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the ClassLoader of the wrapped implementation object or of this
|
||||
* object.</p>
|
||||
*
|
||||
* <p>For compatibility reasons, this method only returns the ClassLoader
|
||||
* of the wrapped implementation object if the {@link
|
||||
* Options#isWrappedObjectVisible WrappedObjectVisible} option was
|
||||
* specified when this StandardMBean was created. Otherwise it returns
|
||||
* {@code this.getClass().getClassLoader()}.</p>
|
||||
*
|
||||
* <p>If you want the MBeanServer's {@link MBeanServer#getClassLoaderFor
|
||||
* getClassLoaderFor} and {@link MBeanServer#isInstanceOf
|
||||
* isInstanceOf} methods to refer to the wrapped implementation and
|
||||
* not this StandardMBean object, then you must set the
|
||||
* {@code WrappedObjectVisible} option, for example using:</p>
|
||||
*
|
||||
* <pre>
|
||||
* StandardMBean.Options opts = new StandardMBean.Options();
|
||||
* opts.setWrappedObjectVisible(true);
|
||||
* StandardMBean mbean = new StandardMBean(impl, MyMBean.class, opts);
|
||||
* </pre>
|
||||
*
|
||||
* @return The ClassLoader of the wrapped Cimplementation object, or of
|
||||
* this StandardMBean instance.
|
||||
*/
|
||||
public ClassLoader getWrappedClassLoader() {
|
||||
return getWrappedObject().getClass().getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -457,7 +589,7 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
* @return The class of the implementation of this Standard MBean (or MXBean).
|
||||
**/
|
||||
public Class<?> getImplementationClass() {
|
||||
return mbean.getResource().getClass();
|
||||
return mbean.getWrappedObject().getClass();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -559,7 +691,7 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
|
||||
MBeanSupport msupport = mbean;
|
||||
final MBeanInfo bi = msupport.getMBeanInfo();
|
||||
final Object impl = msupport.getResource();
|
||||
final Object impl = msupport.getWrappedObject();
|
||||
|
||||
final boolean immutableInfo = immutableInfo(this.getClass());
|
||||
|
||||
@ -1184,6 +1316,7 @@ public class StandardMBean implements DynamicMBean, MBeanRegistration {
|
||||
public ObjectName preRegister(MBeanServer server, ObjectName name)
|
||||
throws Exception {
|
||||
mbean.register(server, name);
|
||||
MBeanInjector.inject(mbean.getWrappedObject(), server, name);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
* have any questions.
|
||||
*/
|
||||
/*
|
||||
* @author IBM Corp.
|
||||
* @(#)author IBM Corp.
|
||||
*
|
||||
* Copyright IBM Corp. 1999-2000. All rights reserved.
|
||||
*/
|
||||
@ -55,6 +55,7 @@ import javax.management.AttributeChangeNotificationFilter;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.DynamicWrapperMBean;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
@ -115,7 +116,7 @@ import sun.reflect.misc.ReflectUtil;
|
||||
*/
|
||||
|
||||
public class RequiredModelMBean
|
||||
implements ModelMBean, MBeanRegistration, NotificationEmitter {
|
||||
implements ModelMBean, MBeanRegistration, NotificationEmitter, DynamicWrapperMBean {
|
||||
|
||||
/*************************************/
|
||||
/* attributes */
|
||||
@ -133,6 +134,9 @@ public class RequiredModelMBean
|
||||
* and operations will be executed */
|
||||
private Object managedResource = null;
|
||||
|
||||
/* true if getWrappedObject returns the wrapped resource */
|
||||
private boolean visible;
|
||||
|
||||
/* records the registering in MBeanServer */
|
||||
private boolean registered = false;
|
||||
private transient MBeanServer server = null;
|
||||
@ -318,9 +322,13 @@ public class RequiredModelMBean
|
||||
*
|
||||
* @param mr Object that is the managed resource
|
||||
* @param mr_type The type of reference for the managed resource.
|
||||
* <br>Can be: "ObjectReference", "Handle", "IOR", "EJBHandle",
|
||||
* or "RMIReference".
|
||||
* <br>In this implementation only "ObjectReference" is supported.
|
||||
* <br>Can be: "ObjectReference", "VisibleObjectReference",
|
||||
* "Handle", "IOR", "EJBHandle", or "RMIReference".
|
||||
* <br>In this implementation only "ObjectReference" and
|
||||
* "VisibleObjectReference" are supported. The two
|
||||
* types are equivalent except for the behavior of the
|
||||
* {@link #getWrappedObject()} and {@link #getWrappedClassLoader()}
|
||||
* methods.
|
||||
*
|
||||
* @exception MBeanException The initializer of the object has
|
||||
* thrown an exception.
|
||||
@ -340,10 +348,11 @@ public class RequiredModelMBean
|
||||
"setManagedResource(Object,String)","Entry");
|
||||
}
|
||||
|
||||
visible = "visibleObjectReference".equalsIgnoreCase(mr_type);
|
||||
|
||||
// check that the mr_type is supported by this JMXAgent
|
||||
// only "objectReference" is supported
|
||||
if ((mr_type == null) ||
|
||||
(! mr_type.equalsIgnoreCase("objectReference"))) {
|
||||
if (!"objectReference".equalsIgnoreCase(mr_type) && !visible) {
|
||||
if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
|
||||
MODELMBEAN_LOGGER.logp(Level.FINER,
|
||||
RequiredModelMBean.class.getName(),
|
||||
@ -368,6 +377,51 @@ public class RequiredModelMBean
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the managed resource for this Model MBean. For compatibility
|
||||
* reasons, the managed resource is only returned if the resource type
|
||||
* specified to {@link #setManagedResource setManagedResource} was {@code
|
||||
* "visibleObjectReference"}. Otherwise, {@code this} is returned.</p>
|
||||
*
|
||||
* @return The value that was specified to {@link #setManagedResource
|
||||
* setManagedResource}, if the resource type is {@code
|
||||
* "visibleObjectReference"}. Otherwise, {@code this}.
|
||||
*/
|
||||
public Object getWrappedObject() {
|
||||
if (visible)
|
||||
return managedResource;
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the ClassLoader of the managed resource for this Model MBean. For
|
||||
* compatibility reasons, the ClassLoader of the managed resource is only
|
||||
* returned if the resource type specified to {@link #setManagedResource
|
||||
* setManagedResource} was {@code "visibleObjectReference"}. Otherwise,
|
||||
* {@code this.getClass().getClassLoader()} is returned.</p>
|
||||
*
|
||||
* @return The ClassLoader of the value that was specified to
|
||||
* {@link #setManagedResource setManagedResource}, if the resource
|
||||
* type is {@code "visibleObjectReference"}. Otherwise, {@code
|
||||
* this.getClass().getClassLoader()}.
|
||||
*/
|
||||
public ClassLoader getWrappedClassLoader() {
|
||||
return getWrappedObject().getClass().getClassLoader();
|
||||
}
|
||||
|
||||
private static boolean isTrue(Descriptor d, String field) {
|
||||
if (d == null)
|
||||
return false;
|
||||
Object x = d.getFieldValue(field);
|
||||
if (x instanceof Boolean)
|
||||
return (Boolean) x;
|
||||
if (!(x instanceof String))
|
||||
return false;
|
||||
String s = (String) x;
|
||||
return ("true".equalsIgnoreCase(s) || "T".equalsIgnoreCase(s));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Instantiates this MBean instance with the data found for
|
||||
* the MBean in the persistent store. The data loaded could include
|
||||
|
@ -38,14 +38,17 @@ have any questions.
|
||||
so within the access control context of the
|
||||
{@link javax.management.monitor.Monitor#start} caller.</p>
|
||||
|
||||
<p>The value being monitored can be a simple value contained within a
|
||||
complex type. For example, the {@link java.lang.management.MemoryMXBean
|
||||
MemoryMXBean} defined in <tt>java.lang.management</tt> has an attribute
|
||||
<tt>HeapMemoryUsage</tt> of type {@link java.lang.management.MemoryUsage
|
||||
MemoryUsage}. To monitor the amount of <i>used</i> memory, described by
|
||||
the <tt>used</tt> property of <tt>MemoryUsage</tt>, you could monitor
|
||||
"<tt>HeapMemoryUsage.used</tt>". That string would be the argument to
|
||||
{@link javax.management.monitor.MonitorMBean#setObservedAttribute(String)
|
||||
<p id="complex">The value being monitored can be a simple value
|
||||
contained within a complex type. For example, the {@link
|
||||
java.lang.management.MemoryMXBean MemoryMXBean} defined in
|
||||
<tt>java.lang.management</tt> has an attribute
|
||||
<tt>HeapMemoryUsage</tt> of type {@link
|
||||
java.lang.management.MemoryUsage MemoryUsage}. To monitor the
|
||||
amount of <i>used</i> memory, described by the <tt>used</tt>
|
||||
property of <tt>MemoryUsage</tt>, you could monitor
|
||||
"<tt>HeapMemoryUsage.used</tt>". That string would be the
|
||||
argument to {@link
|
||||
javax.management.monitor.MonitorMBean#setObservedAttribute(String)
|
||||
setObservedAttribute}.</p>
|
||||
|
||||
<p>The rules used to interpret an <tt>ObservedAttribute</tt> like
|
||||
|
@ -56,41 +56,41 @@ have any questions.
|
||||
resource. It has a <em>management interface</em> consisting
|
||||
of:</p>
|
||||
|
||||
<ul>
|
||||
<li>named and typed attributes that can be read and/or
|
||||
written</li>
|
||||
|
||||
<li>named and typed operations that can be invoked</li>
|
||||
<ul>
|
||||
<li>named and typed attributes that can be read and/or
|
||||
written</li>
|
||||
|
||||
<li>typed notifications that can be emitted by the MBean.</li>
|
||||
</ul>
|
||||
<li>named and typed operations that can be invoked</li>
|
||||
|
||||
<p>For example, an MBean representing an application's
|
||||
configuration could have attributes representing the different
|
||||
configuration items. Reading the <code>CacheSize</code>
|
||||
attribute would return the current value of that item.
|
||||
Writing it would update the item, potentially changing the
|
||||
behavior of the running application. An operation such as
|
||||
<code>save</code> could store the current configuration
|
||||
persistently. A notification such as
|
||||
<code>ConfigurationChangedNotification</code> could be sent
|
||||
every time the configuration is changed.</p>
|
||||
<li>typed notifications that can be emitted by the MBean.</li>
|
||||
</ul>
|
||||
|
||||
<p>In the standard usage of the JMX API, MBeans are implemented
|
||||
as Java objects. However, as explained below, these objects are
|
||||
not usually referenced directly.</p>
|
||||
<p>For example, an MBean representing an application's
|
||||
configuration could have attributes representing the different
|
||||
configuration items. Reading the <code>CacheSize</code>
|
||||
attribute would return the current value of that item.
|
||||
Writing it would update the item, potentially changing the
|
||||
behavior of the running application. An operation such as
|
||||
<code>save</code> could store the current configuration
|
||||
persistently. A notification such as
|
||||
<code>ConfigurationChangedNotification</code> could be sent
|
||||
every time the configuration is changed.</p>
|
||||
|
||||
<p>In the standard usage of the JMX API, MBeans are implemented
|
||||
as Java objects. However, as explained below, these objects are
|
||||
not usually referenced directly.</p>
|
||||
|
||||
|
||||
<h3>Standard MBeans</h3>
|
||||
<h3>Standard MBeans</h3>
|
||||
|
||||
<p>To make MBean implementation simple, the JMX API includes the
|
||||
notion of <em>Standard MBeans</em>. A Standard MBean is one
|
||||
whose attributes and operations are deduced from a Java
|
||||
interface using certain naming patterns, similar to those used
|
||||
by JavaBeans<sup><font size="-1">TM</font></sup>. For
|
||||
example, consider an interface like this:</p>
|
||||
<p>To make MBean implementation simple, the JMX API includes the
|
||||
notion of <em>Standard MBeans</em>. A Standard MBean is one
|
||||
whose attributes and operations are deduced from a Java
|
||||
interface using certain naming patterns, similar to those used
|
||||
by JavaBeans<sup><font size="-1">TM</font></sup>. For
|
||||
example, consider an interface like this:</p>
|
||||
|
||||
<pre>
|
||||
<pre>
|
||||
public interface ConfigurationMBean {
|
||||
public int getCacheSize();
|
||||
public void setCacheSize(int size);
|
||||
@ -128,107 +128,148 @@ have any questions.
|
||||
class.</p>
|
||||
|
||||
|
||||
<h3>MXBeans</h3>
|
||||
|
||||
<p>An <em>MXBean</em> is a variant of Standard MBean where complex
|
||||
types are mapped to a standard set of types defined in the
|
||||
{@link javax.management.openmbean} package. MXBeans are appropriate
|
||||
if you would otherwise need to reference application-specific
|
||||
classes in your MBean interface. They are described in detail
|
||||
in the specification for {@link javax.management.MXBean MXBean}.
|
||||
<h3 id="stdannot">Defining Standard MBeans with annotations</h3>
|
||||
|
||||
<p>As an alternative to creating an interface such as
|
||||
<code>ConfigurationMBean</code> and a class that implements it,
|
||||
you can write just the class, and use annotations to pick out the
|
||||
public methods that will make up the management interface. For
|
||||
example, the following class has the same management interface
|
||||
as a <code>Configuration</code> class that implements the
|
||||
<code>ConfigurationMBean</code> interface above.</p>
|
||||
|
||||
<pre>
|
||||
{@link javax.management.MBean @MBean}
|
||||
public class Configuration {
|
||||
{@link javax.management.ManagedAttribute @ManagedAttribute}
|
||||
public int getCacheSize() {...}
|
||||
@ManagedAttribute
|
||||
public void setCacheSize(int size) {...}
|
||||
|
||||
@ManagedAttribute
|
||||
public long getLastChangedTime() {...}
|
||||
|
||||
{@link javax.management.ManagedOperation @ManagedOperation}
|
||||
public void save() {...}
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>This approach simplifies development, but it does have two
|
||||
potential drawbacks. First, if you run the Javadoc tool on
|
||||
this class, the documentation of the management interface may
|
||||
be mixed in with the documentation of non-management methods
|
||||
in the class. Second, you cannot make a proxy
|
||||
as described <a href="#proxy">below</a> if you do not have an
|
||||
interface like <code>ConfigurationMBean</code>.</p>
|
||||
|
||||
|
||||
<h3>Dynamic MBeans</h3>
|
||||
<h3>MXBeans</h3>
|
||||
|
||||
<p>A <em>Dynamic MBean</em> is an MBean that defines its
|
||||
management interface at run-time. For example, a configuration
|
||||
MBean could determine the names and types of the attributes it
|
||||
exposes by parsing an XML file.</p>
|
||||
<p>An <em>MXBean</em> is a variant of Standard MBean where complex
|
||||
types are mapped to a standard set of types defined in the
|
||||
{@link javax.management.openmbean} package. MXBeans are appropriate
|
||||
if you would otherwise need to reference application-specific
|
||||
classes in your MBean interface. They are described in detail
|
||||
in the specification for {@link javax.management.MXBean MXBean}.</p>
|
||||
|
||||
<p>Any Java object of a class that implements the {@link
|
||||
javax.management.DynamicMBean DynamicMBean} interface is a
|
||||
Dynamic MBean.</p>
|
||||
<p>You can define MXBeans using annotations as described
|
||||
in the <a href="#stdannot">previous section</a>, but
|
||||
using the <code>@MXBean</code> annotation instead of
|
||||
<code>@MBean</code>.</p>
|
||||
|
||||
|
||||
<h3>Open MBeans</h3>
|
||||
<h3>Dynamic MBeans</h3>
|
||||
|
||||
<p>An <em>Open MBean</em> is a kind of Dynamic MBean where the
|
||||
types of attributes and of operation parameters and return
|
||||
values are built using a small set of predefined Java classes.
|
||||
Open MBeans facilitate operation with remote management programs
|
||||
that do not necessarily have access to application-specific
|
||||
types, including non-Java programs. Open MBeans are defined by
|
||||
the package <a href="openmbean/package-summary.html"><code>
|
||||
javax.management.openmbean</code></a>.</p>
|
||||
<p>A <em>Dynamic MBean</em> is an MBean that defines its
|
||||
management interface at run-time. For example, a configuration
|
||||
MBean could determine the names and types of the attributes it
|
||||
exposes by parsing an XML file.</p>
|
||||
|
||||
<p>Any Java object of a class that implements the {@link
|
||||
javax.management.DynamicMBean DynamicMBean} interface is a
|
||||
Dynamic MBean.</p>
|
||||
|
||||
|
||||
<h3>Model MBeans</h3>
|
||||
<h3>Open MBeans</h3>
|
||||
|
||||
<p>A <em>Model MBean</em> is a kind of Dynamic MBean that acts
|
||||
as a bridge between the management interface and the
|
||||
underlying managed resource. Both the management interface and
|
||||
the managed resource are specified as Java objects. The same
|
||||
Model MBean implementation can be reused many times with
|
||||
different management interfaces and managed resources, and it can
|
||||
provide common functionality such as persistence and caching.
|
||||
Model MBeans are defined by the package
|
||||
<a href="modelmbean/package-summary.html"><code>
|
||||
javax.management.modelmbean</code></a>.</p>
|
||||
<p>An <em>Open MBean</em> is a kind of Dynamic MBean where the
|
||||
types of attributes and of operation parameters and return
|
||||
values are built using a small set of predefined Java classes.
|
||||
Open MBeans facilitate operation with remote management programs
|
||||
that do not necessarily have access to application-specific
|
||||
types, including non-Java programs. Open MBeans are defined by
|
||||
the package <a href="openmbean/package-summary.html"><code>
|
||||
javax.management.openmbean</code></a>.</p>
|
||||
|
||||
|
||||
<h2>MBean Server</h2>
|
||||
|
||||
<p>To be useful, an MBean must be registered in an <em>MBean
|
||||
Server</em>. An MBean Server is a repository of MBeans.
|
||||
Usually the only access to the MBeans is through the MBean
|
||||
Server. In other words, code no longer accesses the Java
|
||||
object implementing the MBean directly, but instead accesses
|
||||
the MBean by name through the MBean Server. Each MBean has a
|
||||
unique name within the MBean Server, defined by the {@link
|
||||
javax.management.ObjectName ObjectName} class.</p>
|
||||
|
||||
<p>An MBean Server is an object implementing the interface
|
||||
{@link javax.management.MBeanServer MBeanServer}.
|
||||
The most convenient MBean Server to use is the
|
||||
<em>Platform MBean Server</em>. This is a
|
||||
single MBean Server that can be shared by different managed
|
||||
components running within the same Java Virtual Machine. The
|
||||
Platform MBean Server is accessed with the method {@link
|
||||
java.lang.management.ManagementFactory#getPlatformMBeanServer()}.</p>
|
||||
<h3>Model MBeans</h3>
|
||||
|
||||
<p>Application code can also create a new MBean Server, or
|
||||
access already-created MBean Servers, using the {@link
|
||||
javax.management.MBeanServerFactory MBeanServerFactory} class.</p>
|
||||
<p>A <em>Model MBean</em> is a kind of Dynamic MBean that acts
|
||||
as a bridge between the management interface and the
|
||||
underlying managed resource. Both the management interface and
|
||||
the managed resource are specified as Java objects. The same
|
||||
Model MBean implementation can be reused many times with
|
||||
different management interfaces and managed resources, and it can
|
||||
provide common functionality such as persistence and caching.
|
||||
Model MBeans are defined by the package
|
||||
<a href="modelmbean/package-summary.html"><code>
|
||||
javax.management.modelmbean</code></a>.</p>
|
||||
|
||||
|
||||
<h3>Creating MBeans in the MBean Server</h3>
|
||||
<h2>MBean Server</h2>
|
||||
|
||||
<p>There are two ways to create an MBean. One is to construct a
|
||||
Java object that will be the MBean, then use the {@link
|
||||
javax.management.MBeanServer#registerMBean registerMBean}
|
||||
method to register it in the MBean Server. The other is to
|
||||
create and register the MBean in a single operation using one
|
||||
of the {@link javax.management.MBeanServer#createMBean(String,
|
||||
javax.management.ObjectName) createMBean} methods.</p>
|
||||
<p>To be useful, an MBean must be registered in an <em>MBean
|
||||
Server</em>. An MBean Server is a repository of MBeans.
|
||||
Usually the only access to the MBeans is through the MBean
|
||||
Server. In other words, code no longer accesses the Java
|
||||
object implementing the MBean directly, but instead accesses
|
||||
the MBean by name through the MBean Server. Each MBean has a
|
||||
unique name within the MBean Server, defined by the {@link
|
||||
javax.management.ObjectName ObjectName} class.</p>
|
||||
|
||||
<p>The <code>registerMBean</code> method is simpler for local
|
||||
use, but cannot be used remotely. The
|
||||
<code>createMBean</code> method can be used remotely, but
|
||||
sometimes requires attention to class loading issues.</p>
|
||||
<p>An MBean Server is an object implementing the interface
|
||||
{@link javax.management.MBeanServer MBeanServer}.
|
||||
The most convenient MBean Server to use is the
|
||||
<em>Platform MBean Server</em>. This is a
|
||||
single MBean Server that can be shared by different managed
|
||||
components running within the same Java Virtual Machine. The
|
||||
Platform MBean Server is accessed with the method {@link
|
||||
java.lang.management.ManagementFactory#getPlatformMBeanServer()}.</p>
|
||||
|
||||
<p>An MBean can perform actions when it is registered in or
|
||||
unregistered from an MBean Server if it implements the {@link
|
||||
javax.management.MBeanRegistration MBeanRegistration}
|
||||
interface.</p>
|
||||
<p>Application code can also create a new MBean Server, or
|
||||
access already-created MBean Servers, using the {@link
|
||||
javax.management.MBeanServerFactory MBeanServerFactory} class.</p>
|
||||
|
||||
|
||||
<h3>Accessing MBeans in the MBean Server</h3>
|
||||
<h3>Creating MBeans in the MBean Server</h3>
|
||||
|
||||
<p>Given an <code>ObjectName</code> <code>name</code> and an
|
||||
<code>MBeanServer</code> <code>mbs</code>, you can access
|
||||
attributes and operations as in this example:</p>
|
||||
<p>There are two ways to create an MBean. One is to construct a
|
||||
Java object that will be the MBean, then use the {@link
|
||||
javax.management.MBeanServer#registerMBean registerMBean}
|
||||
method to register it in the MBean Server. The other is to
|
||||
create and register the MBean in a single operation using one
|
||||
of the {@link javax.management.MBeanServer#createMBean(String,
|
||||
javax.management.ObjectName) createMBean} methods.</p>
|
||||
|
||||
<pre>
|
||||
<p>The <code>registerMBean</code> method is simpler for local
|
||||
use, but cannot be used remotely. The
|
||||
<code>createMBean</code> method can be used remotely, but
|
||||
sometimes requires attention to class loading issues.</p>
|
||||
|
||||
<p>An MBean can perform actions when it is registered in or
|
||||
unregistered from an MBean Server if it implements the {@link
|
||||
javax.management.MBeanRegistration MBeanRegistration}
|
||||
interface.</p>
|
||||
|
||||
|
||||
<h3>Accessing MBeans in the MBean Server</h3>
|
||||
|
||||
<p>Given an <code>ObjectName</code> <code>name</code> and an
|
||||
<code>MBeanServer</code> <code>mbs</code>, you can access
|
||||
attributes and operations as in this example:</p>
|
||||
|
||||
<pre>
|
||||
int cacheSize = mbs.getAttribute(name, "CacheSize");
|
||||
{@link javax.management.Attribute Attribute} newCacheSize =
|
||||
new Attribute("CacheSize", new Integer(2000));
|
||||
@ -236,9 +277,9 @@ have any questions.
|
||||
mbs.invoke(name, "save", new Object[0], new Class[0]);
|
||||
</pre>
|
||||
|
||||
<p>Alternatively, if you have a Java interface that corresponds
|
||||
to the management interface for the MBean, you can use an
|
||||
<em>MBean proxy</em> like this:</p>
|
||||
<p id="proxy">Alternatively, if you have a Java interface that
|
||||
corresponds to the management interface for the MBean, you can use an
|
||||
<em>MBean proxy</em> like this:</p>
|
||||
|
||||
<pre>
|
||||
ConfigurationMBean conf =
|
||||
@ -264,66 +305,116 @@ have any questions.
|
||||
perform the query.</p>
|
||||
|
||||
|
||||
<h2>Notifications</h2>
|
||||
<h3>MBean lifecycle and resource injection</h3>
|
||||
|
||||
<p>A <em>notification</em> is an instance of the {@link
|
||||
javax.management.Notification Notification} class or a
|
||||
subclass. In addition to its Java class, it has a
|
||||
<em>type</em> string that can distinguish it from other
|
||||
notifications of the same class.</p>
|
||||
<p>An MBean can implement the {@link javax.management.MBeanRegistration
|
||||
MBeanRegistration} interface in order to be told when it is registered
|
||||
and unregistered in the MBean Server. Additionally, the {@link
|
||||
javax.management.MBeanRegistration#preRegister preRegister} method
|
||||
allows the MBean to get a reference to the <code>MBeanServer</code>
|
||||
object and to get its <code>ObjectName</code> within the MBean
|
||||
Server.</p>
|
||||
|
||||
<p>An MBean that will emit notifications must implement the
|
||||
{@link javax.management.NotificationBroadcaster
|
||||
NotificationBroadcaster} or {@link
|
||||
javax.management.NotificationEmitter NotificationEmitter}
|
||||
interface. Usually, it does this by subclassing {@link
|
||||
javax.management.NotificationBroadcasterSupport
|
||||
NotificationBroadcasterSupport} or by delegating to an instance
|
||||
of that class.</p>
|
||||
|
||||
<p>Notifications can be received by a <em>listener</em>, which
|
||||
is an object that implements the {@link
|
||||
javax.management.NotificationListener NotificationListener}
|
||||
interface. You can add a listener to an MBean with the method
|
||||
{@link
|
||||
javax.management.MBeanServer#addNotificationListener(ObjectName,
|
||||
NotificationListener, NotificationFilter, Object)}.
|
||||
You can optionally supply a <em>filter</em> to this method, to
|
||||
select only notifications of interest. A filter is an object
|
||||
that implements the {@link javax.management.NotificationFilter
|
||||
NotificationFilter} interface.</p>
|
||||
|
||||
<p>An MBean can be a listener for notifications emitted by other
|
||||
MBeans in the same MBean Server. In this case, it implements
|
||||
{@link javax.management.NotificationListener
|
||||
NotificationListener} and the method {@link
|
||||
javax.management.MBeanServer#addNotificationListener(ObjectName,
|
||||
ObjectName, NotificationFilter, Object)} is used to listen.</p>
|
||||
<p>If the only reason to implement <code>MBeanRegistration</code> is to
|
||||
discover the <code>MBeanServer</code> and <code>ObjectName</code>, <a
|
||||
href="MBeanRegistration.html#injection">resource injection</a> may be
|
||||
more convenient.</p>
|
||||
|
||||
|
||||
<h2>Remote Access to MBeans</h2>
|
||||
<h2>Notifications</h2>
|
||||
|
||||
<p>An MBean Server can be accessed remotely through a
|
||||
<em>connector</em>. A connector allows a remote Java
|
||||
application to access an MBean Server in essentially the same
|
||||
way as a local one. The package
|
||||
<a href="remote/package-summary.html"><code>
|
||||
javax.management.remote</code></a> defines connectors.</p>
|
||||
<p>A <em>notification</em> is an instance of the {@link
|
||||
javax.management.Notification Notification} class or a
|
||||
subclass. In addition to its Java class, it has a
|
||||
<em>type</em> string that can distinguish it from other
|
||||
notifications of the same class.</p>
|
||||
|
||||
<p>The JMX specification also defines the notion of an
|
||||
<em>adaptor</em>. An adaptor translates between requests in a
|
||||
protocol such as SNMP or HTML and accesses to an MBean Server.
|
||||
So for example an SNMP GET operation might result in a
|
||||
<code>getAttribute</code> on the MBean Server.</p>
|
||||
<p>If an MBean is to emit notifications, it must do one of two things.</p>
|
||||
|
||||
<p id="spec">
|
||||
@see <a href="{@docRoot}/../technotes/guides/jmx/index.html">
|
||||
Java SE 6 Platform documentation on JMX technology</a>
|
||||
in particular the
|
||||
<a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
|
||||
JMX Specification, version 1.4(pdf).</a>
|
||||
<ul>
|
||||
<li>It can implement the interface {@link
|
||||
javax.management.NotificationEmitter NotificationEmitter} (or
|
||||
its parent {@link javax.management.NotificationBroadcaster
|
||||
NotificationBroadcaster}), usually by subclassing
|
||||
{@link javax.management.NotificationBroadcasterSupport
|
||||
NotificationBroadcasterSupport} or delegating to an instance of
|
||||
that class.</li>
|
||||
<li>It can use <a href="MBeanRegistration.html#injection">resource
|
||||
injection</a> to obtain a {@link javax.management.SendNotification
|
||||
SendNotification} object that it can use to send
|
||||
notifications.</li>
|
||||
</ul>
|
||||
|
||||
@since 1.5
|
||||
<p>The two classes below illustrate these two techniques:</p>
|
||||
|
||||
<pre>
|
||||
// Implementing NotificationEmitter (via NotificationBroadcasterSupport)
|
||||
public class Configuration <b>extends NotificationBroadcasterSupport</b>
|
||||
implements ConfigurationMBean {
|
||||
...
|
||||
private void updated() {
|
||||
Notification n = new Notification(...);
|
||||
<b>{@link javax.management.NotificationBroadcasterSupport#sendNotification
|
||||
sendNotification}(n)</b>;
|
||||
}
|
||||
}
|
||||
|
||||
// Getting a SendNotification through resource injection
|
||||
public class Configuration implements ConfigurationMBean {
|
||||
<b>@Resource</b>
|
||||
private volatile SendNotification sender;
|
||||
...
|
||||
private void updated() {
|
||||
Notification n = new Notification(...);
|
||||
<b>sender.sendNotification(n)</b>;
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
|
||||
<p>Notifications can be received by a <em>listener</em>, which
|
||||
is an object that implements the {@link
|
||||
javax.management.NotificationListener NotificationListener}
|
||||
interface. You can add a listener to an MBean with the method
|
||||
{@link
|
||||
javax.management.MBeanServer#addNotificationListener(ObjectName,
|
||||
NotificationListener, NotificationFilter, Object)}.
|
||||
You can optionally supply a <em>filter</em> to this method, to
|
||||
select only notifications of interest. A filter is an object
|
||||
that implements the {@link javax.management.NotificationFilter
|
||||
NotificationFilter} interface.</p>
|
||||
|
||||
<p>An MBean can be a listener for notifications emitted by other
|
||||
MBeans in the same MBean Server. In this case, it implements
|
||||
{@link javax.management.NotificationListener
|
||||
NotificationListener} and the method {@link
|
||||
javax.management.MBeanServer#addNotificationListener(ObjectName,
|
||||
ObjectName, NotificationFilter, Object)} is used to listen.</p>
|
||||
|
||||
|
||||
<h2>Remote Access to MBeans</h2>
|
||||
|
||||
<p>An MBean Server can be accessed remotely through a
|
||||
<em>connector</em>. A connector allows a remote Java
|
||||
application to access an MBean Server in essentially the same
|
||||
way as a local one. The package
|
||||
<a href="remote/package-summary.html"><code>
|
||||
javax.management.remote</code></a> defines connectors.</p>
|
||||
|
||||
<p>The JMX specification also defines the notion of an
|
||||
<em>adaptor</em>. An adaptor translates between requests in a
|
||||
protocol such as SNMP or HTML and accesses to an MBean Server.
|
||||
So for example an SNMP GET operation might result in a
|
||||
<code>getAttribute</code> on the MBean Server.</p>
|
||||
|
||||
<p id="spec">
|
||||
@see <a href="{@docRoot}/../technotes/guides/jmx/index.html">
|
||||
Java SE 6 Platform documentation on JMX technology</a>
|
||||
in particular the
|
||||
<a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
|
||||
JMX Specification, version 1.4(pdf).</a>
|
||||
|
||||
@since 1.5
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
337
jdk/test/javax/management/Introspector/AnnotatedMBeanTest.java
Normal file
337
jdk/test/javax/management/Introspector/AnnotatedMBeanTest.java
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test %M% %I%
|
||||
* @bug 6323980
|
||||
* @summary Test MBeans defined with @MBean
|
||||
* @author Eamonn McManus
|
||||
* @run main/othervm -ea AnnotatedMBeanTest
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.management.Attribute;
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.DescriptorKey;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ManagedAttribute;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.MBean;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.CompositeType;
|
||||
|
||||
public class AnnotatedMBeanTest {
|
||||
private static MBeanServer mbs;
|
||||
private static final ObjectName objectName;
|
||||
static {
|
||||
try {
|
||||
objectName = new ObjectName("test:type=Test");
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (!AnnotatedMBeanTest.class.desiredAssertionStatus())
|
||||
throw new Exception("Test must be run with -ea");
|
||||
|
||||
File policyFile = File.createTempFile("jmxperms", ".policy");
|
||||
policyFile.deleteOnExit();
|
||||
PrintWriter pw = new PrintWriter(policyFile);
|
||||
pw.println("grant {");
|
||||
pw.println(" permission javax.management.MBeanPermission \"*\", \"*\";");
|
||||
pw.println(" permission javax.management.MBeanServerPermission \"*\";");
|
||||
pw.println(" permission javax.management.MBeanTrustPermission \"*\";");
|
||||
pw.println("};");
|
||||
pw.close();
|
||||
|
||||
System.setProperty("java.security.policy", policyFile.getAbsolutePath());
|
||||
System.setSecurityManager(new SecurityManager());
|
||||
|
||||
String failure = null;
|
||||
|
||||
for (Method m : AnnotatedMBeanTest.class.getDeclaredMethods()) {
|
||||
if (Modifier.isStatic(m.getModifiers()) &&
|
||||
m.getName().startsWith("test") &&
|
||||
m.getParameterTypes().length == 0) {
|
||||
mbs = MBeanServerFactory.newMBeanServer();
|
||||
try {
|
||||
m.invoke(null);
|
||||
System.out.println(m.getName() + " OK");
|
||||
} catch (InvocationTargetException ite) {
|
||||
System.out.println(m.getName() + " got exception:");
|
||||
Throwable t = ite.getCause();
|
||||
t.printStackTrace(System.out);
|
||||
failure = m.getName() + ": " + t.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (failure == null)
|
||||
System.out.println("TEST PASSED");
|
||||
else
|
||||
throw new Exception("TEST FAILED: " + failure);
|
||||
}
|
||||
|
||||
public static class Stats {
|
||||
private final int used;
|
||||
private final int size;
|
||||
private final boolean interesting;
|
||||
|
||||
public Stats(int used, int size, boolean interesting) {
|
||||
this.used = used;
|
||||
this.size = size;
|
||||
this.interesting = interesting;
|
||||
}
|
||||
|
||||
public int getUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public boolean isInteresting() {
|
||||
return interesting;
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public static @interface Units {
|
||||
@DescriptorKey("units")
|
||||
String value();
|
||||
}
|
||||
|
||||
@MBean
|
||||
public static class Cache {
|
||||
private int used = 23;
|
||||
private int size = 99;
|
||||
|
||||
@ManagedAttribute
|
||||
@Units("bytes")
|
||||
public int getUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public void setSize(int x) {
|
||||
this.size = x;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public boolean isInteresting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public Stats getStats() {
|
||||
return new Stats(used, size, false);
|
||||
}
|
||||
|
||||
@ManagedOperation
|
||||
public int dropOldest(int n) {
|
||||
return 55;
|
||||
}
|
||||
|
||||
private void irrelevantMethod() {}
|
||||
private int getIrrelevant() {return 0;}
|
||||
public int getIrrelevant2() {return 0;}
|
||||
|
||||
public int otherIrrelevantMethod() {return 5;}
|
||||
}
|
||||
|
||||
public static class SubCache extends Cache {
|
||||
// SubCache does not have the @MBean annotation
|
||||
// but its parent does. It doesn't add any @ManagedAttribute or
|
||||
// @ManagedOperation methods, so its management interface
|
||||
// should be the same.
|
||||
private void irrelevantMethod2() {}
|
||||
public int otherIrrelevantMethod3() {return 0;}
|
||||
|
||||
public int getX() {return 0;}
|
||||
public void setX(int x) {}
|
||||
}
|
||||
|
||||
@MXBean
|
||||
public static class CacheMX {
|
||||
private int used = 23;
|
||||
private int size = 99;
|
||||
|
||||
@ManagedAttribute
|
||||
@Units("bytes")
|
||||
public int getUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public void setSize(int x) {
|
||||
this.size = x;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public boolean isInteresting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public Stats getStats() {
|
||||
return new Stats(used, size, false);
|
||||
}
|
||||
|
||||
@ManagedOperation
|
||||
public int dropOldest(int n) {
|
||||
return 55;
|
||||
}
|
||||
|
||||
private void irrelevantMethod() {}
|
||||
private int getIrrelevant() {return 0;}
|
||||
public int getIrrelevant2() {return 0;}
|
||||
|
||||
public int otherIrrelevantMethod() {return 5;}
|
||||
}
|
||||
|
||||
public static class SubCacheMX extends CacheMX {
|
||||
private void irrelevantMethod2() {}
|
||||
public int otherIrrelevantMethod3() {return 0;}
|
||||
|
||||
public int getX() {return 0;}
|
||||
public void setX(int x) {}
|
||||
}
|
||||
|
||||
private static void testSimpleManagedResource() throws Exception {
|
||||
testResource(new Cache(), false);
|
||||
}
|
||||
|
||||
private static void testSubclassManagedResource() throws Exception {
|
||||
testResource(new SubCache(), false);
|
||||
}
|
||||
|
||||
private static void testMXBeanResource() throws Exception {
|
||||
testResource(new CacheMX(), true);
|
||||
}
|
||||
|
||||
private static void testSubclassMXBeanResource() throws Exception {
|
||||
testResource(new SubCacheMX(), true);
|
||||
}
|
||||
|
||||
private static void testResource(Object resource, boolean mx) throws Exception {
|
||||
mbs.registerMBean(resource, objectName);
|
||||
|
||||
MBeanInfo mbi = mbs.getMBeanInfo(objectName);
|
||||
assert mbi.getDescriptor().getFieldValue("mxbean").equals(Boolean.toString(mx));
|
||||
|
||||
MBeanAttributeInfo[] mbais = mbi.getAttributes();
|
||||
|
||||
assert mbais.length == 4: mbais.length;
|
||||
|
||||
for (MBeanAttributeInfo mbai : mbais) {
|
||||
String name = mbai.getName();
|
||||
if (name.equals("Used")) {
|
||||
assert mbai.isReadable();
|
||||
assert !mbai.isWritable();
|
||||
assert !mbai.isIs();
|
||||
assert mbai.getType().equals("int");
|
||||
assert "bytes".equals(mbai.getDescriptor().getFieldValue("units"));
|
||||
} else if (name.equals("Size")) {
|
||||
assert mbai.isReadable();
|
||||
assert mbai.isWritable();
|
||||
assert !mbai.isIs();
|
||||
assert mbai.getType().equals("int");
|
||||
} else if (name.equals("Interesting")) {
|
||||
assert mbai.isReadable();
|
||||
assert !mbai.isWritable();
|
||||
assert mbai.isIs();
|
||||
assert mbai.getType().equals("boolean");
|
||||
} else if (name.equals("Stats")) {
|
||||
assert mbai.isReadable();
|
||||
assert !mbai.isWritable();
|
||||
assert !mbai.isIs();
|
||||
Descriptor d = mbai.getDescriptor();
|
||||
if (mx) {
|
||||
assert mbai.getType().equals(CompositeData.class.getName());
|
||||
assert d.getFieldValue("originalType").equals(Stats.class.getName());
|
||||
CompositeType ct = (CompositeType) d.getFieldValue("openType");
|
||||
Set<String> names = new HashSet<String>(
|
||||
Arrays.asList("used", "size", "interesting"));
|
||||
assert ct.keySet().equals(names) : ct.keySet();
|
||||
} else {
|
||||
assert mbai.getType().equals(Stats.class.getName());
|
||||
}
|
||||
} else
|
||||
assert false : name;
|
||||
}
|
||||
|
||||
MBeanOperationInfo[] mbois = mbi.getOperations();
|
||||
|
||||
assert mbois.length == 1: mbois.length;
|
||||
|
||||
MBeanOperationInfo mboi = mbois[0];
|
||||
assert mboi.getName().equals("dropOldest");
|
||||
assert mboi.getReturnType().equals("int");
|
||||
MBeanParameterInfo[] mbpis = mboi.getSignature();
|
||||
assert mbpis.length == 1: mbpis.length;
|
||||
assert mbpis[0].getType().equals("int");
|
||||
|
||||
assert mbs.getAttribute(objectName, "Used").equals(23);
|
||||
|
||||
assert mbs.getAttribute(objectName, "Size").equals(99);
|
||||
mbs.setAttribute(objectName, new Attribute("Size", 55));
|
||||
assert mbs.getAttribute(objectName, "Size").equals(55);
|
||||
|
||||
assert mbs.getAttribute(objectName, "Interesting").equals(false);
|
||||
|
||||
Object stats = mbs.getAttribute(objectName, "Stats");
|
||||
assert (mx ? CompositeData.class : Stats.class).isInstance(stats) : stats.getClass();
|
||||
|
||||
int ret = (Integer) mbs.invoke(
|
||||
objectName, "dropOldest", new Object[] {66}, new String[] {"int"});
|
||||
assert ret == 55;
|
||||
}
|
||||
}
|
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test %M% %I%
|
||||
* @bug 6323980
|
||||
* @summary Test @NotificationInfo annotation
|
||||
* @author Eamonn McManus
|
||||
* @run main/othervm -ea AnnotatedNotificationInfoTest
|
||||
*/
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.Field;
|
||||
import javax.annotation.Resource;
|
||||
import javax.management.AttributeChangeNotification;
|
||||
import javax.management.Description;
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
import javax.management.NotificationInfo;
|
||||
import javax.management.NotificationInfos;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.SendNotification;
|
||||
|
||||
public class AnnotatedNotificationInfoTest {
|
||||
// Data for the first test. This tests that MBeanNotificationInfo
|
||||
// is correctly derived from @NotificationInfo.
|
||||
// Every static field called mbean* is expected to be an MBean
|
||||
// with a single MBeanNotificationInfo that has the same value
|
||||
// in each case.
|
||||
|
||||
@NotificationInfo(
|
||||
types = {"foo", "bar"},
|
||||
notificationClass = AttributeChangeNotification.class,
|
||||
description = @Description(
|
||||
value = "description",
|
||||
bundleBaseName = "bundle",
|
||||
key = "key"),
|
||||
descriptorFields = {"foo=bar"})
|
||||
public static interface Intf1MBean {}
|
||||
|
||||
public static class Intf1
|
||||
extends NotificationBroadcasterSupport implements Intf1MBean {}
|
||||
|
||||
private static Object mbeanIntf1 = new Intf1();
|
||||
|
||||
@NotificationInfos(
|
||||
@NotificationInfo(
|
||||
types = {"foo", "bar"},
|
||||
notificationClass = AttributeChangeNotification.class,
|
||||
description = @Description(
|
||||
value = "description",
|
||||
bundleBaseName = "bundle",
|
||||
key = "key"),
|
||||
descriptorFields = {"foo=bar"}))
|
||||
public static interface Intf2MBean {}
|
||||
|
||||
public static class Intf2
|
||||
extends NotificationBroadcasterSupport implements Intf2MBean {}
|
||||
|
||||
private static Object mbeanIntf2 = new Intf2();
|
||||
|
||||
@NotificationInfos({})
|
||||
@NotificationInfo(
|
||||
types = {"foo", "bar"},
|
||||
notificationClass = AttributeChangeNotification.class,
|
||||
description = @Description(
|
||||
value = "description",
|
||||
bundleBaseName = "bundle",
|
||||
key = "key"),
|
||||
descriptorFields = {"foo=bar"})
|
||||
public static interface Intf3MBean {}
|
||||
|
||||
public static class Intf3
|
||||
extends NotificationBroadcasterSupport implements Intf3MBean {}
|
||||
|
||||
private static Object mbeanIntf3 = new Intf3();
|
||||
|
||||
@NotificationInfo(
|
||||
types = {"foo", "bar"},
|
||||
notificationClass = AttributeChangeNotification.class,
|
||||
description = @Description(
|
||||
value = "description",
|
||||
bundleBaseName = "bundle",
|
||||
key = "key"),
|
||||
descriptorFields = {"foo=bar"})
|
||||
public static interface ParentIntf {}
|
||||
|
||||
public static interface Intf4MBean extends Serializable, ParentIntf, Cloneable {}
|
||||
|
||||
public static class Intf4
|
||||
extends NotificationBroadcasterSupport implements Intf4MBean {}
|
||||
|
||||
private static Object mbeanIntf4 = new Intf4();
|
||||
|
||||
@NotificationInfo(
|
||||
types = {"foo", "bar"},
|
||||
notificationClass = AttributeChangeNotification.class,
|
||||
description = @Description(
|
||||
value = "description",
|
||||
bundleBaseName = "bundle",
|
||||
key = "key"),
|
||||
descriptorFields = {"foo=bar"})
|
||||
public static interface Intf5MXBean {}
|
||||
|
||||
public static class Intf5Impl
|
||||
extends NotificationBroadcasterSupport implements Intf5MXBean {}
|
||||
|
||||
private static Object mbeanIntf5 = new Intf5Impl();
|
||||
|
||||
public static interface Impl1MBean {}
|
||||
|
||||
@NotificationInfo(
|
||||
types = {"foo", "bar"},
|
||||
notificationClass = AttributeChangeNotification.class,
|
||||
description = @Description(
|
||||
value = "description",
|
||||
bundleBaseName = "bundle",
|
||||
key = "key"),
|
||||
descriptorFields = {"foo=bar"})
|
||||
public static class Impl1
|
||||
extends NotificationBroadcasterSupport implements Impl1MBean {}
|
||||
|
||||
private static Object mbeanImpl1 = new Impl1();
|
||||
|
||||
@NotificationInfo(
|
||||
types = {"foo", "bar"},
|
||||
notificationClass = AttributeChangeNotification.class,
|
||||
description = @Description(
|
||||
value = "description",
|
||||
bundleBaseName = "bundle",
|
||||
key = "key"),
|
||||
descriptorFields = {"foo=bar"})
|
||||
public static class ParentImpl extends NotificationBroadcasterSupport {}
|
||||
|
||||
public static interface Impl2MBean {}
|
||||
|
||||
public static class Impl2 extends ParentImpl implements Impl2MBean {}
|
||||
|
||||
private static Object mbeanImpl2 = new Impl2();
|
||||
|
||||
public static interface Impl3MXBean {}
|
||||
|
||||
@NotificationInfo(
|
||||
types = {"foo", "bar"},
|
||||
notificationClass = AttributeChangeNotification.class,
|
||||
description = @Description(
|
||||
value = "description",
|
||||
bundleBaseName = "bundle",
|
||||
key = "key"),
|
||||
descriptorFields = {"foo=bar"})
|
||||
public static class Impl3
|
||||
extends NotificationBroadcasterSupport implements Impl3MXBean {}
|
||||
|
||||
private static Object mbeanImpl3 = new Impl3();
|
||||
|
||||
public static class Impl4 extends ParentImpl implements Impl3MXBean {}
|
||||
|
||||
private static Object mbeanImpl4 = new Impl4();
|
||||
|
||||
@MBean
|
||||
@NotificationInfo(
|
||||
types = {"foo", "bar"},
|
||||
notificationClass = AttributeChangeNotification.class,
|
||||
description = @Description(
|
||||
value = "description",
|
||||
bundleBaseName = "bundle",
|
||||
key = "key"),
|
||||
descriptorFields = {"foo=bar"})
|
||||
public static class MBean1 extends NotificationBroadcasterSupport {}
|
||||
|
||||
private static Object mbeanMBean1 = new MBean1();
|
||||
|
||||
@MBean
|
||||
public static class MBean2 extends ParentImpl {}
|
||||
|
||||
private static Object mbeanMBean2 = new MBean2();
|
||||
|
||||
// Following disabled until we support it
|
||||
// @MBean
|
||||
// @NotificationInfo(
|
||||
// types = {"foo", "bar"},
|
||||
// notificationClass = AttributeChangeNotification.class,
|
||||
// description = @Description(
|
||||
// value = "description",
|
||||
// bundleBaseName = "bundle",
|
||||
// key = "key"),
|
||||
// descriptorFields = {"foo=bar"})
|
||||
// public static class MBean3 {
|
||||
// @Resource
|
||||
// private volatile SendNotification send;
|
||||
// }
|
||||
//
|
||||
// private static Object mbeanMBean3 = new MBean3();
|
||||
|
||||
@MXBean
|
||||
@NotificationInfo(
|
||||
types = {"foo", "bar"},
|
||||
notificationClass = AttributeChangeNotification.class,
|
||||
description = @Description(
|
||||
value = "description",
|
||||
bundleBaseName = "bundle",
|
||||
key = "key"),
|
||||
descriptorFields = {"foo=bar"})
|
||||
public static class MXBean1 extends NotificationBroadcasterSupport {}
|
||||
|
||||
private static Object mbeanMXBean1 = new MXBean1();
|
||||
|
||||
@MXBean
|
||||
public static class MXBean2 extends ParentImpl {}
|
||||
|
||||
private static Object mbeanMXBean2 = new MXBean2();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (!AnnotatedNotificationInfoTest.class.desiredAssertionStatus())
|
||||
throw new Exception("Test must be run with -ea");
|
||||
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
ObjectName on = new ObjectName("a:b=c");
|
||||
|
||||
Descriptor expectedDescriptor = new ImmutableDescriptor(
|
||||
"foo=bar", "descriptionResourceBundleBaseName=bundle",
|
||||
"descriptionResourceKey=key");
|
||||
MBeanNotificationInfo expected = new MBeanNotificationInfo(
|
||||
new String[] {"foo", "bar"},
|
||||
AttributeChangeNotification.class.getName(),
|
||||
"description",
|
||||
expectedDescriptor);
|
||||
|
||||
System.out.println("Testing MBeans...");
|
||||
for (Field mbeanField :
|
||||
AnnotatedNotificationInfoTest.class.getDeclaredFields()) {
|
||||
if (!mbeanField.getName().startsWith("mbean"))
|
||||
continue;
|
||||
System.out.println("..." + mbeanField.getName());
|
||||
Object mbean = mbeanField.get(null);
|
||||
mbs.registerMBean(mbean, on);
|
||||
MBeanInfo mbi = mbs.getMBeanInfo(on);
|
||||
MBeanNotificationInfo[] mbnis = mbi.getNotifications();
|
||||
assert mbnis.length == 1 : mbnis.length;
|
||||
assert mbnis[0].equals(expected) : mbnis[0];
|
||||
mbs.unregisterMBean(on);
|
||||
}
|
||||
}
|
||||
}
|
830
jdk/test/javax/management/Introspector/MBeanDescriptionTest.java
Normal file
830
jdk/test/javax/management/Introspector/MBeanDescriptionTest.java
Normal file
@ -0,0 +1,830 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test %M% %I%
|
||||
* @bug 6323980
|
||||
* @summary Test @Description
|
||||
* @author Eamonn McManus
|
||||
*/
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import javax.management.Description;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanFeatureInfo;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.ManagedAttribute;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.StandardMBean;
|
||||
|
||||
public class MBeanDescriptionTest {
|
||||
private static String failure;
|
||||
private static final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
private static final ObjectName name;
|
||||
static {
|
||||
try {
|
||||
name = new ObjectName("a:b=c");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface Interface {
|
||||
@Description("A description")
|
||||
public String getA();
|
||||
|
||||
@Description("B description")
|
||||
public int getB();
|
||||
public void setB(int x);
|
||||
|
||||
public boolean isC();
|
||||
@Description("C description")
|
||||
public void setC(boolean x);
|
||||
|
||||
@Description("D description")
|
||||
public void setD(float x);
|
||||
|
||||
@Description("H description")
|
||||
public int getH();
|
||||
@Description("H description")
|
||||
public void setH(int x);
|
||||
|
||||
public String getE();
|
||||
|
||||
public int getF();
|
||||
public void setF(int x);
|
||||
|
||||
public void setG(boolean x);
|
||||
|
||||
@Description("opA description")
|
||||
public int opA(
|
||||
@Description("p1 description")
|
||||
int p1,
|
||||
@Description("p2 description")
|
||||
int p2);
|
||||
|
||||
public void opB(float x);
|
||||
}
|
||||
|
||||
@Description("MBean description")
|
||||
public static interface TestMBean extends Interface {}
|
||||
|
||||
public static class Test implements TestMBean {
|
||||
@Description("0-arg constructor description")
|
||||
public Test() {}
|
||||
|
||||
public Test(String why) {}
|
||||
|
||||
@Description("2-arg constructor description")
|
||||
public Test(
|
||||
@Description("p1 description")
|
||||
int x,
|
||||
@Description("p2 description")
|
||||
String y) {
|
||||
}
|
||||
|
||||
public String getA() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getB() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setB(int x) {
|
||||
}
|
||||
|
||||
public boolean isC() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setC(boolean x) {
|
||||
}
|
||||
|
||||
public void setD(float x) {
|
||||
}
|
||||
|
||||
public String getE() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getF() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setF(int x) {
|
||||
}
|
||||
|
||||
public void setG(boolean x) {
|
||||
}
|
||||
|
||||
public int getH() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setH(int x) {
|
||||
}
|
||||
|
||||
public int opA(int p1, int p2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void opB(float x) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestSub extends Test {
|
||||
@Description("0-arg constructor description")
|
||||
public TestSub() {}
|
||||
|
||||
public TestSub(String why) {}
|
||||
|
||||
@Description("2-arg constructor description")
|
||||
public TestSub(
|
||||
@Description("p1 description")
|
||||
int x,
|
||||
@Description("p2 description")
|
||||
String y) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class StandardSub extends StandardMBean implements TestMBean {
|
||||
@Description("0-arg constructor description")
|
||||
public StandardSub() {
|
||||
super(TestMBean.class, false);
|
||||
}
|
||||
|
||||
public StandardSub(String why) {
|
||||
super(TestMBean.class, false);
|
||||
}
|
||||
|
||||
@Description("2-arg constructor description")
|
||||
public StandardSub(
|
||||
@Description("p1 description")
|
||||
int x,
|
||||
@Description("p2 description")
|
||||
String y) {
|
||||
super(TestMBean.class, false);
|
||||
}
|
||||
|
||||
public String getA() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getB() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setB(int x) {
|
||||
}
|
||||
|
||||
public boolean isC() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setC(boolean x) {
|
||||
}
|
||||
|
||||
public void setD(float x) {
|
||||
}
|
||||
|
||||
public String getE() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getF() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setF(int x) {
|
||||
}
|
||||
|
||||
public void setG(boolean x) {
|
||||
}
|
||||
|
||||
public int opA(int p1, int p2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void opB(float x) {
|
||||
}
|
||||
|
||||
public int getH() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setH(int x) {
|
||||
}
|
||||
}
|
||||
|
||||
@Description("MBean description")
|
||||
public static interface TestMXBean extends Interface {}
|
||||
|
||||
public static class TestMXBeanImpl implements TestMXBean {
|
||||
@Description("0-arg constructor description")
|
||||
public TestMXBeanImpl() {}
|
||||
|
||||
public TestMXBeanImpl(String why) {}
|
||||
|
||||
@Description("2-arg constructor description")
|
||||
public TestMXBeanImpl(
|
||||
@Description("p1 description")
|
||||
int x,
|
||||
@Description("p2 description")
|
||||
String y) {
|
||||
}
|
||||
|
||||
public String getA() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getB() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setB(int x) {
|
||||
}
|
||||
|
||||
public boolean isC() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setC(boolean x) {
|
||||
}
|
||||
|
||||
public void setD(float x) {
|
||||
}
|
||||
|
||||
public String getE() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getF() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setF(int x) {
|
||||
}
|
||||
|
||||
public void setG(boolean x) {
|
||||
}
|
||||
|
||||
public int opA(int p1, int p2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void opB(float x) {
|
||||
}
|
||||
|
||||
public int getH() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setH(int x) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class StandardMXSub extends StandardMBean implements TestMXBean {
|
||||
@Description("0-arg constructor description")
|
||||
public StandardMXSub() {
|
||||
super(TestMXBean.class, true);
|
||||
}
|
||||
|
||||
public StandardMXSub(String why) {
|
||||
super(TestMXBean.class, true);
|
||||
}
|
||||
|
||||
@Description("2-arg constructor description")
|
||||
public StandardMXSub(
|
||||
@Description("p1 description")
|
||||
int x,
|
||||
@Description("p2 description")
|
||||
String y) {
|
||||
super(TestMXBean.class, true);
|
||||
}
|
||||
|
||||
public String getA() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getB() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setB(int x) {
|
||||
}
|
||||
|
||||
public boolean isC() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setC(boolean x) {
|
||||
}
|
||||
|
||||
public void setD(float x) {
|
||||
}
|
||||
|
||||
public String getE() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getF() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setF(int x) {
|
||||
}
|
||||
|
||||
public void setG(boolean x) {
|
||||
}
|
||||
|
||||
public int opA(int p1, int p2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void opB(float x) {
|
||||
}
|
||||
|
||||
public int getH() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setH(int x) {
|
||||
}
|
||||
}
|
||||
|
||||
@MBean
|
||||
@Description("MBean description")
|
||||
public static class AnnotatedMBean {
|
||||
@Description("0-arg constructor description")
|
||||
public AnnotatedMBean() {}
|
||||
|
||||
public AnnotatedMBean(String why) {}
|
||||
|
||||
@Description("2-arg constructor description")
|
||||
public AnnotatedMBean(
|
||||
@Description("p1 description")
|
||||
int x,
|
||||
@Description("p2 description")
|
||||
String y) {}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("A description")
|
||||
public String getA() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("B description")
|
||||
public int getB() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public void setB(int x) {
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public boolean isC() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("C description")
|
||||
public void setC(boolean x) {
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("D description")
|
||||
public void setD(float x) {
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public String getE() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public int getF() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public void setF(int x) {
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public void setG(boolean x) {
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("H description")
|
||||
public int getH() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("H description")
|
||||
public void setH(int x) {
|
||||
}
|
||||
|
||||
@ManagedOperation
|
||||
@Description("opA description")
|
||||
public int opA(
|
||||
@Description("p1 description") int p1,
|
||||
@Description("p2 description") int p2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ManagedOperation
|
||||
public void opB(float x) {
|
||||
}
|
||||
}
|
||||
|
||||
@MXBean
|
||||
@Description("MBean description")
|
||||
public static class AnnotatedMXBean {
|
||||
@Description("0-arg constructor description")
|
||||
public AnnotatedMXBean() {}
|
||||
|
||||
public AnnotatedMXBean(String why) {}
|
||||
|
||||
@Description("2-arg constructor description")
|
||||
public AnnotatedMXBean(
|
||||
@Description("p1 description")
|
||||
int x,
|
||||
@Description("p2 description")
|
||||
String y) {}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("A description")
|
||||
public String getA() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("B description")
|
||||
public int getB() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public void setB(int x) {
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public boolean isC() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("C description")
|
||||
public void setC(boolean x) {
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("D description")
|
||||
public void setD(float x) {
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public String getE() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public int getF() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public void setF(int x) {
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
public void setG(boolean x) {
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("H description")
|
||||
public int getH() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ManagedAttribute
|
||||
@Description("H description")
|
||||
public void setH(int x) {
|
||||
}
|
||||
|
||||
@ManagedOperation
|
||||
@Description("opA description")
|
||||
public int opA(
|
||||
@Description("p1 description") int p1,
|
||||
@Description("p2 description") int p2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ManagedOperation
|
||||
public void opB(float x) {
|
||||
}
|
||||
}
|
||||
|
||||
// Negative tests follow.
|
||||
|
||||
// Inconsistent descriptions
|
||||
public static interface BadInterface {
|
||||
@Description("foo")
|
||||
public String getFoo();
|
||||
@Description("bar")
|
||||
public void setFoo(String x);
|
||||
}
|
||||
|
||||
public static interface BadMBean extends BadInterface {}
|
||||
|
||||
public static class Bad implements BadMBean {
|
||||
public String getFoo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setFoo(String x) {
|
||||
}
|
||||
}
|
||||
|
||||
public static interface BadMXBean extends BadInterface {}
|
||||
|
||||
public static class BadMXBeanImpl implements BadMXBean {
|
||||
public String getFoo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setFoo(String x) {
|
||||
}
|
||||
}
|
||||
|
||||
private static interface Defaults {
|
||||
public String defaultAttributeDescription(String name);
|
||||
public String defaultOperationDescription(String name);
|
||||
public String defaultParameterDescription(int index);
|
||||
}
|
||||
|
||||
private static class StandardDefaults implements Defaults {
|
||||
public String defaultAttributeDescription(String name) {
|
||||
return "Attribute exposed for management";
|
||||
}
|
||||
|
||||
public String defaultOperationDescription(String name) {
|
||||
return "Operation exposed for management";
|
||||
}
|
||||
|
||||
public String defaultParameterDescription(int index) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
private static final Defaults standardDefaults = new StandardDefaults();
|
||||
|
||||
private static class MXBeanDefaults implements Defaults {
|
||||
public String defaultAttributeDescription(String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String defaultOperationDescription(String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String defaultParameterDescription(int index) {
|
||||
return "p" + index;
|
||||
}
|
||||
}
|
||||
private static final Defaults mxbeanDefaults = new MXBeanDefaults();
|
||||
|
||||
private static class TestCase {
|
||||
final String name;
|
||||
final Object mbean;
|
||||
final Defaults defaults;
|
||||
TestCase(String name, Object mbean, Defaults defaults) {
|
||||
this.name = name;
|
||||
this.mbean = mbean;
|
||||
this.defaults = defaults;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExceptionTest {
|
||||
final String name;
|
||||
final Object mbean;
|
||||
ExceptionTest(String name, Object mbean) {
|
||||
this.name = name;
|
||||
this.mbean = mbean;
|
||||
}
|
||||
}
|
||||
|
||||
private static final TestCase[] tests = {
|
||||
new TestCase("Standard MBean", new Test(), standardDefaults),
|
||||
new TestCase("Standard MBean subclass", new TestSub(), standardDefaults),
|
||||
new TestCase("StandardMBean delegating",
|
||||
new StandardMBean(new Test(), TestMBean.class, false),
|
||||
standardDefaults),
|
||||
new TestCase("StandardMBean delegating to subclass",
|
||||
new StandardMBean(new TestSub(), TestMBean.class, false),
|
||||
standardDefaults),
|
||||
new TestCase("StandardMBean subclass", new StandardSub(), standardDefaults),
|
||||
|
||||
new TestCase("MXBean", new TestMXBeanImpl(), mxbeanDefaults),
|
||||
new TestCase("StandardMBean MXBean delegating",
|
||||
new StandardMBean(new TestMXBeanImpl(), TestMXBean.class, true),
|
||||
mxbeanDefaults),
|
||||
new TestCase("StandardMBean MXBean subclass",
|
||||
new StandardMXSub(), mxbeanDefaults),
|
||||
|
||||
new TestCase("@MBean", new AnnotatedMBean(), standardDefaults),
|
||||
new TestCase("@MXBean", new AnnotatedMXBean(), mxbeanDefaults),
|
||||
new TestCase("StandardMBean @MBean delegating",
|
||||
new StandardMBean(new AnnotatedMBean(), null, false),
|
||||
standardDefaults),
|
||||
new TestCase("StandardMBean @MXBean delegating",
|
||||
new StandardMBean(new AnnotatedMXBean(), null, true),
|
||||
mxbeanDefaults),
|
||||
};
|
||||
|
||||
private static final ExceptionTest[] exceptionTests = {
|
||||
new ExceptionTest("Standard MBean with inconsistent get/set", new Bad()),
|
||||
new ExceptionTest("MXBean with inconsistent get/set", new BadMXBeanImpl()),
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("=== Testing correct MBeans ===");
|
||||
for (TestCase test : tests) {
|
||||
System.out.println("Testing " + test.name + "...");
|
||||
mbs.registerMBean(test.mbean, name);
|
||||
boolean expectConstructors =
|
||||
(test.mbean.getClass() != StandardMBean.class);
|
||||
check(mbs.getMBeanInfo(name), test.defaults, expectConstructors);
|
||||
mbs.unregisterMBean(name);
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
System.out.println("=== Testing incorrect MBeans ===");
|
||||
for (ExceptionTest test : exceptionTests) {
|
||||
System.out.println("Testing " + test.name);
|
||||
try {
|
||||
mbs.registerMBean(test.mbean, name);
|
||||
fail("Registration succeeded but should not have");
|
||||
mbs.unregisterMBean(name);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
// OK
|
||||
} catch (Exception e) {
|
||||
fail("Registration failed with wrong exception: " +
|
||||
"expected NotCompliantMBeanException, got " +
|
||||
e.getClass().getName());
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
if (failure == null)
|
||||
System.out.println("TEST PASSED");
|
||||
else
|
||||
throw new Exception("TEST FAILED: " + failure);
|
||||
}
|
||||
|
||||
private static void check(
|
||||
MBeanInfo mbi, Defaults defaults, boolean expectConstructors)
|
||||
throws Exception {
|
||||
assertEquals("MBean description", mbi.getDescription());
|
||||
|
||||
// These attributes have descriptions
|
||||
for (String attr : new String[] {"A", "B", "C", "D", "H"}) {
|
||||
MBeanAttributeInfo mbai = getAttributeInfo(mbi, attr);
|
||||
assertEquals(attr + " description", mbai.getDescription());
|
||||
}
|
||||
|
||||
// These attributes don't have descriptions
|
||||
for (String attr : new String[] {"E", "F", "G"}) {
|
||||
// If we ever change the default description, we'll need to change
|
||||
// this test accordingly.
|
||||
MBeanAttributeInfo mbai = getAttributeInfo(mbi, attr);
|
||||
assertEquals(
|
||||
defaults.defaultAttributeDescription(attr), mbai.getDescription());
|
||||
}
|
||||
|
||||
// This operation has a description, as do its parameters
|
||||
MBeanOperationInfo opA = getOperationInfo(mbi, "opA");
|
||||
assertEquals("opA description", opA.getDescription());
|
||||
checkSignature(opA.getSignature());
|
||||
|
||||
// This operation has the default description, as does its parameter
|
||||
MBeanOperationInfo opB = getOperationInfo(mbi, "opB");
|
||||
assertEquals(defaults.defaultOperationDescription("opB"), opB.getDescription());
|
||||
MBeanParameterInfo opB0 = opB.getSignature()[0];
|
||||
assertEquals(defaults.defaultParameterDescription(0), opB0.getDescription());
|
||||
|
||||
if (expectConstructors) {
|
||||
// The 0-arg and 2-arg constructors have descriptions
|
||||
MBeanConstructorInfo con0 = getConstructorInfo(mbi, 0);
|
||||
assertEquals("0-arg constructor description", con0.getDescription());
|
||||
MBeanConstructorInfo con2 = getConstructorInfo(mbi, 2);
|
||||
assertEquals("2-arg constructor description", con2.getDescription());
|
||||
checkSignature(con2.getSignature());
|
||||
|
||||
// The 1-arg constructor does not have a description.
|
||||
// The default description for constructors and their
|
||||
// parameters is the same for all types of MBean.
|
||||
MBeanConstructorInfo con1 = getConstructorInfo(mbi, 1);
|
||||
assertEquals("Public constructor of the MBean", con1.getDescription());
|
||||
assertEquals("", con1.getSignature()[0].getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkSignature(MBeanParameterInfo[] params) {
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
MBeanParameterInfo mbpi = params[i];
|
||||
assertEquals("p" + (i+1) + " description", mbpi.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
private static MBeanAttributeInfo getAttributeInfo(MBeanInfo mbi, String attr)
|
||||
throws Exception {
|
||||
return getFeatureInfo(mbi.getAttributes(), attr);
|
||||
}
|
||||
|
||||
private static MBeanOperationInfo getOperationInfo(MBeanInfo mbi, String op)
|
||||
throws Exception {
|
||||
return getFeatureInfo(mbi.getOperations(), op);
|
||||
}
|
||||
|
||||
private static MBeanConstructorInfo getConstructorInfo(MBeanInfo mbi, int nparams)
|
||||
throws Exception {
|
||||
for (MBeanConstructorInfo mbci : mbi.getConstructors()) {
|
||||
if (mbci.getSignature().length == nparams)
|
||||
return mbci;
|
||||
}
|
||||
throw new Exception("Constructor not found: " + nparams);
|
||||
}
|
||||
|
||||
private static <T extends MBeanFeatureInfo> T getFeatureInfo(
|
||||
T[] features, String name) throws Exception {
|
||||
for (T feature : features) {
|
||||
if (feature.getName().equals(name))
|
||||
return feature;
|
||||
}
|
||||
throw new Exception("Feature not found: " + name);
|
||||
}
|
||||
|
||||
private static void assertEquals(Object expected, Object actual) {
|
||||
if (!expected.equals(actual))
|
||||
fail("Expected " + string(expected) + ", got " + string(actual));
|
||||
}
|
||||
|
||||
private static String string(Object x) {
|
||||
if (x instanceof String)
|
||||
return quote((String) x);
|
||||
else
|
||||
return String.valueOf(x);
|
||||
}
|
||||
|
||||
private static String quote(String s) {
|
||||
return '"' + s.replace("\\", "\\\\").replace("\"", "\\\"") + '"';
|
||||
}
|
||||
|
||||
private static void fail(String why) {
|
||||
StackTraceElement[] stack = new Throwable().getStackTrace();
|
||||
int n = 0;
|
||||
for (StackTraceElement elmt : stack) {
|
||||
String method = elmt.getMethodName();
|
||||
if (method.equals("fail") || method.equals("assertEquals") ||
|
||||
method.equals("checkSignature"))
|
||||
continue;
|
||||
n = elmt.getLineNumber();
|
||||
break;
|
||||
}
|
||||
System.out.println("FAILED: " + why + " (line " + n + ")");
|
||||
failure = why;
|
||||
}
|
||||
}
|
116
jdk/test/javax/management/Introspector/ParameterNameTest.java
Normal file
116
jdk/test/javax/management/Introspector/ParameterNameTest.java
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test %M% %I%
|
||||
* @bug 6323980
|
||||
* @summary Test that parameter names can be specified with @Name.
|
||||
* @author Eamonn McManus
|
||||
*/
|
||||
|
||||
import javax.management.MBean;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import annot.Name;
|
||||
import javax.management.ManagedOperation;
|
||||
|
||||
public class ParameterNameTest {
|
||||
public static interface NoddyMBean {
|
||||
public int add(int x, @Name("y") int y);
|
||||
}
|
||||
|
||||
public static class Noddy implements NoddyMBean {
|
||||
public int add(int x, int y) {
|
||||
return x + y;
|
||||
}
|
||||
}
|
||||
|
||||
public static interface NoddyMXBean {
|
||||
public int add(int x, @Name("y") int y);
|
||||
}
|
||||
|
||||
public static class NoddyImpl implements NoddyMXBean {
|
||||
public int add(int x, int y) {
|
||||
return x + y;
|
||||
}
|
||||
}
|
||||
|
||||
@MBean
|
||||
public static class NoddyAnnot {
|
||||
@ManagedOperation
|
||||
public int add(int x, @Name("y") int y) {
|
||||
return x + y;
|
||||
}
|
||||
}
|
||||
|
||||
@MXBean
|
||||
public static class NoddyAnnotMX {
|
||||
@ManagedOperation
|
||||
public int add(int x, @Name("y") int y) {
|
||||
return x + y;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Object[] mbeans = {
|
||||
new Noddy(), new NoddyImpl(), new NoddyAnnot(), new NoddyAnnotMX(),
|
||||
};
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
MBeanServer mbs = MBeanServerFactory.newMBeanServer();
|
||||
ObjectName name = new ObjectName("a:b=c");
|
||||
for (Object mbean : mbeans) {
|
||||
System.out.println("Testing " + mbean.getClass().getName());
|
||||
mbs.registerMBean(mbean, name);
|
||||
MBeanInfo mbi = mbs.getMBeanInfo(name);
|
||||
MBeanOperationInfo[] mbois = mbi.getOperations();
|
||||
assertEquals(1, mbois.length);
|
||||
MBeanParameterInfo[] mbpis = mbois[0].getSignature();
|
||||
assertEquals(2, mbpis.length);
|
||||
boolean mx = Boolean.parseBoolean(
|
||||
(String) mbi.getDescriptor().getFieldValue("mxbean"));
|
||||
assertEquals(mx ? "p0" : "p1", mbpis[0].getName());
|
||||
assertEquals("y", mbpis[1].getName());
|
||||
mbs.unregisterMBean(name);
|
||||
}
|
||||
System.out.println("TEST PASSED");
|
||||
}
|
||||
|
||||
private static void assertEquals(Object expect, Object actual)
|
||||
throws Exception {
|
||||
boolean eq;
|
||||
if (expect == null)
|
||||
eq = (actual == null);
|
||||
else
|
||||
eq = expect.equals(actual);
|
||||
if (!eq) {
|
||||
throw new Exception(
|
||||
"TEST FAILED: expected " + expect + ", found " + actual);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,656 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test %M% %I%
|
||||
* @bug 6323980
|
||||
* @summary Test resource injection via @Resource
|
||||
* @author Eamonn McManus
|
||||
* @run main/othervm -ea ResourceInjectionTest
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import javax.annotation.Resource;
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ManagedAttribute;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.SendNotification;
|
||||
import javax.management.StandardEmitterMBean;
|
||||
import javax.management.StandardMBean;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
public class ResourceInjectionTest {
|
||||
private static MBeanServer mbs;
|
||||
private static final ObjectName objectName;
|
||||
static {
|
||||
try {
|
||||
objectName = new ObjectName("test:type=Test");
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is somewhat nasty. In the current state of affairs, a
|
||||
* StandardEmitterMBean can only get the
|
||||
* MBeanServer to rewrite the source of a Notification from
|
||||
* the originating object's reference to its ObjectName IF
|
||||
* StandardEmitterMBean.getResource() returns a reference to the
|
||||
* wrapped object. By default it doesn't, and you need to specify
|
||||
* the option below to make it do so. We may hope that this is
|
||||
* obscure enough for users to run into it rarely if ever.
|
||||
*/
|
||||
private static final StandardMBean.Options withWrappedVisible;
|
||||
private static final StandardMBean.Options withWrappedVisibleMX;
|
||||
static {
|
||||
withWrappedVisible = new StandardMBean.Options();
|
||||
withWrappedVisible.setWrappedObjectVisible(true);
|
||||
withWrappedVisibleMX = withWrappedVisible.clone();
|
||||
withWrappedVisibleMX.setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private static @interface ExpectException {
|
||||
Class<? extends Exception> value();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (!ResourceInjectionTest.class.desiredAssertionStatus())
|
||||
throw new Exception("Test must be run with -ea");
|
||||
|
||||
File policyFile = File.createTempFile("jmxperms", ".policy");
|
||||
policyFile.deleteOnExit();
|
||||
PrintWriter pw = new PrintWriter(policyFile);
|
||||
pw.println("grant {");
|
||||
pw.println(" permission javax.management.MBeanPermission \"*\", \"*\";");
|
||||
pw.println(" permission javax.management.MBeanServerPermission \"*\";");
|
||||
pw.println(" permission javax.management.MBeanTrustPermission \"*\";");
|
||||
pw.println("};");
|
||||
pw.close();
|
||||
|
||||
System.setProperty("java.security.policy", policyFile.getAbsolutePath());
|
||||
System.setSecurityManager(new SecurityManager());
|
||||
|
||||
String failure = null;
|
||||
|
||||
for (Method m : ResourceInjectionTest.class.getDeclaredMethods()) {
|
||||
if (Modifier.isStatic(m.getModifiers()) &&
|
||||
m.getName().startsWith("test") &&
|
||||
m.getParameterTypes().length == 0) {
|
||||
ExpectException expexc = m.getAnnotation(ExpectException.class);
|
||||
mbs = MBeanServerFactory.newMBeanServer();
|
||||
try {
|
||||
m.invoke(null);
|
||||
if (expexc != null) {
|
||||
failure =
|
||||
m.getName() + " did not got expected exception " +
|
||||
expexc.value().getName();
|
||||
System.out.println(failure);
|
||||
} else
|
||||
System.out.println(m.getName() + " OK");
|
||||
} catch (InvocationTargetException ite) {
|
||||
Throwable t = ite.getCause();
|
||||
String prob = null;
|
||||
if (expexc != null) {
|
||||
if (expexc.value().isInstance(t)) {
|
||||
System.out.println(m.getName() + " OK (got expected " +
|
||||
expexc.value().getName() + ")");
|
||||
} else
|
||||
prob = "got wrong exception";
|
||||
} else
|
||||
prob = "got exception";
|
||||
if (prob != null) {
|
||||
failure = m.getName() + ": " + prob + " " +
|
||||
t.getClass().getName();
|
||||
System.out.println(failure);
|
||||
t.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (failure == null)
|
||||
System.out.println("TEST PASSED");
|
||||
else
|
||||
throw new Exception("TEST FAILED: " + failure);
|
||||
}
|
||||
|
||||
private static interface Send {
|
||||
public void send();
|
||||
}
|
||||
|
||||
// Test @Resource in MBean defined by annotations
|
||||
|
||||
@MBean
|
||||
public static class Annotated {
|
||||
@Resource
|
||||
private volatile MBeanServer mbeanServer;
|
||||
@Resource
|
||||
private volatile ObjectName myName;
|
||||
|
||||
@ManagedAttribute
|
||||
public ObjectName getMyName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@ManagedOperation
|
||||
public void unregisterSelf()
|
||||
throws InstanceNotFoundException, MBeanRegistrationException {
|
||||
mbeanServer.unregisterMBean(myName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testAnnotated() throws Exception {
|
||||
testMBean(new Annotated());
|
||||
}
|
||||
|
||||
private static void testAnnotatedWrapped() throws Exception {
|
||||
testMBean(new StandardMBean(new Annotated(), null));
|
||||
}
|
||||
|
||||
@MBean
|
||||
public static class AnnotatedSend extends Annotated implements Send {
|
||||
@Resource
|
||||
private volatile SendNotification sender;
|
||||
|
||||
@ManagedOperation
|
||||
public void send() {
|
||||
sender.sendNotification(new Notification("type", this, 0L));
|
||||
}
|
||||
}
|
||||
|
||||
private static void testAnnotatedSend() throws Exception {
|
||||
testMBean(new AnnotatedSend());
|
||||
}
|
||||
|
||||
private static void testAnnotatedSendWrapped() throws Exception {
|
||||
testMBean(new StandardEmitterMBean(
|
||||
new AnnotatedSend(), null, withWrappedVisible, null));
|
||||
}
|
||||
|
||||
// Test @Resource in MXBean defined by annotations
|
||||
|
||||
@MXBean
|
||||
public static class AnnotatedMX {
|
||||
@Resource
|
||||
private volatile MBeanServer mbeanServer;
|
||||
@Resource
|
||||
private volatile ObjectName myName;
|
||||
|
||||
@ManagedAttribute
|
||||
public ObjectName getMyName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@ManagedOperation
|
||||
public void unregisterSelf()
|
||||
throws InstanceNotFoundException, MBeanRegistrationException {
|
||||
mbeanServer.unregisterMBean(myName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testAnnotatedMX() throws Exception {
|
||||
testMBean(new AnnotatedMX());
|
||||
}
|
||||
|
||||
private static void testAnnotatedMXWrapped() throws Exception {
|
||||
testMBean(new StandardMBean(new AnnotatedMX(), null, true));
|
||||
}
|
||||
|
||||
public static class AnnotatedMXSend extends AnnotatedMX implements Send {
|
||||
@Resource
|
||||
private volatile SendNotification sender;
|
||||
|
||||
@ManagedOperation
|
||||
public void send() {
|
||||
sender.sendNotification(new Notification("type", this, 0L));
|
||||
}
|
||||
}
|
||||
|
||||
private static void testAnnotatedMXSend() throws Exception {
|
||||
testMBean(new AnnotatedMXSend());
|
||||
}
|
||||
|
||||
private static void testAnnotatedMXSendWrapped() throws Exception {
|
||||
testMBean(new StandardEmitterMBean(
|
||||
new AnnotatedMXSend(), null, withWrappedVisibleMX, null));
|
||||
}
|
||||
|
||||
// Test @Resource in Standard MBean
|
||||
|
||||
public static interface SimpleStandardMBean {
|
||||
public ObjectName getMyName();
|
||||
public void unregisterSelf() throws Exception;
|
||||
}
|
||||
|
||||
public static class SimpleStandard implements SimpleStandardMBean {
|
||||
@Resource(type = MBeanServer.class)
|
||||
private volatile Object mbeanServer;
|
||||
@Resource(type = ObjectName.class)
|
||||
private volatile Object myName;
|
||||
|
||||
public ObjectName getMyName() {
|
||||
return (ObjectName) myName;
|
||||
}
|
||||
|
||||
public void unregisterSelf() throws Exception {
|
||||
((MBeanServer) mbeanServer).unregisterMBean(getMyName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void testStandard() throws Exception {
|
||||
testMBean(new SimpleStandard());
|
||||
}
|
||||
|
||||
private static void testStandardWrapped() throws Exception {
|
||||
testMBean(new StandardMBean(new SimpleStandard(), SimpleStandardMBean.class));
|
||||
}
|
||||
|
||||
public static interface SimpleStandardSendMBean extends SimpleStandardMBean {
|
||||
public void send();
|
||||
}
|
||||
|
||||
public static class SimpleStandardSend
|
||||
extends SimpleStandard implements SimpleStandardSendMBean {
|
||||
@Resource(type = SendNotification.class)
|
||||
private volatile Object sender;
|
||||
|
||||
public void send() {
|
||||
((SendNotification) sender).sendNotification(
|
||||
new Notification("type", this, 0L));
|
||||
}
|
||||
}
|
||||
|
||||
private static void testStandardSend() throws Exception {
|
||||
testMBean(new SimpleStandardSend());
|
||||
}
|
||||
|
||||
private static void testStandardSendWrapped() throws Exception {
|
||||
testMBean(new StandardEmitterMBean(
|
||||
new SimpleStandardSend(), SimpleStandardSendMBean.class,
|
||||
withWrappedVisible, null));
|
||||
}
|
||||
|
||||
// Test @Resource in MXBean
|
||||
|
||||
public static interface SimpleMXBean {
|
||||
public ObjectName getMyName();
|
||||
public void unregisterSelf() throws Exception;
|
||||
}
|
||||
|
||||
public static class SimpleMX implements SimpleMXBean {
|
||||
@Resource(type = MBeanServer.class)
|
||||
private volatile Object mbeanServer;
|
||||
@Resource(type = ObjectName.class)
|
||||
private volatile Object myName;
|
||||
|
||||
public ObjectName getMyName() {
|
||||
return (ObjectName) myName;
|
||||
}
|
||||
|
||||
public void unregisterSelf() throws Exception {
|
||||
((MBeanServer) mbeanServer).unregisterMBean(getMyName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void testMX() throws Exception {
|
||||
testMBean(new SimpleMX());
|
||||
}
|
||||
|
||||
private static void testMXWrapped() throws Exception {
|
||||
testMBean(new StandardMBean(new SimpleMX(), SimpleMXBean.class, true));
|
||||
}
|
||||
|
||||
public static interface SimpleMXBeanSend extends SimpleMXBean {
|
||||
public void send();
|
||||
}
|
||||
|
||||
public MBeanServer getMbs() {
|
||||
return mbs;
|
||||
}
|
||||
|
||||
public static class SimpleMXSend extends SimpleMX implements SimpleMXBeanSend {
|
||||
@Resource(type = SendNotification.class)
|
||||
private volatile Object sender;
|
||||
|
||||
public void send() {
|
||||
((SendNotification) sender).sendNotification(
|
||||
new Notification("type", this, 0L));
|
||||
}
|
||||
}
|
||||
|
||||
private static void testMXSend() throws Exception {
|
||||
testMBean(new SimpleMXSend());
|
||||
}
|
||||
|
||||
private static void testMXSendWrapped() throws Exception {
|
||||
testMBean(new StandardEmitterMBean(
|
||||
new SimpleMXSend(), SimpleMXBeanSend.class,
|
||||
withWrappedVisibleMX, null));
|
||||
}
|
||||
|
||||
// Test @Resource in Dynamic MBean
|
||||
|
||||
private static class SimpleDynamic implements DynamicMBean {
|
||||
private MBeanServer mbeanServer;
|
||||
private ObjectName myName;
|
||||
|
||||
@Resource
|
||||
private synchronized void setMBeanServer(MBeanServer mbs) {
|
||||
mbeanServer = mbs;
|
||||
}
|
||||
|
||||
@Resource(type = ObjectName.class)
|
||||
private synchronized void setObjectName(Serializable name) {
|
||||
myName = (ObjectName) name;
|
||||
}
|
||||
|
||||
public synchronized Object getAttribute(String attribute)
|
||||
throws AttributeNotFoundException {
|
||||
if (attribute.equals("MyName"))
|
||||
return myName;
|
||||
throw new AttributeNotFoundException(attribute);
|
||||
}
|
||||
|
||||
public void setAttribute(Attribute attribute)
|
||||
throws AttributeNotFoundException {
|
||||
throw new AttributeNotFoundException(attribute.getName());
|
||||
}
|
||||
|
||||
public synchronized AttributeList getAttributes(String[] attributes) {
|
||||
AttributeList list = new AttributeList();
|
||||
for (String name : attributes) {
|
||||
if (name.equals("MyName"))
|
||||
list.add(new Attribute("MyName", myName));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public AttributeList setAttributes(AttributeList attributes) {
|
||||
return new AttributeList();
|
||||
}
|
||||
|
||||
public synchronized Object invoke(
|
||||
String actionName, Object[] params, String[] signature)
|
||||
throws MBeanException, ReflectionException {
|
||||
if (actionName.equals("unregisterSelf") &&
|
||||
(params == null || params.length == 0) &&
|
||||
(signature == null || signature.length == 0)) {
|
||||
try {
|
||||
mbeanServer.unregisterMBean(myName);
|
||||
return null;
|
||||
} catch (Exception x) {
|
||||
throw new MBeanException(x);
|
||||
}
|
||||
} else {
|
||||
Exception x = new NoSuchMethodException(
|
||||
actionName + Arrays.toString(signature));
|
||||
throw new MBeanException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public MBeanInfo getMBeanInfo() {
|
||||
DynamicMBean mbean = new StandardMBean(
|
||||
new SimpleStandard(), SimpleStandardMBean.class, false);
|
||||
return mbean.getMBeanInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private static void testDynamic() throws Exception {
|
||||
testMBean(new SimpleDynamic());
|
||||
}
|
||||
|
||||
private static class SimpleDynamicSend extends SimpleDynamic {
|
||||
private SendNotification sender;
|
||||
|
||||
@Resource
|
||||
private synchronized void setSender(SendNotification sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Object invoke(
|
||||
String actionName, Object[] params, String[] signature)
|
||||
throws MBeanException, ReflectionException {
|
||||
if (actionName.equals("send")) {
|
||||
sender.sendNotification(new Notification("type", this, 0L));
|
||||
return null;
|
||||
} else
|
||||
return super.invoke(actionName, params, signature);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testDynamicSend() throws Exception {
|
||||
testMBean(new SimpleDynamicSend());
|
||||
}
|
||||
|
||||
// Test that @Resource classes don't have to be public
|
||||
// They can even be defined within methods!
|
||||
// But you can't have any @ManagedAttributes or @ManagedOperations
|
||||
// in such MBeans so their utility is limited.
|
||||
|
||||
private static void testNonPublic() throws Exception {
|
||||
@MBean
|
||||
class NonPublic {
|
||||
@Resource
|
||||
ObjectName myName;
|
||||
}
|
||||
assert !Modifier.isPublic(NonPublic.class.getModifiers());
|
||||
NonPublic mbean = new NonPublic();
|
||||
mbs.registerMBean(mbean, objectName);
|
||||
assert objectName.equals(mbean.myName);
|
||||
}
|
||||
|
||||
// Test inheritance and multiple injections of the same value
|
||||
|
||||
private static class ManyResources extends AnnotatedSend {
|
||||
@Resource
|
||||
private volatile ObjectName myName; // same name as in parent!
|
||||
@Resource(type=ObjectName.class)
|
||||
private volatile Object myOtherName;
|
||||
private volatile ObjectName myThirdName;
|
||||
private volatile ObjectName myFourthName;
|
||||
private volatile int methodCalls;
|
||||
@Resource
|
||||
private volatile SendNotification send1;
|
||||
@Resource(type = SendNotification.class)
|
||||
private volatile Object send2;
|
||||
|
||||
@Resource
|
||||
void setMyName(ObjectName name) {
|
||||
myThirdName = name;
|
||||
methodCalls++;
|
||||
}
|
||||
|
||||
@Resource(type=ObjectName.class)
|
||||
private void setMyNameAgain(ObjectName name) {
|
||||
myFourthName = name;
|
||||
methodCalls++;
|
||||
}
|
||||
|
||||
void check() {
|
||||
assert objectName.equals(myName) : myName;
|
||||
for (ObjectName name : new ObjectName[] {
|
||||
(ObjectName)myOtherName, myThirdName, myFourthName
|
||||
}) {
|
||||
assert myName == name : name;
|
||||
}
|
||||
assert methodCalls == 2 : methodCalls;
|
||||
assert send1 != null && send2 == send1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void testManyResources() throws Exception {
|
||||
ManyResources mr = new ManyResources();
|
||||
testMBean(mr);
|
||||
mr.check();
|
||||
}
|
||||
|
||||
// Test that method override doesn't lead to multiple calls of the same method
|
||||
|
||||
private static class ManyResourcesSub extends ManyResources {
|
||||
private boolean called;
|
||||
|
||||
@Override
|
||||
@Resource
|
||||
void setMyName(ObjectName name) {
|
||||
super.setMyName(name);
|
||||
called = true;
|
||||
}
|
||||
|
||||
void check2() {
|
||||
assert called;
|
||||
}
|
||||
}
|
||||
|
||||
private static void testOverride() throws Exception {
|
||||
ManyResourcesSub mrs = new ManyResourcesSub();
|
||||
testMBean(mrs);
|
||||
mrs.check();
|
||||
mrs.check2();
|
||||
}
|
||||
|
||||
// Test that @Resource is illegal on static fields
|
||||
|
||||
@MBean
|
||||
public static class StaticResource {
|
||||
@Resource
|
||||
private static ObjectName name;
|
||||
}
|
||||
|
||||
@ExpectException(NotCompliantMBeanException.class)
|
||||
private static void testStaticResource() throws Exception {
|
||||
testMBean(new StaticResource());
|
||||
}
|
||||
|
||||
// Test that @Resource is illegal on static methods
|
||||
|
||||
@MBean
|
||||
public static class StaticResourceMethod {
|
||||
@Resource
|
||||
private static void setObjectName(ObjectName name) {}
|
||||
}
|
||||
|
||||
@ExpectException(NotCompliantMBeanException.class)
|
||||
private static void testStaticResourceMethod() throws Exception {
|
||||
testMBean(new StaticResourceMethod());
|
||||
}
|
||||
|
||||
// Test that @Resource is illegal on methods that don't return void
|
||||
|
||||
@MBean
|
||||
public static class NonVoidMethod {
|
||||
@Resource
|
||||
private String setObjectName(ObjectName name) {
|
||||
return "oops";
|
||||
}
|
||||
}
|
||||
|
||||
@ExpectException(NotCompliantMBeanException.class)
|
||||
private static void testNonVoidMethod() throws Exception {
|
||||
testMBean(new NonVoidMethod());
|
||||
}
|
||||
|
||||
// Test that @Resource is illegal on methods with no arguments
|
||||
|
||||
@MBean
|
||||
public static class NoArgMethod {
|
||||
@Resource(type=ObjectName.class)
|
||||
private void setObjectName() {}
|
||||
}
|
||||
|
||||
@ExpectException(NotCompliantMBeanException.class)
|
||||
private static void testNoArgMethod() throws Exception {
|
||||
testMBean(new NoArgMethod());
|
||||
}
|
||||
|
||||
// Test that @Resource is illegal on methods with more than one argument
|
||||
|
||||
@MBean
|
||||
public static class MultiArgMethod {
|
||||
@Resource
|
||||
private void setObjectName(ObjectName name, String what) {}
|
||||
}
|
||||
|
||||
@ExpectException(NotCompliantMBeanException.class)
|
||||
private static void testMultiArgMethod() throws Exception {
|
||||
testMBean(new MultiArgMethod());
|
||||
}
|
||||
|
||||
private static class CountListener implements NotificationListener {
|
||||
volatile int count;
|
||||
public void handleNotification(Notification notification, Object handback) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
private static void testMBean(Object mbean) throws Exception {
|
||||
mbs.registerMBean(mbean, objectName);
|
||||
|
||||
final ObjectName name = (ObjectName) mbs.getAttribute(objectName, "MyName");
|
||||
assert objectName.equals(name) : name;
|
||||
|
||||
if (mbean instanceof Send || mbean instanceof NotificationEmitter) {
|
||||
assert mbs.isInstanceOf(name, NotificationEmitter.class.getName());
|
||||
CountListener countL = new CountListener();
|
||||
mbs.addNotificationListener(name, countL, null, null);
|
||||
NotificationListener checkSource = new NotificationListener() {
|
||||
public void handleNotification(Notification n, Object h) {
|
||||
assert n.getSource().equals(name) : n.getSource();
|
||||
}
|
||||
};
|
||||
mbs.addNotificationListener(name, checkSource, null, null);
|
||||
mbs.invoke(objectName, "send", null, null);
|
||||
assert countL.count == 1;
|
||||
mbs.removeNotificationListener(name, checkSource);
|
||||
mbs.removeNotificationListener(name, countL, null, null);
|
||||
}
|
||||
|
||||
mbs.invoke(objectName, "unregisterSelf", null, null);
|
||||
assert !mbs.isRegistered(objectName);
|
||||
}
|
||||
}
|
32
jdk/test/javax/management/Introspector/annot/Name.java
Normal file
32
jdk/test/javax/management/Introspector/annot/Name.java
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. 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.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package annot;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Name {
|
||||
String value();
|
||||
}
|
Loading…
Reference in New Issue
Block a user