Skip to main content

Unit testing remote access to JMX MBeans

Posted by emcmanus on July 7, 2006 at 2:28 AM PDT

I often want to test that my MBeans work correctly when accessed remotely. For example it's easy to accidentally introduce non-serializable objects in them. It's a pain to set up a real remote connection, but you can make a loopback connection in the same JVM to test most of the same things. Here's how.

import javax.management.*;
import javax.management.remote.*;

...

MBeanServer mbs = ...something...;
// for example, java.lang.management.ManagementFactory.getPlatformMBeanServer();

// Make a connector server...
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
JMXConnectorServer cs =
    JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
cs.start();
JMXConnector cc = null;
try {
    JMXServiceURL addr = cs.getAddress();

    // Now make a connector client using the server's address
    cc = JMXConnectorFactory.connect(addr);
    MBeanServerConnection mbsc = cc.getMBeanServerConnection();

    ...test logic here, using mbsc...
    ...e.g. String attr = (String) mbsc.getAttribute(objectName, "MyAttr");
    ...or   mbsc.addNotificationListener(objectName, listener, filter, null);
} finally {
    if (cc != null)
        cc.close();
    cs.stop();
}

If you do your tests using mbsc instead of mbs, then MBean Server operations will go through RMI. Even though the connection never leaves the JVM, this enables you to test that your MBean code is network-friendly.

You'll typically want to stop the connector server before your test exits. Otherwise it will prevent your JVM from exiting promptly. I generally pop this into a try/finally so I'm sure it will get executed even if the test gets an exception.

Obviously you can wrap all this logic into a class that looks like this:

public class JMXRemoteTest {
    public static interface Test {
        public void test(MBeanServerConnection mbsc) throws Exception;
    }

    public static void remoteTest(MBeanServer mbs, Test test) {
        ...
        test.test(mbsc);
        ....
    }
}

and use it like this:

JMXRemoteTester.remoteTest(mbs, new JMXRemoteTester.Test() {
    public void test(MBeanServerConnection mbsc) throws Exception {
        // example test
        mbsc.addNotificationListener(objectName, listener, filter, null);
        mbsc.invoke(objectName, "provokeNotification", null, null);
        waitForNotification();
    }
}

Or if you have a bunch of remote tests, you can set up the MBeanServerConnection in your setup() method or equivalent, and use it for all the tests, then close the JMXConnector and JMXConnectorServer in the tearDown() method.

Related Topics >>

Comments

Attr's names

Note that the Attr names excludes the get but *is* capitalized, like ...e.g. String attr = (String) mbsc.getAttribute(objectName, "MyAttr"); for the following getter/setter public interface SomethingMBean { String GetMyAttr(); ... }