--- a/jdk/.hgtags Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/.hgtags Tue Dec 09 17:41:59 2008 +0100
@@ -15,3 +15,4 @@
cc5f810b5af8a3a83b0df5a29d9e24d7a0ff8086 jdk7-b38
4e51997582effa006dde5c6d8b8820b2045b9c7f jdk7-b39
2201dad60231a3c3e0346e3a0250d69ca3b71fd4 jdk7-b40
+44941f893cea95ecdd5987b12e548069bd803849 jdk7-b41
--- a/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Tue Dec 09 17:41:59 2008 +0100
@@ -919,6 +919,12 @@
DynamicMBean mbean = Introspector.makeDynamicMBean(object);
+ //Access the ObjectName template value only if the provided name is null
+ if(name == null) {
+ name = Introspector.templateToObjectName(mbean.getMBeanInfo().
+ getDescriptor(), mbean);
+ }
+
return registerDynamicMBean(classname, mbean, name);
}
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java Tue Dec 09 17:41:59 2008 +0100
@@ -53,7 +53,7 @@
}
Descriptor getDescriptor() {
- return Introspector.descriptorForElement(method);
+ return Introspector.descriptorForElement(method, false);
}
Type getGenericReturnType() {
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java Tue Dec 09 17:41:59 2008 +0100
@@ -63,7 +63,14 @@
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.management.AttributeNotFoundException;
+import javax.management.JMX;
+import javax.management.ObjectName;
+import javax.management.ObjectNameTemplate;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.MXBeanMappingFactory;
@@ -75,7 +82,13 @@
*/
public class Introspector {
-
+ /**
+ * Pattern used to extract Attribute Names from ObjectNameTemplate Annotation
+ * For example, in the following example, the Name attribute value is
+ * retrieved : ":type=MyType, name={Name}"
+ */
+ private static Pattern OBJECT_NAME_PATTERN_TEMPLATE =
+ Pattern.compile("(\\{[^\\}]+\\})|(=\"\\{[^\\}]+\\}\")");
/*
* ------------------------------------------
* PRIVATE CONSTRUCTORS
@@ -389,6 +402,42 @@
return getStandardMBeanInterface(baseClass);
}
+ public static ObjectName templateToObjectName(Descriptor descriptor,
+ DynamicMBean mbean)
+ throws NotCompliantMBeanException {
+ String template = (String)
+ descriptor.getFieldValue(JMX.OBJECT_NAME_TEMPLATE);
+ if(template == null) return null;
+ try {
+ Matcher m = OBJECT_NAME_PATTERN_TEMPLATE.matcher(template);
+ while (m.find()){
+ String grp = m.group();
+ System.out.println("GROUP " + grp);
+ String attributeName = null;
+ boolean quote = false;
+ if(grp.startsWith("=\"{")) {
+ attributeName = grp.substring(3, grp.length() - 2);
+ quote = true;
+ } else
+ attributeName = grp.substring(1, grp.length() - 1);
+
+ Object attributeValue = mbean.getAttribute(attributeName);
+ String validValue = quote ?
+ "=" + ObjectName.quote(attributeValue.toString()) :
+ attributeValue.toString();
+ template = template.replace(grp, validValue);
+ }
+ return new ObjectName(template);
+ }catch(Exception ex) {
+ NotCompliantMBeanException ncex = new
+ NotCompliantMBeanException(ObjectNameTemplate.class.
+ getSimpleName() + " annotation value [" + template + "] " +
+ "is invalid. " + ex);
+ ncex.initCause(ex);
+ throw ncex;
+ }
+ }
+
/*
* ------------------------------------------
* PRIVATE METHODS
@@ -462,11 +511,31 @@
return null;
}
- public static Descriptor descriptorForElement(final AnnotatedElement elmt) {
+ public static Descriptor descriptorForElement(final AnnotatedElement elmt,
+ boolean isSetter) {
if (elmt == null)
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
final Annotation[] annots = elmt.getAnnotations();
- return descriptorForAnnotations(annots);
+ Descriptor descr = descriptorForAnnotations(annots);
+ String[] exceptions = {};
+ if(elmt instanceof Method)
+ exceptions = getAllExceptions(((Method) elmt).getExceptionTypes());
+ else
+ if(elmt instanceof Constructor<?>)
+ exceptions = getAllExceptions(((Constructor<?>) elmt).
+ getExceptionTypes());
+
+ if(exceptions.length > 0 ) {
+ String fieldName = isSetter ? JMX.SET_EXCEPTIONS_FIELD :
+ JMX.EXCEPTIONS_FIELD;
+
+ String[] fieldNames = {fieldName};
+ Object[] fieldValues = {exceptions};
+ descr = ImmutableDescriptor.union(descr,
+ new ImmutableDescriptor(fieldNames, fieldValues));
+ }
+
+ return descr;
}
public static Descriptor descriptorForAnnotation(Annotation annot) {
@@ -489,6 +558,20 @@
return new ImmutableDescriptor(descriptorMap);
}
+ /**
+ * Array of thrown excepions.
+ * @param exceptions can be null;
+ * @return An Array of Exception class names. Size is 0 if method is null.
+ */
+ private static String[] getAllExceptions(Class<?>[] exceptions) {
+ Set<String> set = new LinkedHashSet<String>();
+ for(Class<?>ex : exceptions)
+ set.add(ex.getName());
+
+ String[] arr = new String[set.size()];
+ return set.toArray(arr);
+ }
+
private static void addDescriptorFieldsToMap(
Map<String, Object> descriptorMap, DescriptorFields df) {
for (String field : df.value()) {
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java Tue Dec 09 17:41:59 2008 +0100
@@ -47,6 +47,10 @@
import javax.management.SendNotification;
public class MBeanInjector {
+ // There are no instances of this class
+ private MBeanInjector() {
+ }
+
private static Class<?>[] injectedClasses = {
MBeanServer.class, ObjectName.class, SendNotification.class,
};
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java Tue Dec 09 17:41:59 2008 +0100
@@ -614,6 +614,15 @@
}
/**
+ * Returns the class of a primitive type.
+ * @param name The type for which we the associated class.
+ * @return the class, or null if name is not primitive.
+ */
+ public static Class<?> primitiveType(String name) {
+ return primitiveClasses.get(name);
+ }
+
+ /**
* Load a class with the specified loader, or with this object
* class loader if the specified loader is null.
**/
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java Tue Dec 09 17:41:59 2008 +0100
@@ -44,7 +44,6 @@
import javax.management.ImmutableDescriptor;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
-import javax.management.JMX;
import javax.management.MBean;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
@@ -404,7 +403,7 @@
new ImmutableDescriptor(interfaceClassName);
final Descriptor mbeanDescriptor = getBasicMBeanDescriptor();
final Descriptor annotatedDescriptor =
- Introspector.descriptorForElement(mbeanInterface);
+ Introspector.descriptorForElement(mbeanInterface, false);
final Descriptor descriptor =
DescriptorCache.getInstance().union(
classNameDescriptor,
@@ -519,7 +518,7 @@
* 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)
+ public static void getAnnotatedMethods(Class<?> c, List<Method> methods)
throws Exception {
Class<?> sup = c.getSuperclass();
if (sup != null)
@@ -538,6 +537,14 @@
}
}
+ /*
+ * Return the array of MBeanNotificationInfo for the given MBean object.
+ * If the object implements NotificationBroadcaster and its
+ * getNotificationInfo() method returns a non-empty array, then that
+ * is the result. Otherwise, if the object has a @NotificationInfo
+ * or @NotificationInfos annotation, then its contents form the result.
+ * Otherwise, the result is null.
+ */
static MBeanNotificationInfo[] findNotifications(Object moi) {
if (moi instanceof NotificationBroadcaster) {
MBeanNotificationInfo[] mbn =
@@ -553,6 +560,13 @@
}
return result;
}
+ } else {
+ try {
+ if (!MBeanInjector.injectsSendNotification(moi))
+ return null;
+ } catch (NotCompliantMBeanException e) {
+ throw new RuntimeException(e);
+ }
}
return findNotificationsFromAnnotations(moi.getClass());
}
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java Tue Dec 09 17:41:59 2008 +0100
@@ -292,7 +292,7 @@
Descriptor descriptor =
typeDescriptor(returnType, originalReturnType);
descriptor = ImmutableDescriptor.union(descriptor,
- Introspector.descriptorForElement(method));
+ Introspector.descriptorForElement(method, false));
final MBeanOperationInfo oi;
if (openReturnType && openParameterTypes) {
/* If the return value and all the parameters can be faithfully
--- a/jdk/src/share/classes/com/sun/servicetag/Installer.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/servicetag/Installer.java Tue Dec 09 17:41:59 2008 +0100
@@ -475,7 +475,7 @@
String filename = "/com/sun/servicetag/resources/javase_" +
version + "_swordfish.properties";
- InputStream in = Installer.class.getClass().getResourceAsStream(filename);
+ InputStream in = Installer.class.getResourceAsStream(filename);
if (in == null) {
return null;
}
@@ -813,7 +813,7 @@
locale,
String.valueOf(version)).toString();
try {
- in = Installer.class.getClass().getResourceAsStream(resource + ".html");
+ in = Installer.class.getResourceAsStream(resource + ".html");
if (in == null) {
// if the resource file is missing
if (isVerbose()) {
@@ -825,34 +825,39 @@
System.out.println("Generating " + f + " from " + resource + ".html");
}
- br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
- pw = new PrintWriter(f, "UTF-8");
- String line = null;
- while ((line = br.readLine()) != null) {
- String output = line;
- if (line.contains(JDK_VERSION_KEY)) {
- output = line.replace(JDK_VERSION_KEY, jdkVersion);
- } else if (line.contains(JDK_HEADER_PNG_KEY)) {
- output = line.replace(JDK_HEADER_PNG_KEY, headerImageSrc);
- } else if (line.contains(REGISTRATION_URL_KEY)) {
- output = line.replace(REGISTRATION_URL_KEY, registerURL);
- } else if (line.contains(REGISTRATION_PAYLOAD_KEY)) {
- output = line.replace(REGISTRATION_PAYLOAD_KEY, payload.toString());
+ try {
+ br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+ pw = new PrintWriter(f, "UTF-8");
+ String line = null;
+ while ((line = br.readLine()) != null) {
+ String output = line;
+ if (line.contains(JDK_VERSION_KEY)) {
+ output = line.replace(JDK_VERSION_KEY, jdkVersion);
+ } else if (line.contains(JDK_HEADER_PNG_KEY)) {
+ output = line.replace(JDK_HEADER_PNG_KEY, headerImageSrc);
+ } else if (line.contains(REGISTRATION_URL_KEY)) {
+ output = line.replace(REGISTRATION_URL_KEY, registerURL);
+ } else if (line.contains(REGISTRATION_PAYLOAD_KEY)) {
+ output = line.replace(REGISTRATION_PAYLOAD_KEY, payload.toString());
+ }
+ pw.println(output);
}
- pw.println(output);
+ f.setReadOnly();
+ pw.flush();
+ } finally {
+ // It's safe for this finally block to have two close statements
+ // consecutively as PrintWriter.close doesn't throw IOException.
+ if (pw != null) {
+ pw.close();
+ }
+ if (br!= null) {
+ br.close();
+ }
}
- f.setReadOnly();
- pw.flush();
} finally {
- if (pw != null) {
- pw.close();
- }
if (in != null) {
in.close();
}
- if (br!= null) {
- br.close();
- }
}
}
}
--- a/jdk/src/share/classes/com/sun/servicetag/SolarisSystemEnvironment.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/servicetag/SolarisSystemEnvironment.java Tue Dec 09 17:41:59 2008 +0100
@@ -62,8 +62,8 @@
return "Sun Microsystems, Inc";
}
- // if we're here, then we'll try smbios (type 3)
- return getSmbiosData("3", "Manufacturer: ");
+ // if we're here, then we'll try smbios (type 4)
+ return getSmbiosData("4", "Manufacturer: ");
}
/**
--- a/jdk/src/share/classes/com/sun/servicetag/SunConnection.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/servicetag/SunConnection.java Tue Dec 09 17:41:59 2008 +0100
@@ -213,10 +213,16 @@
con.setRequestProperty("Content-Type", "text/xml;charset=\"utf-8\"");
con.connect();
- OutputStream out = con.getOutputStream();
- registration.storeToXML(out);
- out.flush();
- out.close();
+ OutputStream out = null;
+ try {
+ out = con.getOutputStream();
+ registration.storeToXML(out);
+ out.flush();
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
int returnCode = con.getResponseCode();
if (Util.isVerbose()) {
--- a/jdk/src/share/classes/com/sun/servicetag/Util.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/servicetag/Util.java Tue Dec 09 17:41:59 2008 +0100
@@ -140,11 +140,14 @@
}
return e.getMessage();
} finally {
- if (r != null) {
- r.close();
- }
- if (err != null) {
- err.close();
+ try {
+ if (r != null) {
+ r.close();
+ }
+ } finally {
+ if (err != null) {
+ err.close();
+ }
}
}
}
--- a/jdk/src/share/classes/com/sun/servicetag/WindowsSystemEnvironment.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/com/sun/servicetag/WindowsSystemEnvironment.java Tue Dec 09 17:41:59 2008 +0100
@@ -107,11 +107,17 @@
Process p = pb.start();
// need this for executing windows commands (at least
// needed for executing wmic command)
- BufferedWriter bw = new BufferedWriter(
- new OutputStreamWriter(p.getOutputStream()));
- bw.write(13);
- bw.flush();
- bw.close();
+ BufferedWriter bw = null;
+ try {
+ bw = new BufferedWriter(
+ new OutputStreamWriter(p.getOutputStream()));
+ bw.write(13);
+ bw.flush();
+ } finally {
+ if (bw != null) {
+ bw.close();
+ }
+ }
p.waitFor();
if (p.exitValue() == 0) {
--- a/jdk/src/share/classes/javax/management/Descriptor.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/Descriptor.java Tue Dec 09 17:41:59 2008 +0100
@@ -147,6 +147,14 @@
* might be disabled if it cannot currently be emitted but could be in
* other circumstances.</td>
*
+ * <tr id="exceptions"><td><i>exceptions</i><td>String[]</td>
+ * <td>MBeanAttributeInfo, MBeanConstructorInfo, MBeanOperationInfo</td>
+ *
+ * <td>The class names of the exceptions that can be thrown when invoking a
+ * constructor or operation, or getting an attribute. Exceptions thrown when
+ * setting an attribute are specified by the field
+ * <a href="#setExceptions">{@code setExceptions}</a>.
+ *
* <tr id="immutableInfo"><td><i>immutableInfo</i><td>String</td>
* <td>MBeanInfo</td>
*
@@ -237,6 +245,13 @@
* MXBean, if it was not the {@linkplain MXBeanMappingFactory#DEFAULT default}
* one.</td>
*
+ * <tr><td id="objectNameTemplate"><i>objectNameTemplate</i>
+ * </td><td>String</td>
+ * <td>MBeanInfo</td>
+ *
+ * <td>The template to use to name this MBean. Its value must be compliant with
+ * the specification of the {@link ObjectNameTemplate} annotation.</td>
+ *
* <tr id="openType"><td><i>openType</i><td>{@link OpenType}</td>
* <td>MBeanAttributeInfo<br>MBeanOperationInfo<br>MBeanParameterInfo</td>
*
@@ -270,6 +285,13 @@
* href="MXBean.html#type-names">Type Names</a> of the MXBean
* specification.</p>
*
+ * <tr id="setExceptions"><td><i>setExceptions</i><td>String[]</td>
+ * <td>MBeanAttributeInfo</td>
+ *
+ * <td>The class names of the exceptions that can be thrown when setting
+ * an attribute. Exceptions thrown when getting an attribute are specified
+ * by the field <a href="#exceptions">{@code exceptions}</a>.
+ *
* <tr><td>severity</td><td>String<br>Integer</td>
* <td>MBeanNotificationInfo</td>
*
--- a/jdk/src/share/classes/javax/management/JMX.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/JMX.java Tue Dec 09 17:41:59 2008 +0100
@@ -76,6 +76,12 @@
"descriptionResourceKey";
/**
+ * The name of the <a href="Descriptor.html#exceptions">{@code
+ * exceptions}</a> field.
+ */
+ public static final String EXCEPTIONS_FIELD = "exceptions";
+
+ /**
* The name of the <a href="Descriptor.html#immutableInfo">{@code
* immutableInfo}</a> field.
*/
@@ -138,6 +144,18 @@
public static final String ORIGINAL_TYPE_FIELD = "originalType";
/**
+ * The name of the <a href="Descriptor.html#setExceptions">{@code
+ * setExceptions}</a> field.
+ */
+ public static final String SET_EXCEPTIONS_FIELD = "setExceptions";
+
+ /**
+ * The name of the <a href="Descriptor.html#objectNameTemplate">{@code
+ * objectNameTemplate}</a> field.
+ */
+ public static final String OBJECT_NAME_TEMPLATE = "objectNameTemplate";
+
+ /**
* <p>Options to apply to an MBean proxy or to an instance of {@link
* StandardMBean}.</p>
*
--- a/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java Tue Dec 09 17:41:59 2008 +0100
@@ -186,8 +186,10 @@
(getter != null),
(setter != null),
isIs(getter),
- ImmutableDescriptor.union(Introspector.descriptorForElement(getter),
- Introspector.descriptorForElement(setter)));
+ ImmutableDescriptor.union(Introspector.
+ descriptorForElement(getter, false),
+ Introspector.descriptorForElement(setter,
+ true)));
}
/**
--- a/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java Tue Dec 09 17:41:59 2008 +0100
@@ -67,7 +67,7 @@
public MBeanConstructorInfo(String description, Constructor<?> constructor) {
this(constructor.getName(), description,
constructorSignature(constructor),
- Introspector.descriptorForElement(constructor));
+ Introspector.descriptorForElement(constructor, false));
}
/**
--- a/jdk/src/share/classes/javax/management/MBeanOperationInfo.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanOperationInfo.java Tue Dec 09 17:41:59 2008 +0100
@@ -113,7 +113,7 @@
methodSignature(method),
method.getReturnType().getName(),
UNKNOWN,
- Introspector.descriptorForElement(method));
+ Introspector.descriptorForElement(method, false));
}
/**
--- a/jdk/src/share/classes/javax/management/MBeanServer.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanServer.java Tue Dec 09 17:41:59 2008 +0100
@@ -351,11 +351,14 @@
/**
* <p>Registers a pre-existing object as an MBean with the MBean
- * server. If the object name given is null, the MBean must
- * provide its own name by implementing the {@link
+ * server. If the object name given is null, the
+ * MBean must provide its own name in one or both of two ways: by implementing the {@link
* javax.management.MBeanRegistration MBeanRegistration} interface
* and returning the name from the {@link
- * MBeanRegistration#preRegister preRegister} method.</p>
+ * MBeanRegistration#preRegister preRegister} method; or by defining
+ * an {@code objectNameTemplate} field in its {@link Descriptor},
+ * typically using the {@link ObjectNameTemplate @ObjectNameTemplate}
+ * annotation.</p>
*
* <p>If this method successfully registers an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
--- a/jdk/src/share/classes/javax/management/MBeanServerConnection.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanServerConnection.java Tue Dec 09 17:41:59 2008 +0100
@@ -46,11 +46,14 @@
* MBean server will use its {@link
* javax.management.loading.ClassLoaderRepository Default Loader
* Repository} to load the class of the MBean. An object name is
- * associated to the MBean. If the object name given is null, the
- * MBean must provide its own name by implementing the {@link
+ * associated with the MBean. If the object name given is null, the
+ * MBean must provide its own name in one or both of two ways: by implementing the {@link
* javax.management.MBeanRegistration MBeanRegistration} interface
* and returning the name from the {@link
- * MBeanRegistration#preRegister preRegister} method.</p>
+ * MBeanRegistration#preRegister preRegister} method; or by defining
+ * an {@code objectNameTemplate} field in its {@link Descriptor},
+ * typically using the {@link ObjectNameTemplate @ObjectNameTemplate}
+ * annotation.</p>
*
* <p>This method is equivalent to {@link
* #createMBean(String,ObjectName,Object[],String[])
@@ -117,13 +120,16 @@
/**
* <p>Instantiates and registers an MBean in the MBean server. The
* class loader to be used is identified by its object name. An
- * object name is associated to the MBean. If the object name of
+ * object name is associated with the MBean. If the object name of
* the loader is null, the ClassLoader that loaded the MBean
- * server will be used. If the MBean's object name given is null,
- * the MBean must provide its own name by implementing the {@link
+ * server will be used. If the object name given is null, the
+ * MBean must provide its own name in one or both of two ways: by implementing the {@link
* javax.management.MBeanRegistration MBeanRegistration} interface
* and returning the name from the {@link
- * MBeanRegistration#preRegister preRegister} method.</p>
+ * MBeanRegistration#preRegister preRegister} method; or by defining
+ * an {@code objectNameTemplate} field in its {@link Descriptor},
+ * typically using the {@link ObjectNameTemplate @ObjectNameTemplate}
+ * annotation.</p>
*
* <p>This method is equivalent to {@link
* #createMBean(String,ObjectName,ObjectName,Object[],String[])
@@ -198,11 +204,14 @@
* MBean server will use its {@link
* javax.management.loading.ClassLoaderRepository Default Loader
* Repository} to load the class of the MBean. An object name is
- * associated to the MBean. If the object name given is null, the
- * MBean must provide its own name by implementing the {@link
+ * associated with the MBean. If the object name given is null, the
+ * MBean must provide its own name in one or both of two ways: by implementing the {@link
* javax.management.MBeanRegistration MBeanRegistration} interface
* and returning the name from the {@link
- * MBeanRegistration#preRegister preRegister} method.
+ * MBeanRegistration#preRegister preRegister} method; or by defining
+ * an {@code objectNameTemplate} field in its {@link Descriptor},
+ * typically using the {@link ObjectNameTemplate @ObjectNameTemplate}
+ * annotation.</p>
*
* @param className The class name of the MBean to be instantiated.
* @param name The object name of the MBean. May be null.
@@ -267,15 +276,18 @@
NotCompliantMBeanException, IOException;
/**
- * Instantiates and registers an MBean in the MBean server. The
+ * <p>Instantiates and registers an MBean in the MBean server. The
* class loader to be used is identified by its object name. An
- * object name is associated to the MBean. If the object name of
+ * object name is associated with the MBean. If the object name of
* the loader is not specified, the ClassLoader that loaded the
- * MBean server will be used. If the MBean object name given is
- * null, the MBean must provide its own name by implementing the
- * {@link javax.management.MBeanRegistration MBeanRegistration}
- * interface and returning the name from the {@link
- * MBeanRegistration#preRegister preRegister} method.
+ * MBean server will be used. If the object name given is null, the
+ * MBean must provide its own name in one or both of two ways: by implementing the {@link
+ * javax.management.MBeanRegistration MBeanRegistration} interface
+ * and returning the name from the {@link
+ * MBeanRegistration#preRegister preRegister} method; or by defining
+ * an {@code objectNameTemplate} field in its {@link Descriptor},
+ * typically using the {@link ObjectNameTemplate @ObjectNameTemplate}
+ * annotation.</p>
*
* @param className The class name of the MBean to be instantiated.
* @param name The object name of the MBean. May be null.
--- a/jdk/src/share/classes/javax/management/MBeanServerNotification.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/MBeanServerNotification.java Tue Dec 09 17:41:59 2008 +0100
@@ -57,15 +57,55 @@
* what = "Unknown type " + n.getType();
* System.out.println("Received MBean Server notification: " + what + ": " +
* mbsn.getMBeanName());
+ * }
* };
*
* ...
* mbeanServer.addNotificationListener(
* MBeanServerDelegate.DELEGATE_NAME, printListener, null, null);
* </pre>
- *
- * <p>The following code prints a message every time an MBean is registered
- * or unregistered in the MBean Server {@code mbeanServer}:</p>
+ * <p id="group">
+ * An MBean which is not an {@link MBeanServerDelegate} may also emit
+ * MBeanServerNotifications. In particular, a custom subclass of the
+ * {@link javax.management.namespace.JMXDomain JMXDomain} MBean or a custom
+ * subclass of the {@link javax.management.namespace.JMXNamespace JMXNamespace}
+ * MBean may emit an MBeanServerNotification for a group of MBeans.<br>
+ * An MBeanServerNotification emitted to denote the registration or
+ * unregistration of a group of MBeans has the following characteristics:
+ * <ul><li>Its {@linkplain Notification#getType() notification type} is
+ * {@code "JMX.mbean.registered.group"} or
+ * {@code "JMX.mbean.unregistered.group"}, which can also be written {@link
+ * MBeanServerNotification#REGISTRATION_NOTIFICATION}{@code + ".group"} or
+ * {@link
+ * MBeanServerNotification#UNREGISTRATION_NOTIFICATION}{@code + ".group"}.
+ * </li>
+ * <li>Its {@linkplain #getMBeanName() MBean name} is an ObjectName pattern
+ * that selects the set (or a superset) of the MBeans being registered
+ * or unregistered</li>
+ * <li>Its {@linkplain Notification#getUserData() user data} can optionally
+ * be set to an array of ObjectNames containing the names of all MBeans
+ * being registered or unregistered.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * MBeans which emit these group registration/unregistration notifications will
+ * declare them in their {@link MBeanInfo#getNotifications()
+ * MBeanNotificationInfo}.
+ * </p>
+ * <P>
+ * To receive a group MBeanServerNotification, you need to register a listener
+ * with the MBean that emits it. For instance, assuming that the {@link
+ * javax.management.namespace.JMXNamespace JMXNamespace} MBean handling
+ * namespace {@code "foo"} has declared that it emits such a notification,
+ * you will need to register your notification listener with that MBean, which
+ * will be named {@link
+ * javax.management.namespace.JMXNamespaces#getNamespaceObjectName(java.lang.String)
+ * foo//:type=JMXNamespace}.
+ * </p>
+ * <p>The following code prints a message every time a group of MBean is
+ * registered or unregistered in the namespace {@code "foo"}, assumimg its
+ * {@link javax.management.namespace.JMXNamespace handler} supports
+ * group MBeanServerNotifications:</p>
*
* <pre>
* private static final NotificationListener printListener = new NotificationListener() {
@@ -76,19 +116,33 @@
* }
* MBeanServerNotification mbsn = (MBeanServerNotification) n;
* String what;
- * if (n.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION))
+ * ObjectName[] names = null;
+ * if (n.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION)) {
* what = "MBean registered";
- * else if (n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION))
+ * } else if (n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
* what = "MBean unregistered";
- * else
+ * } else if (n.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION+".group")) {
+ * what = "Group of MBeans registered matching";
+ * if (mbsn.getUserData() instanceof ObjectName[])
+ * names = (ObjectName[]) mbsn.getUserData();
+ * } else if (n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION+".group")) {
+ * what = "Group of MBeans unregistered matching";
+ * if (mbsn.getUserData() instanceof ObjectName[])
+ * names = (ObjectName[]) mbsn.getUserData();
+ * } else
* what = "Unknown type " + n.getType();
* System.out.println("Received MBean Server notification: " + what + ": " +
* mbsn.getMBeanName());
+ * if (names != null) {
+ * for (ObjectName mb : names)
+ * System.out.println("\t"+mb);
+ * }
+ * }
* };
*
* ...
* mbeanServer.addNotificationListener(
- * MBeanServerDelegate.DELEGATE_NAME, printListener, null, null);
+ * JMXNamespaces.getNamespaceObjectName("foo"), printListener, null, null);
* </pre>
*
* @since 1.5
--- a/jdk/src/share/classes/javax/management/NotificationInfo.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/NotificationInfo.java Tue Dec 09 17:41:59 2008 +0100
@@ -44,7 +44,13 @@
* "com.example.notifs.destroy"})
* public interface CacheMBean {...}
*
- * public class Cache implements CacheMBean {...}
+ * public class Cache
+ * extends NotificationBroadcasterSupport implements CacheMBean {
+ * public Cache() {
+ * super(); // do not supply any MBeanNotificationInfo[]
+ * }
+ * ...
+ * }
* </pre>
*
* <pre>
@@ -52,7 +58,11 @@
* {@link MBean @MBean}
* {@code @NotificationInfo}(types={"com.example.notifs.create",
* "com.example.notifs.destroy"})
- * public class Cache {...}
+ * public class Cache {
+ * <a href="MBeanRegistration.html#injection">{@code @Resource}</a>
+ * private volatile SendNotification sendNotification;
+ * ...
+ * }
* </pre>
*
* <p>Each {@code @NotificationInfo} produces an {@link
@@ -64,6 +74,13 @@
* several {@code @NotificationInfo} annotations into a containing
* {@link NotificationInfos @NotificationInfos} annotation.
*
+ * <p>The {@code @NotificationInfo} and {@code @NotificationInfos} annotations
+ * are ignored on an MBean that is not a {@linkplain JMX#isNotificationSource
+ * notification source} or that implements {@link NotificationBroadcaster} and
+ * returns a non-empty array from its {@link
+ * NotificationBroadcaster#getNotificationInfo() getNotificationInfo()}
+ * method.</p>
+ *
* <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
@@ -71,7 +88,8 @@
* 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>
+ * of them is a descendant of all the others; registering such an erroneous
+ * MBean will cause a {@link NotCompliantMBeanException}.</p>
*/
@Documented
@Inherited
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/ObjectNameTemplate.java Tue Dec 09 17:41:59 2008 +0100
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2008 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;
+
+/**
+ * Annotation to allow an MBean to provide its name.
+ * This annotation can be used on the following types:
+ * <ul>
+ * <li>MBean or MXBean Java interface.</li>
+ * <li>Java class annotated with {@link javax.management.MBean @MBean}</code>
+ * annotation.</li>
+ * <li>Java class annotated with {@link javax.management.MXBean @MXBean}</code>
+ * annotation.</li>
+ * </ul>
+ *
+ * <p>The value of this annotation is used to build the <code>ObjectName</code>
+ * when instances of the annotated type are registered in
+ * an <code>MBeanServer</code> and no explicit name is given to the
+ * {@code createMBean} or {@code registerMBean} method (the {@code ObjectName}
+ * is {@code null}).</p>
+ *
+ * <p>For Dynamic MBeans, which define their own {@code MBeanInfo}, you can
+ * produce the same effect as this annotation by including a field
+ * <a href="Descriptor.html#objectNameTemplate">{@code objectNameTemplate}</a>
+ * in the {@link Descriptor} for the {@code MBeanInfo} returned by
+ * {@link DynamicMBean#getMBeanInfo()}.</p>
+ *
+ * <p>For Standard MBeans and MXBeans, this annotation automatically produces
+ * an {@code objectNameTemplate} field in the {@code Descriptor}.</p>
+ *
+ * <p>The template can contain variables so that the name of the MBean
+ * depends on the value of one or more of its attributes.
+ * A variable that identifies an MBean attribute is of the form
+ * <code>{<em>attribute name</em>}</code>. For example, to make an MBean name
+ * depend on the <code>Name</code> attribute, use the variable
+ * <code>{Name}</code>. Attribute names are case sensitive.
+ * Naming attributes can be of any type. The <code>String</code> returned by
+ * <code>toString()</code> is included in the constructed name.</p>
+ *
+ * <p>If you need the attribute value to be quoted
+ * by a call to {@link ObjectName#quote(String) ObjectName.quote},
+ * surround the variable with quotes. Quoting only applies to key values.
+ * For example, <code>@ObjectNameTemplate("java.lang:type=MemoryPool,name=\"{Name}\"")</code>,
+ * quotes the <code>Name</code> attribute value. You can notice the "\"
+ * character needed to escape a quote within a <code>String</code>. A name
+ * produced by this template might look like
+ * {@code java.lang:type=MemoryPool,name="Code Cache"}.</p>
+ *
+ * <p>Variables can be used anywhere in the <code>String</code>.
+ * Be sure to make the template derived name comply with
+ * {@link ObjectName ObjectName} syntax.</p>
+ *
+ * <p>If an MBean is registered with a null name and it implements
+ * {@link javax.management.MBeanRegistration MBeanRegistration}, then
+ * the computed name is provided to the <code>preRegister</code> method.
+ * Similarly,
+ * if the MBean uses <a href="MBeanRegistration.html#injection">resource
+ * injection</a> to discover its name, it is the computed name that will
+ * be injected.</p>
+ * <p>All of the above can be used with the {@link StandardMBean} class and
+ * the annotation is effective in that case too.</p>
+ * <p>If any exception occurs (such as unknown attribute, invalid syntax or
+ * exception
+ * thrown by the MBean) when the name is computed it is wrapped in a
+ * <code>NotCompliantMBeanException</code>.</p>
+ * <p>Some ObjectName template examples:
+ * <ul><li>"com.example:type=Memory". Fixed ObjectName. Used to name a
+ * singleton MBean.</li>
+ * <li>"com.example:type=MemoryPool,name={Name}". Variable ObjectName.
+ * <code>Name</code> attribute is retrieved to compose the <code>name</code>
+ * key value.</li>
+ * <li>"com.example:type=SomeType,name={InstanceName},id={InstanceId}".
+ * Variable ObjectName.
+ * <code>InstanceName</code> and <code>InstanceId</code> attributes are
+ * retrieved to compose respectively
+ * the <code>name</code> and <code>id</code> key values.</li>
+ * <li>"com.example:type=OtherType,name=\"{ComplexName}\"". Variable ObjectName.
+ * <code>ComplexName</code> attribute is retrieved to compose the
+ * <code>name</code> key quoted value.</li> </li>
+ * <li>"com.example:{TypeKey}=SomeOtherType". Variable ObjectName.
+ * <code>TypeKey</code> attribute is retrieved to compose the
+ * first key name.</li>
+ * * <li>"{Domain}:type=YetAnotherType". Variable ObjectName.
+ * <code>Domain</code> attribute is retrieved to compose the
+ * management domain.</li>
+ * <li>"{Naming}". Variable ObjectName.
+ * <code>Naming</code> attribute is retrieved to compose the
+ * complete name.</li>
+ * </ul>
+ * </p>
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ObjectNameTemplate {
+
+ /**
+ * The MBean name template.
+ * @return The MBean name template.
+ */
+ @DescriptorKey("objectNameTemplate")
+ public String value();
+}
--- a/jdk/src/share/classes/javax/management/StandardMBean.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/StandardMBean.java Tue Dec 09 17:41:59 2008 +0100
@@ -28,14 +28,21 @@
import com.sun.jmx.mbeanserver.DescriptorCache;
import com.sun.jmx.mbeanserver.Introspector;
import com.sun.jmx.mbeanserver.MBeanInjector;
+import com.sun.jmx.mbeanserver.MBeanInstantiator;
+import com.sun.jmx.mbeanserver.MBeanIntrospector;
import com.sun.jmx.mbeanserver.MBeanSupport;
import com.sun.jmx.mbeanserver.MXBeanSupport;
import com.sun.jmx.mbeanserver.StandardMBeanSupport;
import com.sun.jmx.mbeanserver.Util;
+import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.WeakHashMap;
import java.util.logging.Level;
import javax.management.openmbean.MXBeanMappingFactory;
@@ -135,6 +142,7 @@
private static final long serialVersionUID = 5107355471177517164L;
private boolean wrappedVisible;
+ private boolean forwardRegistration;
/**
* <p>Construct an {@code Options} object where all options have
@@ -177,15 +185,56 @@
this.wrappedVisible = visible;
}
- // Canonical objects for each of (MXBean,!MXBean) x (WVisible,!WVisible)
+ /**
+ * <p>Defines whether the {@link MBeanRegistration MBeanRegistration}
+ * callbacks are forwarded to the wrapped object.</p>
+ *
+ * <p>If this option is true, then
+ * {@link #preRegister(MBeanServer, ObjectName) preRegister},
+ * {@link #postRegister(Boolean) postRegister},
+ * {@link #preDeregister preDeregister} and
+ * {@link #postDeregister postDeregister} methods are forwarded
+ * to the wrapped object, in addition to the behaviour specified
+ * for the StandardMBean instance itself.
+ * The default value is false for compatibility reasons, but true
+ * is a better value for most new code.</p>
+ *
+ * @return true if the <code>MBeanRegistration</code> callbacks
+ * are forwarded to the wrapped object.
+ */
+ public boolean isMBeanRegistrationForwarded() {
+ return this.forwardRegistration;
+ }
+
+ /**
+ * <p>Set the
+ * {@link #isMBeanRegistrationForwarded MBeanRegistrationForwarded}
+ * option to the given value.</p>
+ * @param forward the new value.
+ */
+ public void setMBeanRegistrationForwarded(boolean forward) {
+ this.forwardRegistration = forward;
+ }
+
+ // Canonical objects for each of
+ // (MXBean,!MXBean) x (WVisible,!WVisible) x (Forward,!Forward)
private static final Options[] CANONICALS = {
new Options(), new Options(), new Options(), new Options(),
+ 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);
+ CANONICALS[4].setMBeanRegistrationForwarded(true);
+ CANONICALS[5].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
+ CANONICALS[5].setMBeanRegistrationForwarded(true);
+ CANONICALS[6].setWrappedObjectVisible(true);
+ CANONICALS[6].setMBeanRegistrationForwarded(true);
+ CANONICALS[7].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
+ CANONICALS[7].setWrappedObjectVisible(true);
+ CANONICALS[7].setMBeanRegistrationForwarded(true);
}
@Override
MBeanOptions[] canonicals() {
@@ -195,7 +244,8 @@
@Override
boolean same(MBeanOptions opts) {
return (super.same(opts) && opts instanceof Options &&
- ((Options) opts).wrappedVisible == wrappedVisible);
+ ((Options) opts).wrappedVisible == wrappedVisible &&
+ ((Options) opts).forwardRegistration ==forwardRegistration);
}
}
@@ -477,7 +527,9 @@
*
* @exception IllegalArgumentException if the given
* <var>implementation</var> is null.
- *
+ * @exception IllegalStateException if the
+ * {@link Options#isMBeanRegistrationForwarded MBeanRegistrationForwarded}
+ * option is true.
* @exception NotCompliantMBeanException if the given
* <var>implementation</var> does not implement the
* Standard MBean (or MXBean) interface that was
@@ -490,6 +542,12 @@
if (implementation == null)
throw new IllegalArgumentException("implementation is null");
+
+ if(options instanceof Options &&
+ ((Options) options).isMBeanRegistrationForwarded())
+ throw new IllegalStateException("Implementation can't be changed " +
+ "because MBeanRegistrationForwarded option is true");
+
setImplementation2(implementation);
}
@@ -1265,6 +1323,145 @@
return natts;
}
+ // ------------------------------------------------------------------
+ // Resolve from a type name to a Class.
+ // ------------------------------------------------------------------
+ private static Class<?> resolveClass(MBeanFeatureInfo info, String type,
+ Class<?> mbeanItf)
+ throws ClassNotFoundException {
+ String t = (String) info.getDescriptor().
+ getFieldValue(JMX.ORIGINAL_TYPE_FIELD);
+ if (t == null) {
+ t = type;
+ }
+ Class<?> clazz = MBeanInstantiator.primitiveType(t);
+ if(clazz == null)
+ clazz = Class.forName(t, false, mbeanItf.getClassLoader());
+ return clazz;
+ }
+
+ // ------------------------------------------------------------------
+ // Return the subset of valid Management methods
+ // ------------------------------------------------------------------
+ private static Method getManagementMethod(final Class<?> mbeanType,
+ String opName, Class<?>... parameters) throws NoSuchMethodException,
+ SecurityException {
+ Method m = mbeanType.getMethod(opName, parameters);
+ if (mbeanType.isInterface()) {
+ return m;
+ }
+ final List<Method> methods = new ArrayList<Method>();
+ try {
+ MBeanIntrospector.getAnnotatedMethods(mbeanType, methods);
+ }catch (SecurityException ex) {
+ throw ex;
+ }catch (NoSuchMethodException ex) {
+ throw ex;
+ }catch (Exception ex) {
+ NoSuchMethodException nsme =
+ new NoSuchMethodException(ex.toString());
+ nsme.initCause(ex);
+ throw nsme;
+ }
+
+ if(methods.contains(m)) return m;
+
+ throw new NoSuchMethodException("Operation " + opName +
+ " not found in management interface " + mbeanType.getName());
+ }
+ /**
+ * Retrieve the set of MBean attribute accessor <code>Method</code>s
+ * located in the <code>mbeanInterface</code> MBean interface that
+ * correspond to the <code>attr</code> <code>MBeanAttributeInfo</code>
+ * parameter.
+ * @param mbeanInterface the management interface.
+ * Can be a standard MBean or MXBean interface, or a Java class
+ * annotated with {@link MBean @MBean} or {@link MXBean @MXBean}.
+ * @param attr The attribute we want the accessors for.
+ * @return The set of accessors.
+ * @throws java.lang.NoSuchMethodException if no accessor exists
+ * for the given {@link MBeanAttributeInfo MBeanAttributeInfo}.
+ * @throws java.lang.IllegalArgumentException if at least one
+ * of the two parameters is null.
+ * @throws java.lang.ClassNotFoundException if the class named in the
+ * attribute type is not found.
+ * @throws java.lang.SecurityException if this exception is
+ * encountered while introspecting the MBean interface.
+ */
+ public static Set<Method> findAttributeAccessors(Class<?> mbeanInterface,
+ MBeanAttributeInfo attr)
+ throws NoSuchMethodException,
+ ClassNotFoundException {
+ if (mbeanInterface == null || attr == null) {
+ throw new IllegalArgumentException("mbeanInterface or attr " +
+ "parameter is null");
+ }
+ String attributeName = attr.getName();
+ Set<Method> methods = new HashSet<Method>();
+ Class<?> clazz = resolveClass(attr, attr.getType(), mbeanInterface);
+ if (attr.isReadable()) {
+ String radical = "get";
+ if(attr.isIs()) radical = "is";
+ Method getter = getManagementMethod(mbeanInterface, radical +
+ attributeName);
+ if (getter.getReturnType().equals(clazz)) {
+ methods.add(getter);
+ } else {
+ throw new NoSuchMethodException("Invalid getter return type, " +
+ "should be " + clazz + ", found " +
+ getter.getReturnType());
+ }
+ }
+ if (attr.isWritable()) {
+ Method setter = getManagementMethod(mbeanInterface, "set" +
+ attributeName,
+ clazz);
+ if (setter.getReturnType().equals(Void.TYPE)) {
+ methods.add(setter);
+ } else {
+ throw new NoSuchMethodException("Invalid setter return type, " +
+ "should be void, found " + setter.getReturnType());
+ }
+ }
+ return methods;
+ }
+
+ /**
+ * Retrieve the MBean operation <code>Method</code>
+ * located in the <code>mbeanInterface</code> MBean interface that
+ * corresponds to the provided <code>op</code>
+ * <code>MBeanOperationInfo</code> parameter.
+ * @param mbeanInterface the management interface.
+ * Can be a standard MBean or MXBean interface, or a Java class
+ * annotated with {@link MBean @MBean} or {@link MXBean @MXBean}.
+ * @param op The operation we want the method for.
+ * @return the method corresponding to the provided MBeanOperationInfo.
+ * @throws java.lang.NoSuchMethodException if no method exists
+ * for the given {@link MBeanOperationInfo MBeanOperationInfo}.
+ * @throws java.lang.IllegalArgumentException if at least one
+ * of the two parameters is null.
+ * @throws java.lang.ClassNotFoundException if one of the
+ * classes named in the operation signature array is not found.
+ * @throws java.lang.SecurityException if this exception is
+ * encountered while introspecting the MBean interface.
+ */
+ public static Method findOperationMethod(Class<?> mbeanInterface,
+ MBeanOperationInfo op)
+ throws ClassNotFoundException, NoSuchMethodException {
+ if (mbeanInterface == null || op == null) {
+ throw new IllegalArgumentException("mbeanInterface or op " +
+ "parameter is null");
+ }
+ List<Class<?>> classes = new ArrayList<Class<?>>();
+ for (MBeanParameterInfo info : op.getSignature()) {
+ Class<?> clazz = resolveClass(info, info.getType(), mbeanInterface);
+ classes.add(clazz);
+ }
+ Class<?>[] signature = new Class<?>[classes.size()];
+ classes.toArray(signature);
+ return getManagementMethod(mbeanInterface, op.getName(), signature);
+ }
+
/**
* <p>Allows the MBean to perform any operations it needs before
* being registered in the MBean server. If the name of the MBean
@@ -1273,10 +1470,14 @@
* registered in the MBean server.</p>
*
* <p>The default implementation of this method returns the {@code name}
- * parameter. It does nothing else for
- * Standard MBeans. For MXBeans, it records the {@code MBeanServer}
- * and {@code ObjectName} parameters so they can be used to translate
- * inter-MXBean references.</p>
+ * parameter. If the
+ * {@link Options#isMBeanRegistrationForwarded MBeanRegistrationForwarded}
+ * option is set to true, then this method is forwarded to the object
+ * returned by the {@link #getImplementation getImplementation()} method.
+ * The name returned by this call is then returned by this method.
+ * It does nothing else for Standard MBeans. For MXBeans, it records
+ * the {@code MBeanServer} and {@code ObjectName} parameters so they can
+ * be used to translate inter-MXBean references.</p>
*
* <p>It is good practice for a subclass that overrides this method
* to call the overridden method via {@code super.preRegister(...)}.
@@ -1311,6 +1512,11 @@
*/
public ObjectName preRegister(MBeanServer server, ObjectName name)
throws Exception {
+ // Forward preRegister before to call register and
+ // inject parameters.
+ if(shouldForwardMBeanRegistration())
+ name = ((MBeanRegistration)getImplementation()).
+ preRegister(server, name);
mbean.register(server, name);
MBeanInjector.inject(mbean.getWrappedObject(), server, name);
return name;
@@ -1320,7 +1526,11 @@
* <p>Allows the MBean to perform any operations needed after having been
* registered in the MBean server or after the registration has failed.</p>
*
- * <p>The default implementation of this method does nothing for
+ * <p>If the
+ * {@link Options#isMBeanRegistrationForwarded MBeanRegistrationForwarded}
+ * option is set to true, then this method is forwarded to the object
+ * returned by the {@link #getImplementation getImplementation()} method.
+ * The default implementation of this method does nothing else for
* Standard MBeans. For MXBeans, it undoes any work done by
* {@link #preRegister preRegister} if registration fails.</p>
*
@@ -1338,16 +1548,24 @@
public void postRegister(Boolean registrationDone) {
if (!registrationDone)
mbean.unregister();
+ if(shouldForwardMBeanRegistration())
+ ((MBeanRegistration)getImplementation()).
+ postRegister(registrationDone);
}
/**
* <p>Allows the MBean to perform any operations it needs before
* being unregistered by the MBean server.</p>
*
- * <p>The default implementation of this method does nothing.</p>
+ * <p>If the
+ * {@link Options#isMBeanRegistrationForwarded MBeanRegistrationForwarded}
+ * option is set to true, then this method is forwarded to the object
+ * returned by the {@link #getImplementation getImplementation()} method.
+ * Other than that, the default implementation of this method does nothing.
+ * </p>
*
* <p>It is good practice for a subclass that overrides this method
- * to call the overridden method via {@code super.preDeegister(...)}.</p>
+ * to call the overridden method via {@code super.preDeregister(...)}.</p>
*
* @throws Exception no checked exceptions are throw by this method
* but {@code Exception} is declared so that subclasses can override
@@ -1356,13 +1574,19 @@
* @since 1.6
*/
public void preDeregister() throws Exception {
+ if(shouldForwardMBeanRegistration())
+ ((MBeanRegistration)getImplementation()).preDeregister();
}
/**
* <p>Allows the MBean to perform any operations needed after having been
* unregistered in the MBean server.</p>
*
- * <p>The default implementation of this method does nothing for
+ * <p>If the
+ * {@link Options#isMBeanRegistrationForwarded MBeanRegistrationForwarded}
+ * option is set to true, then this method is forwarded to the object
+ * returned by the {@link #getImplementation getImplementation()} method.
+ * The default implementation of this method does nothing else for
* Standard MBeans. For MXBeans, it removes any information that
* was recorded by the {@link #preRegister preRegister} method.</p>
*
@@ -1375,8 +1599,15 @@
*/
public void postDeregister() {
mbean.unregister();
+ if(shouldForwardMBeanRegistration())
+ ((MBeanRegistration)getImplementation()).postDeregister();
}
+ private boolean shouldForwardMBeanRegistration() {
+ return (getImplementation() instanceof MBeanRegistration) &&
+ (options instanceof Options &&
+ ((Options) options).isMBeanRegistrationForwarded());
+ }
//
// MBeanInfo immutability
//
--- a/jdk/src/share/classes/javax/management/modelmbean/DescriptorSupport.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/modelmbean/DescriptorSupport.java Tue Dec 09 17:41:59 2008 +0100
@@ -229,9 +229,10 @@
init(inDescr.descriptorMap);
}
-
/**
- * <p>Descriptor constructor taking an XML String.</p>
+ * <p>Descriptor constructor taking an XML String or a
+ * <i>fieldName=fieldValue</i> format String. The String parameter is
+ * parsed as XML if it begins with a '<' character.</p>
*
* <p>The format of the XML string is not defined, but an
* implementation must ensure that the string returned by
@@ -244,17 +245,20 @@
* programmer will have to reset or convert these fields
* correctly.</p>
*
- * @param inStr An XML-formatted string used to populate this
- * Descriptor. The format is not defined, but any
+ * @param inStr An XML-format or a fieldName=fieldValue formatted string
+ * used to populate this Descriptor. The XML format is not defined, but any
* implementation must ensure that the string returned by
* method {@link #toXMLString toXMLString} on an existing
* descriptor can be used to instantiate an equivalent
* descriptor when instantiated using this constructor.
*
- * @exception RuntimeOperationsException If the String inStr
- * passed in parameter is null
+ * @exception RuntimeOperationsException If the String inStr passed in
+ * parameter is null or, when it is not an XML string, if the field name or
+ * field value is illegal. If inStr is not an XML string then it must
+ * contain an "=". "fieldValue", "fieldName", and "fieldValue" are illegal.
+ * FieldName cannot be empty. "fieldName=" will cause the value to be empty.
* @exception XMLParseException XML parsing problem while parsing
- * the input String
+ * the XML-format input String
* @exception MBeanException Wraps a distributed communication Exception.
*/
/* At some stage we should rewrite this code to be cleverer. Using
@@ -283,14 +287,27 @@
throw new RuntimeOperationsException(iae, msg);
}
+ // parse parameter string into structures
+
+ init(null);
+
+ if(!inStr.startsWith("<")) {
+ parseNamesValues(inStr);
+ if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
+ MODELMBEAN_LOGGER.logp(Level.FINEST,
+ DescriptorSupport.class.getName(),
+ "Descriptor(name=value)", "Exit");
+ }
+ return;
+ }
+
final String lowerInStr = inStr.toLowerCase();
if (!lowerInStr.startsWith("<descriptor>")
|| !lowerInStr.endsWith("</descriptor>")) {
throw new XMLParseException("No <descriptor>, </descriptor> pair");
}
- // parse xmlstring into structures
- init(null);
+
// create dummy descriptor: should have same size
// as number of fields in xmlstring
// loop through structures and put them in descriptor
@@ -454,6 +471,16 @@
init(null);
+ parseNamesValues(fields);
+
+ if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
+ MODELMBEAN_LOGGER.logp(Level.FINEST,
+ DescriptorSupport.class.getName(),
+ "Descriptor(String... fields)", "Exit");
+ }
+ }
+
+ private void parseNamesValues(String... fields) {
for (int i=0; i < fields.length; i++) {
if ((fields[i] == null) || (fields[i].equals(""))) {
continue;
@@ -495,11 +522,6 @@
setField(fieldName,fieldValue);
}
- if (MODELMBEAN_LOGGER.isLoggable(Level.FINEST)) {
- MODELMBEAN_LOGGER.logp(Level.FINEST,
- DescriptorSupport.class.getName(),
- "Descriptor(String... fields)", "Exit");
- }
}
private void init(Map<String, ?> initMap) {
--- a/jdk/src/share/classes/javax/management/monitor/MonitorNotification.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/src/share/classes/javax/management/monitor/MonitorNotification.java Tue Dec 09 17:41:59 2008 +0100
@@ -201,7 +201,7 @@
* @param derGauge The derived gauge.
* @param trigger The threshold/string (depending on the monitor type) that triggered the notification.
*/
- MonitorNotification(String type, Object source, long sequenceNumber, long timeStamp, String msg,
+ public MonitorNotification(String type, Object source, long sequenceNumber, long timeStamp, String msg,
ObjectName obsObj, String obsAtt, Object derGauge, Object trigger) {
super(type, source, sequenceNumber, timeStamp, msg);
--- a/jdk/test/javax/management/Introspector/AnnotatedNotificationInfoTest.java Tue Dec 09 17:41:04 2008 +0100
+++ b/jdk/test/javax/management/Introspector/AnnotatedNotificationInfoTest.java Tue Dec 09 17:41:59 2008 +0100
@@ -38,19 +38,34 @@
import javax.management.Description;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
+import javax.management.ListenerNotFoundException;
import javax.management.MBean;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanServer;
import javax.management.MXBean;
+import javax.management.Notification;
+import javax.management.NotificationBroadcaster;
import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
import javax.management.NotificationInfo;
import javax.management.NotificationInfos;
+import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.SendNotification;
public class AnnotatedNotificationInfoTest {
- // Data for the first test. This tests that MBeanNotificationInfo
+
+ static final Descriptor expectedDescriptor = new ImmutableDescriptor(
+ "foo=bar", "descriptionResourceBundleBaseName=bundle",
+ "descriptionResourceKey=key");
+ static final MBeanNotificationInfo expected = new MBeanNotificationInfo(
+ new String[] {"foo", "bar"},
+ AttributeChangeNotification.class.getName(),
+ "description",
+ expectedDescriptor);
+
+ // Data for the first kind of test. This tests that MBeanNotificationInfo
// is correctly derived from @NotificationInfo.
// Every static field called mbean* is expected to be an MBean
// with a single MBeanNotificationInfo that has the same value
@@ -254,11 +269,48 @@
private static Object mbeanMXBean2 = new MXBean2();
- // Classes for the second test. This tests the simplest case, which is
- // the first example in the javadoc for @NotificationInfo. Notice that
- // this MBean is not a NotificationBroadcaster and does not inject a
- // SendNotification! That should possibly be an error, but it's currently
- // allowed by the spec.
+ // Test that @NotificationInfo and @NotificationInfos are ignored if
+ // the MBean returns a non-empty MBeanNotificationInfo[] from its
+ // NotificationBroadcaster.getNotifications() implementation.
+
+ @NotificationInfo(types={"blim", "blam"})
+ public static interface Explicit1MBean {}
+
+ public static class Explicit1
+ extends NotificationBroadcasterSupport implements Explicit1MBean {
+ public Explicit1() {
+ super(expected);
+ }
+ }
+
+ private static Object mbeanExplicit1 = new Explicit1();
+
+ @NotificationInfos(
+ {
+ @NotificationInfo(types="blim"), @NotificationInfo(types="blam")
+ }
+ )
+ public static interface Explicit2MXBean {}
+
+ public static class Explicit2
+ implements NotificationBroadcaster, Explicit2MXBean {
+ public void addNotificationListener(NotificationListener listener,
+ NotificationFilter filter, Object handback) {}
+
+ public void removeNotificationListener(NotificationListener listener)
+ throws ListenerNotFoundException {}
+
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ return new MBeanNotificationInfo[] {expected};
+ }
+ }
+
+ // Data for the second kind of test. This tests that @NotificationInfo is
+ // ignored if the MBean is not a notification source. Every static
+ // field called ignoredMBean* is expected to be an MBean on which
+ // isInstanceOf(NotificationBroadcaster.class.getName() is false,
+ // addNotificationListener produces an exception, and the
+ // MBeanNotificationInfo array is empty.
@NotificationInfo(types={"com.example.notifs.create",
"com.example.notifs.destroy"})
public static interface CacheMBean {
@@ -271,6 +323,73 @@
}
}
+ private static Object ignoredMBean1 = new Cache();
+
+ @NotificationInfos(
+ @NotificationInfo(types={"foo", "bar"})
+ )
+ public static interface Cache2MBean {
+ public int getCachedNum();
+ }
+
+ public static class Cache2 implements Cache2MBean {
+ public int getCachedNum() {
+ return 0;
+ }
+ }
+
+ private static Object ignoredMBean2 = new Cache2();
+
+ private static final NotificationListener nullListener =
+ new NotificationListener() {
+ public void handleNotification(
+ Notification notification, Object handback) {}
+ };
+
+ // Test that inheriting inconsistent @NotificationInfo annotations is
+ // an error, but not if they are overridden by a non-empty getNotifications()
+
+ @NotificationInfo(types={"blim"})
+ public static interface Inconsistent1 {}
+
+ @NotificationInfo(types={"blam"})
+ public static interface Inconsistent2 {}
+
+ public static interface InconsistentMBean extends Inconsistent1, Inconsistent2 {}
+
+ public static class Inconsistent
+ extends NotificationBroadcasterSupport implements InconsistentMBean {}
+
+ public static class Consistent
+ extends Inconsistent implements NotificationBroadcaster {
+ public void addNotificationListener(NotificationListener listener,
+ NotificationFilter filter, Object handback) {}
+
+ public void removeNotificationListener(NotificationListener listener)
+ throws ListenerNotFoundException {}
+
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ return new MBeanNotificationInfo[] {expected};
+ }
+ }
+
+ private static Object mbeanConsistent = new Consistent();
+
+ @NotificationInfo(
+ types = {"foo", "bar"},
+ notificationClass = AttributeChangeNotification.class,
+ description = @Description(
+ value = "description",
+ bundleBaseName = "bundle",
+ key = "key"),
+ descriptorFields = {"foo=bar"})
+ public static interface Consistent2MBean extends Inconsistent1, Inconsistent2 {}
+
+ public static class Consistent2
+ extends NotificationBroadcasterSupport implements Consistent2MBean {}
+
+ private static Object mbeanConsistent2 = new Consistent2();
+
public static void main(String[] args) throws Exception {
if (!AnnotatedNotificationInfoTest.class.desiredAssertionStatus())
throw new Exception("Test must be run with -ea");
@@ -278,37 +397,46 @@
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName on = new ObjectName("a:b=c");
- Descriptor expectedDescriptor = new ImmutableDescriptor(
- "foo=bar", "descriptionResourceBundleBaseName=bundle",
- "descriptionResourceKey=key");
- MBeanNotificationInfo expected = new MBeanNotificationInfo(
- new String[] {"foo", "bar"},
- AttributeChangeNotification.class.getName(),
- "description",
- expectedDescriptor);
-
System.out.println("Testing MBeans...");
for (Field mbeanField :
AnnotatedNotificationInfoTest.class.getDeclaredFields()) {
- if (!mbeanField.getName().startsWith("mbean"))
+ boolean notifier;
+ if (mbeanField.getName().startsWith("mbean"))
+ notifier = true;
+ else if (mbeanField.getName().startsWith("ignoredMBean"))
+ notifier = false;
+ else
continue;
System.out.println("..." + mbeanField.getName());
Object mbean = mbeanField.get(null);
mbs.registerMBean(mbean, on);
MBeanInfo mbi = mbs.getMBeanInfo(on);
MBeanNotificationInfo[] mbnis = mbi.getNotifications();
- assert mbnis.length == 1 : mbnis.length;
- assert mbnis[0].equals(expected) : mbnis[0];
+ if (notifier) {
+ assert mbnis.length == 1 : mbnis.length;
+ assert mbnis[0].equals(expected) : mbnis[0];
+ } else {
+ assert mbnis.length == 0 : mbnis.length;
+ assert !mbs.isInstanceOf(on, NotificationBroadcaster.class.getName());
+ try {
+ mbs.addNotificationListener(on, nullListener, null, null);
+ assert false : "addNotificationListener works";
+ } catch (Exception e) {
+ // OK: addNL correctly refused
+ }
+ }
mbs.unregisterMBean(on);
}
- mbs.registerMBean(new Cache(), on);
- MBeanInfo mbi = mbs.getMBeanInfo(on);
- MBeanNotificationInfo[] mbnis = mbi.getNotifications();
- assert mbnis.length == 1 : mbnis.length;
- String[] types = mbnis[0].getNotifTypes();
- String[] expectedTypes =
- CacheMBean.class.getAnnotation(NotificationInfo.class).types();
- assert Arrays.equals(types, expectedTypes) : Arrays.toString(types);
+ // Test that inconsistent @NotificationInfo annotations produce an
+ // error.
+ try {
+ mbs.registerMBean(new Inconsistent(), on);
+ System.out.println(mbs.getMBeanInfo(on));
+ assert false : "Inconsistent @NotificationInfo not detected";
+ } catch (Exception e) {
+ System.out.println(
+ "Inconsistent @NotificationInfo correctly produced " + e);
+ }
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/Introspector/ExceptionsDescriptorTest.java Tue Dec 09 17:41:59 2008 +0100
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2008 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 6250014
+ * @summary Test that Exceptions are added to the MbeanInfo
+ * @author Jean-Francois Denise
+ * @run main/othervm ExceptionsDescriptorTest
+ */
+import java.lang.management.ManagementFactory;
+import java.util.HashSet;
+import java.util.Set;
+import javax.management.Descriptor;
+import javax.management.JMX;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.ObjectName;
+
+public class ExceptionsDescriptorTest {
+
+ private static final ObjectName OBJECT_NAME = ObjectName.valueOf(":type=Foo");
+ final static String EXCEPTION_NAME = Exception.class.getName();
+ final static String ILLEGAL_ARGUMENT_EXCEPTION_NAME =
+ IllegalArgumentException.class.getName();
+ final static Set<String> ONE_EXCEPTION = new HashSet<String>();
+ final static Set<String> TWO_EXCEPTION = new HashSet<String>();
+ static {
+ ONE_EXCEPTION.add(EXCEPTION_NAME);
+ TWO_EXCEPTION.add(EXCEPTION_NAME);
+ TWO_EXCEPTION.add(ILLEGAL_ARGUMENT_EXCEPTION_NAME);
+ }
+ public interface TestMBean {
+
+ public void doIt();
+
+ public void doIt(String str) throws Exception;
+
+ public void doIt(String str, boolean b) throws Exception,
+ IllegalArgumentException;
+
+ public String getThat();
+
+ public void setThat(String that);
+
+ public String getThe() throws Exception;
+
+ public void setThe(String the);
+
+ public String getThese();
+
+ public void setThese(String the) throws Exception;
+
+ public String getIt() throws Exception;
+
+ public void setIt(String str) throws Exception;
+
+ public String getThis() throws Exception, IllegalArgumentException;
+
+ public void setThose(String str) throws Exception,
+ IllegalArgumentException;
+ }
+
+ public static class Test implements TestMBean {
+
+ public Test() {
+ }
+
+ public Test(int i) throws Exception {
+ }
+
+ public Test(int i, int j) throws Exception, IllegalArgumentException {
+ }
+
+ public void doIt() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void doIt(String str) throws Exception {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void doIt(String str, boolean b) throws Exception, IllegalArgumentException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public String getThat() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setThat(String that) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public String getThe() throws Exception {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setThe(String the) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public String getThese() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setThese(String the) throws Exception {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public String getIt() throws Exception {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setIt(String str) throws Exception {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public String getThis() throws Exception, IllegalArgumentException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setThose(String str) throws Exception, IllegalArgumentException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+
+ private static void check(Descriptor d,
+ Set<String> exceptionsExpectedValue,
+ boolean exceptionsExpected,
+ Set<String> setExceptionsExpectedValue,
+ boolean setExceptionsExpected) throws Exception {
+ String[] exceptionsValues = (String[]) d.getFieldValue(JMX.EXCEPTIONS_FIELD);
+ String[] setExceptionsValues = (String[]) d.getFieldValue(JMX.SET_EXCEPTIONS_FIELD);
+
+ if (exceptionsExpected && exceptionsValues == null) {
+ throw new Exception("exceptions is expected but null value");
+ }
+ if (!exceptionsExpected && exceptionsValues != null) {
+ throw new Exception("exceptions is not expected but non null value");
+ }
+ if (setExceptionsExpected && setExceptionsValues == null) {
+ throw new Exception("setExceptions is expected but null value");
+ }
+ if (!setExceptionsExpected && setExceptionsValues != null) {
+ throw new Exception("setExceptions is not expected but non null value");
+ }
+
+ if (exceptionsExpected) {
+ checkValues(exceptionsExpectedValue, exceptionsValues);
+ }
+ if (setExceptionsExpected) {
+ checkValues(setExceptionsExpectedValue, setExceptionsValues);
+ }
+ }
+
+ private static void checkValues(Set<String> expectedValuesSet,
+ String[] realValues) throws Exception {
+
+ Set<String> realValuesSet = new HashSet<String>();
+ for (String ex : realValues) {
+ realValuesSet.add(ex);
+ }
+ if (!realValuesSet.equals(expectedValuesSet)) {
+ throw new Exception("Invalid content for exceptions. Was expecting " +
+ expectedValuesSet + ". Found " + realValuesSet);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ Test t = new Test();
+ ManagementFactory.getPlatformMBeanServer().registerMBean(t, OBJECT_NAME);
+ MBeanInfo info = ManagementFactory.getPlatformMBeanServer().
+ getMBeanInfo(OBJECT_NAME);
+ //Constructors
+ for (MBeanConstructorInfo ctr : info.getConstructors()) {
+ if (ctr.getSignature().length == 0) {
+ check(ctr.getDescriptor(), null, false, null, false);
+ }
+ if (ctr.getSignature().length == 1) {
+ check(ctr.getDescriptor(), ONE_EXCEPTION, true, null, false);
+ }
+ if (ctr.getSignature().length == 2) {
+ check(ctr.getDescriptor(),TWO_EXCEPTION,true, null, false);
+ }
+ }
+ //Attributes
+ for (MBeanAttributeInfo attr : info.getAttributes()) {
+ if (attr.getName().equals("That")) {
+ check(attr.getDescriptor(), null, false, null, false);
+ }
+ if (attr.getName().equals("The")) {
+ check(attr.getDescriptor(), ONE_EXCEPTION,true,null, false);
+ }
+ if (attr.getName().equals("These")) {
+ check(attr.getDescriptor(), null, false, ONE_EXCEPTION,true);
+ }
+ if (attr.getName().equals("It")) {
+ check(attr.getDescriptor(), ONE_EXCEPTION,true,ONE_EXCEPTION,
+ true);
+ }
+ if (attr.getName().equals("This")) {
+ check(attr.getDescriptor(), TWO_EXCEPTION,true,null,false);
+ }
+ if (attr.getName().equals("Those")) {
+ check(attr.getDescriptor(), null,false,TWO_EXCEPTION,true);
+ }
+ }
+ //Operations
+ for (MBeanOperationInfo oper : info.getOperations()) {
+ if (oper.getSignature().length == 0) {
+ check(oper.getDescriptor(), null, false, null, false);
+ }
+ if (oper.getSignature().length == 1) {
+ check(oper.getDescriptor(), ONE_EXCEPTION, true, null, false);
+ }
+ if (oper.getSignature().length == 2) {
+ check(oper.getDescriptor(), TWO_EXCEPTION,true, null, false);
+ }
+ }
+ System.out.println("Test passed");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/Introspector/ObjectNameTemplateTest.java Tue Dec 09 17:41:59 2008 +0100
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2008 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 6675526
+ * @summary Test MBeans named with @ObjectNameTemplate
+ * @author Jean-Francois Denise
+ * @run main/othervm ObjectNameTemplateTest
+ */
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.ImmutableDescriptor;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMX;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.MXBean;
+import javax.management.MBean;
+import javax.management.ManagedAttribute;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+import javax.management.ObjectNameTemplate;
+import javax.management.ReflectionException;
+import javax.management.StandardMBean;
+
+public class ObjectNameTemplateTest {
+
+ private static MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ private static final String NAME_TEMPLATE_MULTI =
+ "com.example:type=MultiStdCache,name={Name}";
+ private static final String NAME_TEMPLATE_MONO =
+ "com.example:{Type}={TypeValue}";
+ private static final String NAME_TEMPLATE_QUOTED =
+ "com.example:type=Quotted,name=\"{Name}\"";
+ private static final String NAME_TEMPLATE_WRAPPED =
+ "com.example:type=MgtInterface,id={Id}";
+ private static final String NAME_TEMPLATE_FULL =
+ "{Naming}";
+ private static final String FULL_NAME = "com.example:type=NotAdvised";
+ private static final String NAME1 = "toto1";
+ private static final String NAME2 = "toto2";
+ private static final String TYPE_KEY = "thisIsTheType";
+ private static final String TYPE_VALUE = "aTypeValue";
+ private static final String INVALID_NAME = "?,=*,\n, ";
+ private static final int ID = 999;
+ private static Object[] EMPTY_PARAMS = {};
+ private static String[] EMPTY_SIGNATURE = {};
+ private static final ObjectName OBJECTNAME_CACHE =
+ ObjectName.valueOf("com.example:type=Cache");
+ private static final ObjectName OBJECTNAME_SUBCACHE =
+ ObjectName.valueOf("com.example:type=SubCache");
+ private static final ObjectName OBJECTNAME_CACHEMX =
+ ObjectName.valueOf("com.example:type=CacheMX");
+ private static final ObjectName OBJECTNAME_SUBCACHEMX =
+ ObjectName.valueOf("com.example:type=SubCacheMX");
+ private static final ObjectName OBJECTNAME_DYNACACHE =
+ ObjectName.valueOf("com.example:type=DynaCache");
+ private static final ObjectName OBJECTNAME_STDCACHE =
+ ObjectName.valueOf("com.example:type=StdCache");
+ private static final ObjectName OBJECTNAME_STDCACHEMX =
+ ObjectName.valueOf("com.example:type=StdCacheMX");
+ private static final ObjectName OBJECTNAME_MULTI_1 =
+ ObjectName.valueOf("com.example:" +
+ "type=MultiStdCache,name=" + NAME1);
+ private static final ObjectName OBJECTNAME_MULTI_2 =
+ ObjectName.valueOf("com.example:" +
+ "type=MultiStdCache,name=" + NAME2);
+ private static final ObjectName OBJECTNAME_MONO =
+ ObjectName.valueOf("com.example:" + TYPE_KEY + "=" +
+ TYPE_VALUE);
+ private static final ObjectName OBJECTNAME_QUOTED =
+ ObjectName.valueOf("com.example:type=Quotted," +
+ "name="+ObjectName.quote(INVALID_NAME));
+ private static final ObjectName OBJECTNAME_WRAPPED_RESOURCE =
+ ObjectName.valueOf("com.example:type=MgtInterface,id=" + ID);
+ private static final ObjectName OBJECTNAME_FULL =
+ ObjectName.valueOf(FULL_NAME);
+
+ private static void test(Class<?> mbean, Object[] params,
+ String[] signature, ObjectName name, String template)
+ throws Exception {
+ mbs.createMBean(mbean.getName(), null, params, signature);
+ test(name, template);
+ List<Class<?>> parameters = new ArrayList<Class<?>>();
+ for (String sig : signature) {
+ parameters.add(Class.forName(sig));
+ }
+ Class<?> classes[] = new Class<?>[parameters.size()];
+ Constructor ctr = mbean.getConstructor(parameters.toArray(classes));
+ Object inst = ctr.newInstance(params);
+ test(inst, name, template);
+ }
+
+ private static void test(Object obj, ObjectName name, String template)
+ throws Exception {
+ mbs.registerMBean(obj, null);
+ test(name, template);
+ }
+
+ private static void test(ObjectName name, String template)
+ throws Exception {
+ if (!mbs.isRegistered(name)) {
+ throw new Exception("Wrong " + name + " name");
+ }
+ if (template != null && !mbs.getMBeanInfo(name).getDescriptor().
+ getFieldValue("objectNameTemplate").equals(template)) {
+ throw new Exception("Invalid Derscriptor");
+ }
+ mbs.unregisterMBean(name);
+ }
+
+ public static void main(String[] args) throws Exception {
+ test(Cache.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_CACHE,
+ OBJECTNAME_CACHE.toString());
+
+ test(CacheMX.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_CACHEMX,
+ OBJECTNAME_CACHEMX.toString());
+
+ test(SubCache.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_SUBCACHE,
+ OBJECTNAME_SUBCACHE.toString());
+
+ test(SubCacheMX.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_SUBCACHEMX,
+ OBJECTNAME_SUBCACHEMX.toString());
+
+ test(DynaCache.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_DYNACACHE,
+ null);
+
+ test(StdCacheMX.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_STDCACHEMX,
+ OBJECTNAME_STDCACHEMX.toString());
+
+ test(StdCache.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_STDCACHE,
+ OBJECTNAME_STDCACHE.toString());
+ String[] sig = {String.class.getName()};
+ Object[] params = {NAME1};
+ test(MultiStdCache.class, params, sig, OBJECTNAME_MULTI_1,
+ NAME_TEMPLATE_MULTI);
+ Object[] params2 = {NAME2};
+ test(MultiStdCache.class, params2, sig, OBJECTNAME_MULTI_2,
+ NAME_TEMPLATE_MULTI);
+
+ test(MonoStdCache.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_MONO,
+ NAME_TEMPLATE_MONO);
+
+ test(Quoted.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_QUOTED,
+ NAME_TEMPLATE_QUOTED);
+
+ test(new StandardMBean(new WrappedResource(), MgtInterface.class),
+ OBJECTNAME_WRAPPED_RESOURCE, NAME_TEMPLATE_WRAPPED);
+
+ test(FullName.class, EMPTY_PARAMS, EMPTY_SIGNATURE, OBJECTNAME_FULL,
+ NAME_TEMPLATE_FULL);
+ try {
+ test(Wrong.class, EMPTY_PARAMS, EMPTY_SIGNATURE, null, null);
+ throw new Exception("No treceived expected Exception");
+ } catch (NotCompliantMBeanException ncex) {
+ if (!(ncex.getCause() instanceof AttributeNotFoundException)) {
+ throw new Exception("Invalid initCause");
+ }
+ }
+ }
+
+ @MBean
+ @ObjectNameTemplate("{Naming}")
+ public static class FullName {
+
+ @ManagedAttribute
+ public String getNaming() {
+ return FULL_NAME;
+ }
+ }
+
+ @ObjectNameTemplate("com.example:type=MgtInterface,id={Id}")
+ public interface MgtInterface {
+
+ public int getId();
+ }
+
+ public static class WrappedResource implements MgtInterface {
+
+ public int getId() {
+ return ID;
+ }
+ }
+
+ @MBean
+ @ObjectNameTemplate("com.example:type=Cache")
+ public static class Cache {
+ }
+
+ @ObjectNameTemplate("com.example:type=SubCache")
+ public static class SubCache extends Cache {
+ }
+
+ @MXBean
+ @ObjectNameTemplate("com.example:type=CacheMX")
+ public static class CacheMX {
+ }
+
+ @ObjectNameTemplate("com.example:type=SubCacheMX")
+ public static class SubCacheMX extends CacheMX {
+ }
+
+ @ObjectNameTemplate("com.example:type=StdCache")
+ public interface StdCacheMBean {
+ }
+
+ public static class StdCache implements StdCacheMBean {
+ }
+
+ @ObjectNameTemplate("com.example:type=StdCacheMX")
+ public interface StdCacheMXBean {
+ }
+
+ public static class StdCacheMX implements StdCacheMXBean {
+ }
+
+ public static class DynaCache implements DynamicMBean {
+
+ public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public AttributeList getAttributes(String[] attributes) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public AttributeList setAttributes(AttributeList attributes) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public MBeanInfo getMBeanInfo() {
+ ImmutableDescriptor d = new ImmutableDescriptor(JMX.OBJECT_NAME_TEMPLATE + "=com.example:type=DynaCache");
+
+ return new MBeanInfo("DynaCache", "Description", null, null, null, null, d);
+ }
+ }
+
+ @ObjectNameTemplate("com.example:type=MultiStdCache,name={Name}")
+ public interface MultiStdCacheMXBean {
+
+ public String getName();
+ }
+
+ public static class MultiStdCache implements MultiStdCacheMXBean {
+
+ private String name;
+
+ public MultiStdCache(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ @ObjectNameTemplate("com.example:{Type}={TypeValue}")
+ public interface MonoStdCacheMXBean {
+
+ public String getTypeValue();
+
+ public String getType();
+ }
+
+ public static class MonoStdCache implements MonoStdCacheMXBean {
+
+ public String getTypeValue() {
+ return TYPE_VALUE;
+ }
+
+ public String getType() {
+ return TYPE_KEY;
+ }
+ }
+
+ @ObjectNameTemplate("com.example:type=Quotted,name=\"{Name}\"")
+ public interface QuottedMXBean {
+
+ public String getName();
+ }
+
+ public static class Quoted implements QuottedMXBean {
+
+ public String getName() {
+ return INVALID_NAME;
+ }
+ }
+
+ @ObjectNameTemplate("com.example:{Type}={TypeValue}, name={Name}")
+ public interface WrongMXBean {
+
+ public String getTypeValue();
+
+ public String getType();
+ }
+
+ public static class Wrong implements WrongMXBean {
+
+ public String getTypeValue() {
+ return TYPE_VALUE;
+ }
+
+ public String getType() {
+ return TYPE_KEY;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/descriptor/DescriptorConstructorTest.java Tue Dec 09 17:41:59 2008 +0100
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2004-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.
+ *
+ * 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
+ * @bug 6501362
+ * @summary DescriptorSupport(String) could recognize "name=value" as well as XML format
+ * @author Jean-Francois Denise
+ * @run clean DescriptorConstructorTest
+ * @run build DescriptorConstructorTest
+ * @run main DescriptorConstructorTest
+ */
+
+import javax.management.modelmbean.DescriptorSupport;
+
+public class DescriptorConstructorTest {
+ public static void main(String[] args) throws Exception {
+ DescriptorSupport d1 = new DescriptorSupport("MyName1=MyValue1");
+ if(!d1.getFieldValue("MyName1").equals("MyValue1"))
+ throw new Exception("Invalid parsing");
+ DescriptorSupport d2 = new DescriptorSupport("<Descriptor>" +
+ "<field name=\"MyName2\" value=\"MyValue2\"></field></Descriptor>");
+ if(!d2.getFieldValue("MyName2").equals("MyValue2"))
+ throw new Exception("Invalid parsing");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/monitor/InstantiateMonitorNotificationTest.java Tue Dec 09 17:41:59 2008 +0100
@@ -0,0 +1,52 @@
+
+import javax.management.ObjectName;
+import javax.management.monitor.MonitorNotification;
+
+/*
+ * Copyright 2008 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
+ * @bug 6373143
+ * @summary Test MonitorNotification public constructor
+ * @author JFDenise
+ * @run clean InstantiateMonitorNotificationTest
+ * @run build InstantiateMonitorNotificationTest
+ * @run main InstantiateMonitorNotificationTest
+ */
+
+public class InstantiateMonitorNotificationTest {
+
+ public static void main(String[] args) throws Exception {
+ MonitorNotification notif = new MonitorNotification("com.foo.test",
+ ObjectName.valueOf(":type=Monitor"),
+ 999,
+ 999,
+ "A message",
+ ObjectName.valueOf(":type=Observed"),
+ "MyAttribute",
+ Integer.valueOf(14),
+ Integer.valueOf(15));
+ System.out.println("Test passed");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/standardmbean/FindMethodTest.java Tue Dec 09 17:41:59 2008 +0100
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2008 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
+ * @bug 6287328
+ * @summary Add methods to StandardMBean to retrieve a method based on
+ * MBean{Attribute|Operation}Info
+ * @author Jean-Francois Denise
+ * @run main FindMethodTest
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.ThreadMXBean;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.management.MBean;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.MBeanServer;
+import javax.management.ManagedAttribute;
+import javax.management.ManagedOperation;
+import javax.management.ObjectName;
+import javax.management.StandardMBean;
+
+public class FindMethodTest {
+
+ private static MBeanServer server =
+ ManagementFactory.getPlatformMBeanServer();
+
+ private static Map<String, Set<Method>> expectedMapping =
+ new HashMap<String, Set<Method>>();
+ private static Set<Method> STATE_SET = new HashSet<Method>();
+ private static Set<Method> ENABLED_SET = new HashSet<Method>();
+ private static Set<Method> DOIT_SET = new HashSet<Method>();
+ private static Set<Method> STATUS_SET = new HashSet<Method>();
+ private static Set<Method> HEAPMEMORYUSAGE_SET = new HashSet<Method>();
+ private static Set<Method> THREADINFO_SET = new HashSet<Method>();
+ private static Set<Method> DOIT_ANNOTATED_SET = new HashSet<Method>();
+ private static Set<Method> IT_ANNOTATED_SET = new HashSet<Method>();
+ private static HashSet<Set<Method>> TEST_MBEAN_SET =
+ new HashSet<Set<Method>>();
+ private static HashSet<Set<Method>> ANNOTATED_MBEAN_SET =
+ new HashSet<Set<Method>>();
+ private static HashSet<Set<Method>> MEMORY_MBEAN_SET =
+ new HashSet<Set<Method>>();
+ private static HashSet<Set<Method>> THREAD_MBEAN_SET =
+ new HashSet<Set<Method>>();
+
+ public interface TestMBean {
+
+ public void doIt();
+
+ public void setState(String str);
+
+ public String getState();
+
+ public boolean isEnabled();
+
+ public void setStatus(int i);
+ }
+
+ public interface FaultyTestMBean {
+
+ public void doIt(String doIt);
+
+ public long getState();
+
+ public void setEnabled(boolean b);
+
+ public int getStatus();
+
+ public String setWrong(int i);
+ }
+
+ @MBean
+ public static class AnnotatedTest {
+ @ManagedOperation
+ public void doItAnnotated() {
+
+ }
+
+ public void dontDoIt() {
+
+ }
+
+ @ManagedAttribute
+ public String getItAnnotated() {
+ return null;
+ }
+ @ManagedAttribute
+ public void setItAnnotated(String str) {
+
+ }
+
+ public String getItNot() {
+ return null;
+ }
+
+ }
+
+ static class Test implements TestMBean {
+
+ public void doIt() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setState(String str) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public String getState() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public boolean isEnabled() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void setStatus(int i) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+
+
+ static {
+ try {
+ ENABLED_SET.add(TestMBean.class.getDeclaredMethod("isEnabled"));
+
+ STATE_SET.add(TestMBean.class.getDeclaredMethod("getState"));
+ STATE_SET.add(TestMBean.class.getDeclaredMethod("setState",
+ String.class));
+ STATUS_SET.add(TestMBean.class.getDeclaredMethod("setStatus",
+ int.class));
+
+ DOIT_SET.add(TestMBean.class.getDeclaredMethod("doIt"));
+
+ DOIT_ANNOTATED_SET.add(AnnotatedTest.class.getDeclaredMethod("doItAnnotated"));
+
+ IT_ANNOTATED_SET.add(AnnotatedTest.class.getDeclaredMethod("getItAnnotated"));
+ IT_ANNOTATED_SET.add(AnnotatedTest.class.getDeclaredMethod("setItAnnotated", String.class));
+
+ THREADINFO_SET.add(ThreadMXBean.class.getDeclaredMethod("dumpAllThreads", boolean.class,
+ boolean.class));
+
+ HEAPMEMORYUSAGE_SET.add(MemoryMXBean.class.getDeclaredMethod("getHeapMemoryUsage"));
+
+ TEST_MBEAN_SET.add(ENABLED_SET);
+ TEST_MBEAN_SET.add(STATE_SET);
+ TEST_MBEAN_SET.add(STATUS_SET);
+ TEST_MBEAN_SET.add(DOIT_SET);
+
+ ANNOTATED_MBEAN_SET.add(DOIT_ANNOTATED_SET);
+ ANNOTATED_MBEAN_SET.add(IT_ANNOTATED_SET);
+
+ MEMORY_MBEAN_SET.add(HEAPMEMORYUSAGE_SET);
+
+ THREAD_MBEAN_SET.add(THREADINFO_SET);
+
+ expectedMapping.put("State", STATE_SET);
+ expectedMapping.put("Enabled", ENABLED_SET);
+ expectedMapping.put("Status", STATUS_SET);
+ expectedMapping.put("doIt", DOIT_SET);
+ expectedMapping.put("HeapMemoryUsage", HEAPMEMORYUSAGE_SET);
+ expectedMapping.put("dumpAllThreads", THREADINFO_SET);
+ expectedMapping.put("doItAnnotated", DOIT_ANNOTATED_SET);
+ expectedMapping.put("ItAnnotated", IT_ANNOTATED_SET);
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ throw new RuntimeException("Initialization failed");
+ }
+ }
+
+ private static void testMBean(ObjectName name, Class<?> itf,
+ HashSet<Set<Method>> expectMappings)
+ throws Exception {
+
+ Set<Set<Method>> expectedMappings =
+ (Set<Set<Method>>) expectMappings.clone();
+
+ MBeanInfo info = server.getMBeanInfo(name);
+ for (MBeanAttributeInfo attr : info.getAttributes()) {
+ Set<Method> expected = expectedMapping.get(attr.getName());
+ if (expected == null) {
+ continue;
+ }
+ if (!expectedMappings.remove(expected)) {
+ throw new Exception("The mapping to use is not the expected " +
+ "one for " + attr);
+ }
+ System.out.println("Expected : " + expected);
+ Set<Method> found =
+ StandardMBean.findAttributeAccessors(itf, attr);
+ System.out.println("Found : " + found);
+ if (!found.equals(expected)) {
+ throw new Exception("Mapping error.");
+ }
+ }
+ for (MBeanOperationInfo op : info.getOperations()) {
+ Set<Method> expected = expectedMapping.get(op.getName());
+ if (expected == null) {
+ continue;
+ }
+ if (!expectedMappings.remove(expected)) {
+ throw new Exception("The mapping to use is not the expected " +
+ "one for " + op);
+ }
+ System.out.println("Expected : " + expected);
+ Method method =
+ StandardMBean.findOperationMethod(itf, op);
+ Set<Method> found = new HashSet<Method>();
+ found.add(method);
+ System.out.println("Found : " + found);
+ if (!found.equals(expected)) {
+ throw new Exception("Mapping error.");
+ }
+ }
+
+ if (expectedMappings.size() != 0) {
+ throw new Exception("Some mapping have not been found " +
+ expectedMappings);
+ } else {
+ System.out.println("All mappings have been found");
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ // Positive tests
+ Test t = new Test();
+ ObjectName name = ObjectName.valueOf(":type=Test");
+ server.registerMBean(t, name);
+ AnnotatedTest at = new AnnotatedTest();
+ ObjectName annotatedName = ObjectName.valueOf(":type=AnnotatedTest");
+ server.registerMBean(at, annotatedName);
+
+ testMBean(name, TestMBean.class, TEST_MBEAN_SET);
+
+ testMBean(annotatedName, AnnotatedTest.class, ANNOTATED_MBEAN_SET);
+
+ ObjectName memoryName =
+ ObjectName.valueOf(ManagementFactory.MEMORY_MXBEAN_NAME);
+ testMBean(memoryName, MemoryMXBean.class, MEMORY_MBEAN_SET);
+
+ ObjectName threadName =
+ ObjectName.valueOf(ManagementFactory.THREAD_MXBEAN_NAME);
+ testMBean(threadName, ThreadMXBean.class, THREAD_MBEAN_SET);
+
+ // Negative tests
+ try {
+ StandardMBean.findOperationMethod(null,
+ new MBeanOperationInfo("Test",
+ TestMBean.class.getDeclaredMethod("doIt")));
+ throw new Exception("Expected exception not found");
+ } catch (IllegalArgumentException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ try {
+ StandardMBean.findOperationMethod(TestMBean.class, null);
+ throw new Exception("Expected exception not found");
+ } catch (IllegalArgumentException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ try {
+ StandardMBean.findAttributeAccessors(null,
+ new MBeanAttributeInfo("Test", "Test",
+ TestMBean.class.getDeclaredMethod("getState"),
+ TestMBean.class.getDeclaredMethod("setState",
+ String.class)));
+ throw new Exception("Expected exception not found");
+ } catch (IllegalArgumentException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ try {
+ StandardMBean.findAttributeAccessors(TestMBean.class, null);
+ throw new Exception("Expected exception not found");
+ } catch (IllegalArgumentException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ //Wrong operation signature
+ try {
+ StandardMBean.findOperationMethod(TestMBean.class,
+ new MBeanOperationInfo("FaultyTest",
+ FaultyTestMBean.class.getDeclaredMethod("doIt",
+ String.class)));
+ throw new Exception("Expected exception not found");
+ } catch (NoSuchMethodException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ //Wrong attribute accessor
+ try {
+ StandardMBean.findAttributeAccessors(TestMBean.class,
+ new MBeanAttributeInfo("FaultyTest", "FaultyTest", null,
+ FaultyTestMBean.class.getDeclaredMethod("setEnabled",
+ String.class)));
+ throw new Exception("Expected exception not found");
+ } catch (NoSuchMethodException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ //Wrong attribute type
+ try {
+ StandardMBean.findAttributeAccessors(TestMBean.class,
+ new MBeanAttributeInfo("State", "toto.FaultType",
+ "FaultyTest", true, true, false));
+ throw new Exception("Expected exception not found");
+ } catch (ClassNotFoundException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ //Wrong operation parameter type
+ try {
+ MBeanParameterInfo[] p = {new MBeanParameterInfo("p1",
+ "toto.FaultType2", "FaultyParameter")
+ };
+ StandardMBean.findOperationMethod(TestMBean.class,
+ new MBeanOperationInfo("doIt", "FaultyMethod", p, "void",
+ 0));
+ throw new Exception("Expected exception not found");
+ } catch (ClassNotFoundException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ // Check that not annotated attributes are not found
+ try {
+ StandardMBean.findAttributeAccessors(AnnotatedTest.class,
+ new MBeanAttributeInfo("ItNot", String.class.getName(),
+ "FaultyTest", true, false, false));
+ throw new Exception("Expected exception not found");
+ } catch (NoSuchMethodException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ // Check that not annotated operations are not found
+ try {
+ StandardMBean.findOperationMethod(AnnotatedTest.class,
+ new MBeanOperationInfo("dontDoIt","dontDoIt",null,
+ Void.TYPE.getName(),0));
+ throw new Exception("Expected exception not found");
+ } catch (NoSuchMethodException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ // Check that wrong getter return type throws Exception
+ try {
+ StandardMBean.findAttributeAccessors(AnnotatedTest.class,
+ new MBeanAttributeInfo("ItAnnotated", Long.class.getName(),
+ "FaultyTest", true, false, false));
+ throw new Exception("Expected exception not found");
+ } catch (NoSuchMethodException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ // Check that wrong setter return type throws Exception
+ try {
+ StandardMBean.findAttributeAccessors(FaultyTestMBean.class,
+ new MBeanAttributeInfo("Wrong", String.class.getName(),
+ "FaultyTest", true, true, false));
+ throw new Exception("Expected exception not found");
+ } catch (NoSuchMethodException ex) {
+ System.out.println("OK received expected exception " + ex);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/standardmbean/RegistrationTest.java Tue Dec 09 17:41:59 2008 +0100
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2008 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
+ * @bug 6450834
+ * @summary Forward MBeanRegistration calls
+ * @author JF Denise
+ * @run main RegistrationTest
+ */
+
+import java.io.Serializable;
+import java.lang.management.ManagementFactory;
+import javax.management.*;
+
+public class RegistrationTest {
+ static boolean preRegisterCalled;
+ static boolean postRegisterCalled;
+ static boolean preDeregisterCalled;
+ static boolean postDeregisterCalled;
+
+ static void checkResult(boolean expected) throws Exception {
+ if((preRegisterCalled != expected ||
+ postRegisterCalled != expected ||
+ preDeregisterCalled != expected ||
+ postDeregisterCalled != expected))
+ throw new Exception("Mismatch preRegisterCalled = "
+ + preRegisterCalled + ", postRegisterCalled = "
+ + postRegisterCalled + ", preDeregisterCalled = "
+ + preDeregisterCalled + ", postDeregisterCalled = "
+ + postDeregisterCalled);
+ }
+ static class Wrapped implements MBeanRegistration,Serializable {
+
+ public ObjectName preRegister(MBeanServer server, ObjectName name)
+ throws Exception {
+ preRegisterCalled = true;
+ return name;
+ }
+
+ public void postRegister(Boolean registrationDone) {
+ postRegisterCalled = true;
+ }
+
+ public void preDeregister() throws Exception {
+ preDeregisterCalled = true;
+ }
+
+ public void postDeregister() {
+ postDeregisterCalled = true;
+ }
+
+ }
+
+ public static void main(String[] args) throws Exception {
+ StandardMBean std = new StandardMBean(new Wrapped(),
+ Serializable.class);
+ ObjectName name = ObjectName.valueOf(":type=Test");
+ ManagementFactory.getPlatformMBeanServer().registerMBean(std,name);
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(name);
+ checkResult(false);
+ StandardMBean.Options opt = new StandardMBean.Options();
+ opt.setMBeanRegistrationForwarded(true);
+ std = new StandardMBean(new Wrapped(),
+ Serializable.class, opt );
+ ManagementFactory.getPlatformMBeanServer().registerMBean(std,name);
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(name);
+ checkResult(true);
+ System.out.println("Test OK");
+ }
+}