jdk/test/javax/management/MBeanServer/DynamicWrapperMBeanTest.java
changeset 1636 eb801ce73ac9
parent 1247 b4c26443dee5
--- a/jdk/test/javax/management/MBeanServer/DynamicWrapperMBeanTest.java	Wed Nov 26 15:37:14 2008 +0000
+++ b/jdk/test/javax/management/MBeanServer/DynamicWrapperMBeanTest.java	Thu Nov 27 15:44:32 2008 +0100
@@ -23,14 +23,27 @@
 
 /*
  * @test DynamicWrapperMBeanTest
- * @bug 6624232
+ * @bug 6624232 6776225
  * @summary Test the DynamicWrapperMBean interface
  * @author Eamonn McManus
  */
 
 import java.lang.management.ManagementFactory;
+import javax.annotation.Resource;
+import javax.management.JMX;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
 import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationInfo;
+import javax.management.NotificationListener;
 import javax.management.ObjectName;
+import javax.management.SendNotification;
+import javax.management.StandardEmitterMBean;
 import javax.management.StandardMBean;
 import javax.management.modelmbean.ModelMBeanInfo;
 import javax.management.modelmbean.ModelMBeanInfoSupport;
@@ -39,6 +52,25 @@
 import static javax.management.StandardMBean.Options;
 
 public class DynamicWrapperMBeanTest {
+    private static String failure;
+
+    public static void main(String[] args) throws Exception {
+        wrapTest();
+        notifTest();
+
+        if (failure == null)
+            System.out.println("TEST PASSED");
+        else
+            throw new Exception("TEST FAILED: " + failure);
+    }
+
+    private static final Options wrappedVisOpts = new Options();
+    private static final Options wrappedInvisOpts = new Options();
+    static {
+        wrappedVisOpts.setWrappedObjectVisible(true);
+        wrappedInvisOpts.setWrappedObjectVisible(false);
+    }
+
     public static interface WrappedMBean {
         public void sayHello();
     }
@@ -48,19 +80,13 @@
         }
     }
 
