Skip to main content

Mustang Beta and the JMX API

Posted by emcmanus on February 15, 2006 at 8:52 AM PST

As you'll no doubt have read href="http://weblogs.java.net/blog/mreinhold/archive/2006/02/mustang_beta_bl.html">elsewhere,
the Mustang Beta Release is href="http://java.sun.com/javase/6">now available. There are
plenty of improvements in plenty of areas, including the JMX
API.

The improvements to the JMX API are incremental changes to
existing functionality, rather than entirely new features. The
new features will arrive in Dolphin (Java SE 7), as defined by
JSR 255. (The
members of the JSR 255 Expert Group were also closely involved
in the JMX API changes made in Mustang.)

We don't expect there to be any significant changes to the JMX
API beyond the Beta. If you felt that the weekly
Mustang snapshots from
mustang.dev.java.net
might be too risky or
too volatile, but you're tempted by the new features, now you
can download the Beta and play with them. We think the Beta is
pretty solid, but let us know through
bugs.sun.com
if you find a problem. In
particular, if you find a regression (code that used
to work on Tiger but doesn't work on Mustang), then you might
be eligible for the href="http://weblogs.java.net/blog/robogeek/archive/2006/01/announcing_the.html">Mustang
regression challenge.

What's changed?

The two biggest changes to the JMX API in Mustang concern
MXBeans and Descriptors.

I wrote about
MXBeans href="http://weblogs.java.net/blog/emcmanus/archive/2006/02/what_is_an_mxbe.html">
recently. MXBeans provide a way to package related
information together in an MBean without requiring any special
configuration for clients that interact with that MBean. This
is an incremental change, because MXBeans already existed in
J2SE 5.0, in the package href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/management/package-frame.html">
java.lang.management. What's new is that
users can now define their own MXBeans, in addition to the
standard set defined in java.lang.management.

I also wrote about Descriptors href="http://weblogs.java.net/blog/emcmanus/archive/2005/10/adding_descript.html">
a while back. Descriptors give you a convenient way to
attach arbitrary extra metadata to your MBeans. This is an
incremental change because Descriptors have always existed in
the JMX API, but only in conjunction with href="http://java.sun.com/j2se/1.5.0/docs/api/javax/management/modelmbean/package-frame.html">
Model MBeans. In Mustang, Descriptors are available with
all types of MBeans. This helps to erase the somewhat
arbitrary distinctions between different sorts of MBeans,
notably Open MBeans and Model MBeans.

Here are a few of the other improvements that Mustang brings to
the JMX API.

Generification

For obscure compatibility reasons, we weren't able to generify
the JMX API in Tiger. This has been fixed in Mustang. So
MBeanServer.queryNames
now returns a
Set<ObjectName> rather than a plain
Set.

ObjectName.geyKeyPropertyList() returns a
Hashtable<String,String>
rather than a
plain Hashtable (compatibility forbids us from
changing it to Map<String,String>, alas).
And, especially, the methods in the href="http://java.sun.com/javase/6/docs/api/javax/management/relation/RelationServiceMBean.html">
RelationServiceMBean are much more
understandable with their new generic return types. It was
pretty tough understanding what was in the Map
returned by href="http://java.sun.com/javase/6/docs/api/javax/management/relation/RelationServiceMBean.html#findAssociatedMBeans(javax.management.ObjectName,%20java.lang.String,%20java.lang.String)">
RelationServiceMBean.findAssociatedMBeans.
Now that it's a
Map<ObjectName,List<String>> you have
a fighting chance of making sense of it.

One nice effect of generification is that you no longer need a
cast in the following assignment:

SomeMBean proxy = (SomeMBean)
    MBeanServerInvocationHandler.newProxyInstance(
    mbeanServer, objectName, SomeMBean.class, false);

As a side-note, this can now be replaced by the much
easier-to-remember:

SomeMBean proxy =
    JMX.newMBeanProxy(mbeanServer, objectName, SomeMBean.class);

More powerful wildcards in ObjectName

The
ObjectName
class has always had support for
wildcards, to define ObjectName patterns. But
you could not use a wildcard within the value of a key. For
example, you could not write
domain:type=Dir,path="/foo/bar/*" to match an
ObjectName such as
domain:type=Dir,path="/foo/bar/baz" but not
domain:type=Dir,path="/fred/jim/sheila". Now you
can.

ObjectName implements Comparable

ObjectName is now Comparable. The
ordering function is a little arbitrary, but the important point
here is that you can take a collection of
ObjectNames, such as the result of
MBeanServer.queryNames
, and put them in a
SortedSet
to see them in a more meaningful
order. For example, if I write this...

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> names = mbs.queryNames(null, null);
System.out.println(names.toString().replace(", ",
            System.getProperty("line.separator")));

...then I'll get this rather random output:

[java.lang:type=MemoryManager,name=CodeCacheManager
java.lang:type=Compilation
java.lang:type=GarbageCollector,name=Copy
com.sun.management:type=HotSpotDiagnostic
java.lang:type=MemoryPool,name=Eden Space
java.lang:type=Runtime
java.lang:type=ClassLoading
java.lang:type=MemoryPool,name=Survivor Space
java.lang:type=Threading
java.lang:type=GarbageCollector,name=MarkSweepCompact
java.util.logging:type=Logging
java.lang:type=Memory
java.lang:type=OperatingSystem
java.lang:type=MemoryPool,name=Code Cache
java.lang:type=MemoryPool,name=Tenured Gen
java.lang:type=MemoryPool,name=Perm Gen
JMImplementation:type=MBeanServerDelegate]

On the other hand, if I add the following line after the
assignment to names...

names = new TreeSet(names);  // a TreeSet is a SortedSet

...then I get this reasonable ordering:

[JMImplementation:type=MBeanServerDelegate
com.sun.management:type=HotSpotDiagnostic
java.lang:type=ClassLoading
java.lang:type=Compilation
java.lang:type=GarbageCollector,name=Copy
java.lang:type=GarbageCollector,name=MarkSweepCompact
java.lang:type=Memory
java.lang:type=MemoryManager,name=CodeCacheManager
java.lang:type=MemoryPool,name=Code Cache
java.lang:type=MemoryPool,name=Eden Space
java.lang:type=MemoryPool,name=Perm Gen
java.lang:type=MemoryPool,name=Survivor Space
java.lang:type=MemoryPool,name=Tenured Gen
java.lang:type=OperatingSystem
java.lang:type=Runtime
java.lang:type=Threading
java.util.logging:type=Logging]

Notifications

NotificationBroadcasterSupport constructor with MBeanInfo[]

If you have an MBean that emits notifications, it must
implement the
NotificationBroadcaster
interface. The JMX
API provides a default implementation called
NotificationBroadcasterSupport
. But you are
supposed to override the
getNotificationInfo
method to return an array
of all the notification types you might send. Since this
array is almost always a constant,
NotificationBroadcasterSupport now has a

constructor
that allows you to supply the array and avoid
having to override getNotificationInfo().

New StandardEmitterMBean class

Speaking of MBeans that emit notifications, if you're writing a
Standard MBean but you can't subclass
NotificationBroadcasterSupport because you have
already need to inherit from a different parent class, you can
use the new
StandardEmitterMBean
class to build a
notification-emitting MBean from your Standard MBean class. You
can also use this class if you need to customize the behaviour
of a notification-emitting Standard MBean, for example to change
the contents of its MBeanInfo.

New Query.isInstanceOf

You can now query for MBeans that are an instance of a
particular class or interface. For example, to find all Monitor
MBeans in the domesne domain, you could write:

QueryExp isMonitor =
    Query.isInstanceOf("javax.management.monitor.MonitorMBean");
Set<ObjectName> monitorNames =
    mbeanServer.queryNames(new ObjectName("domesne:*"), isMonitor);

Actually, I should warn you that this will change after the
Beta, and the first line will become this instead:

QueryExp isMonitor =
    Query.isInstanceOf(Query.value("javax.management.monitor.MonitorMBean"));

Alert readers will deduce that either I was lying when I said
there would be no significant API changes after the Beta, or I
don't consider this a significant change. Either way, this is
likely to be about as significant as it will get.

Monitor Service supports complex types

Previously, the Monitor Service defined by
javax.management.monitor
could only monitor
attributes of simple numeric types like int or
double, or strings. (A reminder that this
service allows you to sample an attribute periodically and
send a notification if it goes over or under a certain
threshold.) Now, you can monitor a value inside a complex
type using a syntax like
connectionStats.open.current.

The ability to pick out values like this is confined to the
Monitor Service. You cannot call
mbeanServer.getAttribute("connectionStats.open.current")
to obtain a similar effect. (We thought about allowing that,
but it could pose problems for existing code that uses
attribute.names.with.dots and it's also not obvious
what the corresponding behaviour for setAttribute
should be.)

Address of a JMXConnector

If you have an RMI connector client obtained with code
something like this...

JMXServiceURL jurl =
    new JMXServiceURL("service:jmx:rmi://blah);
JMXConnector jc = JMXConnectorFactory.connect(jurl);

...then you can now retrieve the address from jc
like this...

JMXServiceURL jurl2 = ((JMXAddressable) jc).getAddress();

Here, jurl2 will be equal to
jurl.

So there it is

As usual, if you have comments on these new features or the way
they are specified, feel free to drop me a line at href="mailto:jmx-spec-comments@sun.com">jmx-spec-comments@sun.com.

Related Topics >>