提交 0a690d3a 编写于 作者: T tbell

Merge

......@@ -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);
......
/*
* 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
......
/*
* 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) {
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
}
Method getter, Method setter) throws IntrospectionException {
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;
}
......
/*
* 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>
*
......
/*
* 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>&#64;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>&#64;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 &#64;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>&#64;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>&#64;DescriptorFields</code> is more convenient but includes
* those risks. <code>&#64;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>&#64;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 &#64;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>
* &#64;Documented
* &#64;Target(ElementType.METHOD)
* &#64;Retention(RetentionPolicy.RUNTIME)
* public &#64;interface Units {
* &#64;DescriptorKey("units")
* String value();
*
* <b>&#64;DescriptorKey(value = "descriptionResourceKey",
* omitIfDefault = true)</b>
* String resourceKey() default "";
*
* <b>&#64;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;
}
/*
* 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();
}
/*
* 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));
}
}
/*
* 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 &#64;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>&#64;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 {
* &#64;Resource
* private volatile MBeanServer mbeanServer;
* &#64;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 {
* &#64;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>&#64;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>&#64;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>&#64;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>&#64;Resource</code> annotation. For example:</p>
*
* <pre>
* &#64;Resource(type = MBeanServer.class)
* private volatile MBeanServerConnection mbsc;
* </pre>
*
* <p>Formally, suppose <em>R</em> is the type in the <code>&#64;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>&#64;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>&#64;{@link
ManagedAttribute}</code> or <code>&#64;{@link ManagedOperation}</code>
annotations, as described for <code>&#64;{@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.
......
/*
* 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 {
}
/*
* 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
......
/*
* 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 {};
}
/*
* 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
* &#64;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();
}
/*
* 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
......
/*
* 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 &#64;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);
}
}
}
/*
* 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();
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册