OpenJDK / bsd-port / jdk9 / jdk
changeset 740:30239cf868b0
Merge
author | sjiang |
---|---|
date | Tue, 09 Dec 2008 17:41:59 +0100 |
parents | 6eec8be80bfe 3d822c99e3ab |
children | 0b1c7f982cc0 |
files | |
diffstat | 33 files changed, 2073 insertions(+), 134 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Tue Dec 09 17:41:04 2008 +0100 +++ b/.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/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/servicetag/Installer.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/servicetag/SolarisSystemEnvironment.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/servicetag/SunConnection.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/servicetag/Util.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/com/sun/servicetag/WindowsSystemEnvironment.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/Descriptor.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/JMX.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/MBeanAttributeInfo.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/MBeanConstructorInfo.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/MBeanOperationInfo.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/MBeanServer.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/MBeanServerConnection.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/MBeanServerNotification.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/NotificationInfo.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/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/src/share/classes/javax/management/StandardMBean.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/modelmbean/DescriptorSupport.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/src/share/classes/javax/management/monitor/MonitorNotification.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/test/javax/management/Introspector/AnnotatedNotificationInfoTest.java Tue Dec 09 17:41:04 2008 +0100 +++ b/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/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/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/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/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/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/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"); + } +}