-    private static String failure;
-
-    public static void main(String[] args) throws Exception {
+    private static void wrapTest() throws Exception {
         if (Wrapped.class.getClassLoader() ==
                 StandardMBean.class.getClassLoader()) {
             throw new Exception(
                     "TEST ERROR: Resource and StandardMBean have same ClassLoader");
         }
 
-        Options wrappedVisOpts = new Options();
-        wrappedVisOpts.setWrappedObjectVisible(true);
-        Options wrappedInvisOpts = new Options();
-        wrappedInvisOpts.setWrappedObjectVisible(false);
         assertEquals("Options withWrappedObjectVisible(false)",
                      new Options(), wrappedInvisOpts);
 
@@ -138,8 +164,223 @@
         assertEquals("isInstanceOf(RequiredModelMBean) for invisible resource",
                 true, mbs.isInstanceOf(invisibleName, RequiredModelMBean.class.getName()));
 
-        if (failure != null)
-            throw new Exception("TEST FAILED: " + failure);
+        mbs.unregisterMBean(visibleName);
+        mbs.unregisterMBean(invisibleName);
+    }
+
+    private static enum WrapType {
+        NBS("NotificationBroadcasterSupport"),
+        INJ("@Resource SendNotification"),
+        STD_MBEAN_NBS("StandardMBean delegating to NotificationBroadcasterSupport"),
+        STD_MBEAN_INJ("StandardMBean delegating to @Resource SendNotification"),
+        STD_MBEAN_SUB_NBS("StandardMBean subclass implementing NotificationBroadcaster"),
+        STD_MBEAN_SUB_INJ("StandardMBean subclass with @Resource SendNotification"),
+        STD_EMIT_MBEAN_NBS("StandardEmitterMBean delegating to NotificationBroadcasterSupport"),
+        STD_EMIT_MBEAN_INJ("StandardEmitterMBean delegating to @Resource SendNotification"),
+        STD_EMIT_MBEAN_SUB("StandardEmitterMBean subclass"),
+        STD_EMIT_MBEAN_SUB_INJ("StandardEmitterMBean subclass with @Resource SendNotification");
+
+        WrapType(String s) {
+            this.s = s;
+        }
+
+        @Override
+        public String toString() {
+            return s;
+        }
+
+        private final String s;
+    }
+
+    @NotificationInfo(
+        types = {"foo", "bar"}
+    )
+    public static interface BroadcasterMBean {
+        public void send(Notification n);
+    }
+
+    public static class Broadcaster
+            extends NotificationBroadcasterSupport implements BroadcasterMBean {
+        public void send(Notification n) {
+            super.sendNotification(n);
+        }
+    }
+
+    public static interface SendNotifMBean extends BroadcasterMBean {
+    }
+
+    public static class SendNotif implements SendNotifMBean {
+        @Resource
+        private volatile SendNotification sendNotif;
+
+        public void send(Notification n) {
+            sendNotif.sendNotification(n);
+        }
+    }
+
+    public static class StdBroadcaster
+            extends StandardMBean
+            implements BroadcasterMBean, NotificationBroadcaster {
+        private final NotificationBroadcasterSupport nbs =
+                new NotificationBroadcasterSupport();
+
+        public StdBroadcaster() throws Exception {
+            super(BroadcasterMBean.class);
+        }
+
+        public void send(Notification n) {
+            nbs.sendNotification(n);
+        }
+
+        public void addNotificationListener(NotificationListener listener,
+                NotificationFilter filter, Object handback) {
+            nbs.addNotificationListener(listener, filter, handback);
+        }
+
+        public MBeanNotificationInfo[] getNotificationInfo() {
+            return null;
+        }
+
+        public void removeNotificationListener(NotificationListener listener)
+                throws ListenerNotFoundException {
+            nbs.removeNotificationListener(listener);
+        }
+    }
+
+    public static class StdSendNotif
+            extends StandardMBean implements SendNotifMBean {
+        @Resource
+        private volatile SendNotification sendNotif;
+
+        public StdSendNotif() throws Exception {
+            super(SendNotifMBean.class);
+        }
+
+        public void send(Notification n) {
+            sendNotif.sendNotification(n);
+        }
+    }
+
+    public static class StdEmitterBroadcaster // :-)
+            extends StandardEmitterMBean
+            implements BroadcasterMBean {
+
+        public StdEmitterBroadcaster() throws Exception {
+            super(BroadcasterMBean.class, null);
+        }
+
+        public void send(Notification n) {
+            super.sendNotification(n);
+        }
+    }
+
+    // This case is unlikely - if you're using @Resource SendNotification
+    // then there's no point in using StandardEmitterMBean, since
+    // StandardMBean would suffice.
+    public static class StdEmitterSendNotif
+            extends StandardEmitterMBean implements SendNotifMBean {
+        @Resource
+        private volatile SendNotification sendNotif;
+
+        public StdEmitterSendNotif() {
+            super(SendNotifMBean.class, null);
+        }
+
+        public void send(Notification n) {
+            sendNotif.sendNotification(n);
+        }
+    }
+
+    // Test that JMX.isNotificationSource and
+    // mbs.isInstanceOf("NotificationBroadcaster") work correctly even when
+    // the MBean is a broadcaster by virtue of its wrapped resource.
+    // Test that we find the MBeanNotificationInfo[] from the @NotificationInfo
+    // annotation on BroadcasterMBean.  We cover a large number of different
+    // MBean types, but all ultimately implement that interface.
+    private static void notifTest() throws Exception {
+        System.out.println("===Testing notification senders===");
+
+        for (WrapType wrapType : WrapType.values()) {
+            System.out.println("---" + wrapType);
+
+            final Object mbean;
+
+            switch (wrapType) {
+            case NBS:
+                // An MBean that extends NotificationBroadcasterSupport
+                mbean = new Broadcaster();
+                break;
+            case INJ:
+                // An MBean that injects SendNotification
+                mbean = new SendNotif();
+                break;
+            case STD_MBEAN_NBS:
+                // A StandardMBean that delegates to a NotificationBroadcasterSupport
+                mbean = new StandardMBean(
+                        new Broadcaster(), BroadcasterMBean.class, wrappedVisOpts);
+                break;
+            case STD_MBEAN_INJ:
+                // A StandardMBean that delegates to an object that injects
+                // SendNotification
+                mbean = new StandardMBean(
+                        new SendNotif(), BroadcasterMBean.class, wrappedVisOpts);
+                break;
+            case STD_EMIT_MBEAN_NBS: {
+                // A StandardEmitterMBean that delegates to a NotificationBroadcasterSupport
+                Broadcaster broadcaster = new Broadcaster();
+                mbean = new StandardEmitterMBean(
+                        broadcaster, BroadcasterMBean.class, wrappedVisOpts,
+                        broadcaster);
+                break;
+            }
+            case STD_EMIT_MBEAN_INJ: {
+                // A StandardEmitterMBean that delegates to an object that injects
+                // SendNotification
+                SendNotif sendNotif = new SendNotif();
+                mbean = new StandardEmitterMBean(
+                        sendNotif, BroadcasterMBean.class, wrappedVisOpts,
+                        null);
+                break;
+            }
+            case STD_MBEAN_SUB_NBS:
+                // A subclass of StandardMBean that implements NotificationBroadcaster
+                mbean = new StdBroadcaster();
+                break;
+            case STD_MBEAN_SUB_INJ:
+                // A subclass of StandardMBean that injects SendNotification
+                mbean = new StdSendNotif();
+                break;
+            case STD_EMIT_MBEAN_SUB:
+                // A subclass of StandardEmitterMBean
+                mbean = new StdEmitterBroadcaster();
+                break;
+            case STD_EMIT_MBEAN_SUB_INJ:
+                // A subclass of StandardEmitterMBean that injects SendNotification
+                // (which is a rather strange thing to do and probably a user
+                // misunderstanding but we should do the right thing anyway).
+                mbean = new StdEmitterSendNotif();
+                break;
+            default:
+                throw new AssertionError();
+            }
+
+            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+
+            final ObjectName name = new ObjectName("a:type=Sender");
+            mbs.registerMBean(mbean, name);
+            boolean isBroadcaster = mbs.isInstanceOf(
+                    name, NotificationBroadcaster.class.getName());
+            assertEquals("JMX.isNotificationSource(mbean)",
+                    true, JMX.isNotificationSource(mbean));
+            assertEquals("isInstanceOf(NotificationBroadcaster)",
+                    true, isBroadcaster);
+            MBeanNotificationInfo[] mbnis =
+                    mbs.getMBeanInfo(name).getNotifications();
+            assertEquals("MBeanNotificationInfo not empty",
+                    true, (mbnis.length > 0));
+
+            mbs.unregisterMBean(name);
+        }
     }
 
     private static void assertEquals(String what, Object expect, Object actual) {