jdk/test/javax/management/namespace/NamespaceNotificationsTest.java
changeset 1156 bbc2d15aaf7a
child 1227 4546977d0d66
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/namespace/NamespaceNotificationsTest.java	Thu Sep 04 14:46:36 2008 +0200
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ *
+ * @test NamespaceNotificationsTest.java 1.12
+ * @summary General Namespace & Notifications test.
+ * @author Daniel Fuchs
+ * @run clean NamespaceNotificationsTest
+ *            Wombat WombatMBean JMXRemoteTargetNamespace
+ *            NamespaceController NamespaceControllerMBean
+ * @compile -XDignore.symbol.file=true  NamespaceNotificationsTest.java
+ *            Wombat.java WombatMBean.java JMXRemoteTargetNamespace.java
+ *            NamespaceController.java NamespaceControllerMBean.java
+ * @run main NamespaceNotificationsTest
+ */
+import com.sun.jmx.remote.util.EventClientConnection;
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Logger;
+import javax.management.JMX;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanServerDelegate;
+import javax.management.MBeanServerFactory;
+import javax.management.MBeanServerNotification;
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.loading.MLet;
+import javax.management.namespace.JMXNamespace;
+import javax.management.namespace.JMXNamespaces;
+import javax.management.remote.JMXAddressable;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+/**
+ *
+ * @author Sun Microsystems, Inc.
+ */
+public class NamespaceNotificationsTest {
+
+    /**
+     * A logger for this class.
+     **/
+    private static final Logger LOG =
+            Logger.getLogger(NamespaceNotificationsTest.class.getName());
+
+    /** Creates a new instance of NamespaceNotificationsTest */
+    public NamespaceNotificationsTest() {
+    }
+
+
+    public static JMXServiceURL export(MBeanServer server)
+    throws Exception {
+        final JMXServiceURL in = new JMXServiceURL("rmi",null,0);
+        final JMXConnectorServer cs =
+                JMXConnectorServerFactory.newJMXConnectorServer(in,null,null);
+        final ObjectName csname = ObjectName.
+                getInstance(cs.getClass().getPackage().getName()+
+                ":type="+cs.getClass().getSimpleName());
+        server.registerMBean(cs,csname);
+        cs.start();
+        return cs.getAddress();
+    }
+
+    public static class Counter {
+        int count;
+        public synchronized int count() {
+            count++;
+            notifyAll();
+            return count;
+        }
+        public synchronized int peek() {
+            return count;
+        }
+        public synchronized int waitfor(int max, long timeout)
+        throws InterruptedException {
+            final long start = System.currentTimeMillis();
+            while (count < max && timeout > 0) {
+                final long rest = timeout -
+                        (System.currentTimeMillis() - start);
+                if (rest <= 0) break;
+                wait(rest);
+            }
+            return count;
+        }
+    }
+
+    public static class CounterListener
+            implements NotificationListener {
+        final private Counter counter;
+        public CounterListener(Counter counter) {
+            this.counter = counter;
+        }
+        public void handleNotification(Notification notification,
+                Object handback) {
+            System.out.println("Received notif from " + handback +
+                    ":\n\t" + notification);
+            if (!notification.getSource().equals(handback)) {
+                System.err.println("OhOh... Unexpected source: \n\t"+
+                        notification.getSource()+"\n\twas expecting:\n\t"+
+                        handback);
+            }
+            counter.count();
+        }
+    }
+
+    public static void simpleTest(String[] args) {
+        try {
+            final MBeanServer server1 =
+                    ManagementFactory.getPlatformMBeanServer();
+            final JMXServiceURL url1 = export(server1);
+
+            final MBeanServer server2 =
+                    MBeanServerFactory.createMBeanServer("server2");
+            final JMXServiceURL url2 = export(server2);
+
+            final MBeanServer server3 =
+                    MBeanServerFactory.createMBeanServer("server3");
+            final JMXServiceURL url3 = export(server3);
+
+            final ObjectInstance ncinst =
+                    NamespaceController.createInstance(server1);
+
+            final NamespaceControllerMBean nc =
+                    JMX.newMBeanProxy(server1,ncinst.getObjectName(),
+                    NamespaceControllerMBean.class);
+
+            final Map<String,Object> options = new HashMap<String,Object>();
+            options.put(JMXRemoteTargetNamespace.CREATE_EVENT_CLIENT,"true");
+
+            final String mount1 =
+                    nc.mount(url1,"server1",options);
+            final String mount2 = nc.mount(url2,"server1//server2",
+                    options);
+            final String mount3 = nc.mount(url3,
+                    "server1//server2//server3",
+                    options);
+            final String mount13 = nc.mount(
+                    url1,
+                    "server3",
+                    "server2//server3",
+                    options);
+            final String mount21 = nc.mount(url1,"server2//server1",
+                    options);
+            final String mount31 = nc.mount(
+                    url1,
+                    "server3//server1",
+                    "server1",
+                    options);
+            final String mount32 = nc.mount(
+                    url1,
+                    "server3//server2",
+                    "server2",
+                    options);
+
+
+            final ObjectName deep =
+                    new ObjectName("server1//server2//server3//bush:type=Wombat,name=kanga");
+            server1.createMBean(Wombat.class.getName(),deep);
+
+            System.err.println("There's a wombat in the bush!");
+
+            final Counter counter = new Counter();
+
+            final NotificationListener listener =
+                    new CounterListener(counter);
+
+            final JMXConnector jc = JMXConnectorFactory.connect(url1);
+            final MBeanServerConnection aconn =
+                    EventClientConnection.getEventConnectionFor(
+                        jc.getMBeanServerConnection(),null);
+            aconn.addNotificationListener(deep,listener,null,deep);
+
+
+            final JMXServiceURL urlx = new JMXServiceURL(url1.toString());
+            System.out.println("conn: "+urlx);
+            final JMXConnector jc2 = JMXNamespaces.narrowToNamespace(
+                    JMXConnectorFactory.connect(urlx),"server1//server1");
+            final JMXConnector jc3 = JMXNamespaces.narrowToNamespace(jc2,"server3");
+            jc3.connect();
+            System.out.println("JC#3: " +
+                    ((jc3 instanceof JMXAddressable)?
+                        ((JMXAddressable)jc3).getAddress():
+                        jc3.toString()));
+            final MBeanServerConnection bconn =
+                    jc3.getMBeanServerConnection();
+            final ObjectName shallow =
+                    new ObjectName("bush:"+
+                    deep.getKeyPropertyListString());
+            final WombatMBean proxy =
+                    JMX.newMBeanProxy(EventClientConnection.getEventConnectionFor(
+                        bconn,null),shallow,WombatMBean.class,true);
+
+            ((NotificationEmitter)proxy).
+                    addNotificationListener(listener,null,shallow);
+            proxy.setCaption("I am a new Wombat!");
+            System.err.println("New caption: "+proxy.getCaption());
+            final int rcvcount = counter.waitfor(2,3000);
+            if (rcvcount != 2)
+                throw new RuntimeException("simpleTest failed: "+
+                        "received count is " +rcvcount);
+
+            System.err.println("simpleTest passed: got "+rcvcount+
+                    " notifs");
+
+        } catch (RuntimeException x) {
+            throw x;
+        } catch (Exception x) {
+            throw new RuntimeException("simpleTest failed: " + x,x);
+        }
+    }
+
+    public static class LocalNamespace extends
+            JMXNamespace {
+        LocalNamespace() {
+            super(MBeanServerFactory.newMBeanServer());
+        }
+
+    }
+
+    public static class ContextObject<K,V> {
+        public final K name;
+        public final V object;
+        public ContextObject(K name, V object) {
+            this.name = name;
+            this.object = object;
+        }
+        private Object[] data() {
+            return new Object[] {name,object};
+        }
+
+        @Override
+        public boolean equals(Object x) {
+            if (x instanceof ContextObject)
+                return Arrays.deepEquals(data(),((ContextObject<?,?>)x).data());
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return Arrays.deepHashCode(data());
+        }
+    }
+
+    private static <K,V> ContextObject<K,V> context(K k, V v) {
+        return new ContextObject<K,V>(k,v);
+    }
+
+    private static ObjectName name(String name) {
+        try {
+            return new ObjectName(name);
+        } catch(MalformedObjectNameException x) {
+            throw new IllegalArgumentException(name,x);
+        }
+    }
+
+    public static void simpleTest2() {
+        try {
+            System.out.println("\nsimpleTest2: STARTING\n");
+            final LocalNamespace foo = new LocalNamespace();
+            final LocalNamespace joe = new LocalNamespace();
+            final LocalNamespace bar = new LocalNamespace();
+            final MBeanServer server = MBeanServerFactory.newMBeanServer();
+
+            server.registerMBean(foo,JMXNamespaces.getNamespaceObjectName("foo"));
+            server.registerMBean(joe,JMXNamespaces.getNamespaceObjectName("foo//joe"));
+            server.registerMBean(bar,JMXNamespaces.getNamespaceObjectName("foo//bar"));
+            final BlockingQueue<ContextObject<String,MBeanServerNotification>> queue =
+                    new ArrayBlockingQueue<ContextObject<String,MBeanServerNotification>>(20);
+
+            final NotificationListener listener = new NotificationListener() {
+                public void handleNotification(Notification n, Object handback) {
+                    if (!(n instanceof MBeanServerNotification)) {
+                        System.err.println("Error: expected MBeanServerNotification");
+                        return;
+                    }
+                    final MBeanServerNotification mbsn =
+                            (MBeanServerNotification) n;
+
+                    // We will pass the namespace name in the handback.
+                    //
+                    final String namespace = (String) handback;
+                    System.out.println("Received " + mbsn.getType() +
+                            " for MBean " + mbsn.getMBeanName() +
+                            " from name space " + namespace);
+                    try {
+                        queue.offer(context(namespace,mbsn),500,TimeUnit.MILLISECONDS);
+                    } catch (Exception x) {
+                        System.err.println("Failed to enqueue received notif: "+mbsn);
+                        x.printStackTrace();
+                    }
+                }
+            };
+
+            server.addNotificationListener(JMXNamespaces.insertPath("foo//joe",
+                    MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//joe");
+            server.addNotificationListener(JMXNamespaces.insertPath("foo//bar",
+                    MBeanServerDelegate.DELEGATE_NAME),listener,null,"foo//bar");
+            server.createMBean(MLet.class.getName(),
+                    name("foo//joe//domain:type=MLet"));
+            checkQueue(queue,"foo//joe",
+                    MBeanServerNotification.REGISTRATION_NOTIFICATION);
+            server.createMBean(MLet.class.getName(),
+                    name("foo//bar//domain:type=MLet"));
+            checkQueue(queue,"foo//bar",
+                    MBeanServerNotification.REGISTRATION_NOTIFICATION);
+            server.unregisterMBean(
+                    name("foo//joe//domain:type=MLet"));
+            checkQueue(queue,"foo//joe",
+                    MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
+            server.unregisterMBean(
+                    name("foo//bar//domain:type=MLet"));
+            checkQueue(queue,"foo//bar",
+                    MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
+        } catch (RuntimeException x) {
+            System.err.println("FAILED: "+x);
+            throw x;
+        } catch(Exception x) {
+            System.err.println("FAILED: "+x);
+            throw new RuntimeException("Unexpected exception: "+x,x);
+        }
+    }
+
+
+    private static void checkQueue(
+            BlockingQueue<ContextObject<String,MBeanServerNotification>> q,
+                              String path, String type) {
+        try {
+          final ContextObject<String,MBeanServerNotification> ctxt =
+                    q.poll(500,TimeUnit.MILLISECONDS);
+          if (ctxt == null)
+            throw new RuntimeException("Timeout expired: expected notif from "+
+                    path +", type="+type);
+          if (!ctxt.name.equals(path))
+            throw new RuntimeException("expected notif from "+
+                    path +", got "+ctxt.name);
+          if (!ctxt.object.getType().equals(type))
+            throw new RuntimeException(ctxt.name+": expected type="+
+                    type +", got "+ctxt.object.getType());
+          if (!ctxt.object.getType().equals(type))
+            throw new RuntimeException(ctxt.name+": expected type="+
+                    type +", got "+ctxt.object.getType());
+          if (!ctxt.object.getMBeanName().equals(name("domain:type=MLet")))
+            throw new RuntimeException(ctxt.name+": expected MBean=domain:type=MLet"+
+                    ", got "+ctxt.object.getMBeanName());
+        } catch(InterruptedException x) {
+            throw new RuntimeException("unexpected interruption: "+x,x);
+        }
+    }
+
+    public static void main(String[] args) {
+        simpleTest(args);
+        simpleTest2();
+    }
+
+}