changeset 406:afa8b71365aa

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