changeset 743:0dc9fc01e5d6

Merge
author sjiang
date Tue, 09 Dec 2008 18:45:09 +0100
parents 23738109351f 0b1c7f982cc0
children 4951fee90769
files
diffstat 30 files changed, 1977 insertions(+), 100 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Tue Dec 09 18:42:13 2008 +0100
+++ b/src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/src/share/classes/com/sun/jmx/mbeanserver/MBeanInjector.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java	Tue Dec 09 18:45:09 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.
      **/
@@ -636,7 +645,7 @@
             }
         } catch (ClassNotFoundException e) {
             throw new ReflectionException(e,
-            "The MBean class could not be loaded by the context classloader");
+            "The MBean class could not be loaded");
         }
         return theClass;
     }
--- a/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java	Tue Dec 09 18:42:13 2008 +0100
+++ b/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java	Tue Dec 09 18:45:09 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/javax/management/Descriptor.java	Tue Dec 09 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/Descriptor.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/JMX.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/MBeanAttributeInfo.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/MBeanConstructorInfo.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/MBeanOperationInfo.java	Tue Dec 09 18:45:09 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/MBeanRegistration.java	Tue Dec 09 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/MBeanRegistration.java	Tue Dec 09 18:45:09 2008 +0100
@@ -79,6 +79,9 @@
  * }
  * </pre>
  *
+ * <p>(Listeners may be invoked in the same thread as the caller of
+ * {@code sender.sendNotification}.)</p>
+ *
  * <p>A field to be injected must not be static.  It is recommended that
  * such fields be declared {@code volatile}.</p>
  *
--- a/src/share/classes/javax/management/MBeanServer.java	Tue Dec 09 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/MBeanServer.java	Tue Dec 09 18:45:09 2008 +0100
@@ -186,11 +186,11 @@
  * caller's permissions must imply {@link
  * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
  * MBeanPermission(mbeanServerName, null, null, null, "queryMBeans")}.
- * Additionally, for each MBean that matches <code>name</code>,
+ * Additionally, for each MBean <em>n</em> that matches <code>name</code>,
  * if the caller's permissions do not imply {@link
  * MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
- * MBeanPermission(mbeanServerName, className, null, name, "queryMBeans")}, the
- * MBean server will behave as if that MBean did not exist.</p>
+ * MBeanPermission(mbeanServerName, className, null, <em>n</em>, "queryMBeans")},
+ * the MBean server will behave as if that MBean did not exist.</p>
  *
  * <p>Certain query elements perform operations on the MBean server.
  * If the caller does not have the required permissions for a given
@@ -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 &#64;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 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/MBeanServerConnection.java	Tue Dec 09 18:45:09 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 &#64;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 &#64;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 &#64;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 &#64;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/NotificationInfo.java	Tue Dec 09 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/NotificationInfo.java	Tue Dec 09 18:45:09 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 18:45:09 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 &#64;MBean}</code>
+ * annotation.</li>
+ *   <li>Java class annotated with {@link javax.management.MXBean &#64;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 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/StandardMBean.java	Tue Dec 09 18:45:09 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 &#64;MBean} or {@link MXBean &#64;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 &#64;MBean} or {@link MXBean &#64;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/event/EventClient.java	Tue Dec 09 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/event/EventClient.java	Tue Dec 09 18:45:09 2008 +0100
@@ -187,9 +187,10 @@
      * forwarded by the {@link EventClientDelegateMBean}. If {@code null}, a
      * {@link FetchingEventRelay} object will be used.
      * @param distributingExecutor Used to distribute notifications to local
-     * listeners. If {@code null}, the thread that calls {@link
-     * EventReceiver#receive EventReceiver.receive} from the {@link EventRelay}
-     * object is used.
+     * listeners. Only one job at a time will be submitted to this Executor.
+     * If {@code distributingExecutor} is {@code null}, the thread that calls
+     * {@link EventReceiver#receive EventReceiver.receive} from the {@link
+     * EventRelay} object is used.
      * @param leaseScheduler An object that will be used to schedule the
      * periodic {@linkplain EventClientDelegateMBean#lease lease updates}.
      * If {@code null}, a default scheduler will be used.
@@ -545,7 +546,7 @@
      *
      * <P>The method returns the listeners which were added successfully. The
      * elements in the returned collection are a subset of the elements in
-     * {@code infoList}. If all listeners were added successfully, the two
+     * {@code listeners}. If all listeners were added successfully, the two
      * collections are the same. If no listener was added successfully, the
      * returned collection is empty.</p>
      *
--- a/src/share/classes/javax/management/event/FetchingEventRelay.java	Tue Dec 09 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/event/FetchingEventRelay.java	Tue Dec 09 18:45:09 2008 +0100
@@ -39,10 +39,18 @@
 import javax.management.remote.NotificationResult;
 
 /**
- * This class is an implementation of the {@link EventRelay} interface. It calls
+ * <p>This class is an implementation of the {@link EventRelay} interface. It calls
  * {@link EventClientDelegateMBean#fetchNotifications
  * fetchNotifications(String, long, int, long)} to get
- * notifications and then forwards them to an {@link EventReceiver} object.
+ * notifications and then forwards them to an {@link EventReceiver} object.</p>
+ *
+ * <p>A {@code fetchExecutor} parameter can be specified when creating a
+ * {@code FetchingEventRelay}.  That is then the {@code Executor} that will
+ * be used to perform the {@code fetchNotifications} operation.  Only one
+ * job at a time will be submitted to this {@code Executor}.  The behavior
+ * is unspecified if {@link Executor#execute} throws an exception, including
+ * {@link java.util.concurrent.RejectedExecutionException
+ * RejectedExecutionException}.
  *
  * @since JMX 2.0
  */
--- a/src/share/classes/javax/management/loading/MLet.java	Tue Dec 09 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/loading/MLet.java	Tue Dec 09 18:45:09 2008 +0100
@@ -1165,9 +1165,10 @@
                      file.deleteOnExit();
                      FileOutputStream fileOutput = new FileOutputStream(file);
                      try {
-                         int c;
-                         while ((c = is.read()) != -1) {
-                             fileOutput.write(c);
+                         byte[] buf = new byte[4096];
+                         int n;
+                         while ((n = is.read(buf)) >= 0) {
+                            fileOutput.write(buf, 0, n);
                          }
                      } finally {
                          fileOutput.close();
--- a/src/share/classes/javax/management/modelmbean/DescriptorSupport.java	Tue Dec 09 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/modelmbean/DescriptorSupport.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/src/share/classes/javax/management/monitor/MonitorNotification.java	Tue Dec 09 18:45:09 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 18:42:13 2008 +0100
+++ b/test/javax/management/Introspector/AnnotatedNotificationInfoTest.java	Tue Dec 09 18:45:09 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 18:45:09 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 18:45:09 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 &#64;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 18:45:09 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 18:45:09 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 18:45:09 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 18:45:09 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");
+    }
+}