MX4J version 1.x provided a custom implementation of a JDK 1.3's dynamic proxy to ease invocation
of methods on a MBean via the MBeanServer, the
mx4j.util.StandardMBeanProxy class.
MX4J 1.x provided also a class for invocation of methods on remote MBeans, namely
mx4j.connector.RemoteStandardMBeanProxy
based on MX4J's custom remote implementation.
In MX4J 1.x these classes were separated since JMX 1.1 did not specify a super-interface for MBeanServer
that could be used also remotely.
In JMX 1.2, the
javax.management.MBeanServer interface inherits from the
javax.management.MBeanServerConnection interface.
The MBeanServerConnection interface has basically the same methods of MBeanServer except those that
does not have sense remotely (like deserialize() and registerMBean()), and adds
java.io.IOException in the throws clause
of each method, thus making it the "remote" view of a remote MBeanServer.
As of JMX 1.2, both mx4j.util.StandardMBeanProxy and mx4j.connector.RemoteStandardMBeanProxy are obsolete since they have been replaced by one single class, the standard javax.management.MBeanServerInvocationHandler class, that takes advantage of the improved class hierarchy of the javax.management.MBeanServer interface to unify the functionalities that were provided before by the two MX4J classes.
In the following section will be explained how to port old MX4J 1.x code to the new JMX 1.2 code.
The JMX API to call an MBean via MBeanServer is very tedious: involves a reflection-like syntax and
a complex exception handling.
The reflection-like syntax is sometimes an advantage, but it suffers of lack of static type checkings
made by the compiler.
The exception handling is complex since it involves unwrapping of
javax.management.MBeanExceptions and rethrowing of the original exception thrown
by the MBean method, very much like
java.lang.reflect.InvocationTargetException
requires.
Fortunately, JDK 1.3 provides
dynamic proxies via the
java.lang.reflect.Proxy class.
By means of dynamic proxies, is it possible to write a proxy that hides the complexity of JMX
invocations and provides static type checking and trasparent exception handling.
Compare the two code examples below and note how the second example is cleaner.
Example 2.7. Standard JMX invocation
// The ObjectName of the delegate MBean ObjectName delegateName = ObjectName.getInstance("JMImplementation:type=delegate"); MBeanServer server = ...; // The MBeanServer ID String id = null; try { id = server.getAttribute(delegateName, "MBeanServerId"); } catch (MBeanException x) { // The getMBeanServerId() method threw an exception ?!? } catch(AttributeNotFoundException x) { // Uh ? Not a compliant JMX implementation ? } catch (InstanceNotFoundException x) { // Uh ? Not a compliant JMX implementation ? } catch (ReflectionException x) { // Uh ? What happened here ? }
Example 2.8. JMX invocation with MBeanServerInvocationHandler
// The ObjectName of the delegate MBean ObjectName delegateName = ObjectName.getInstance("JMImplementation:type=delegate"); MBeanServer server = ...; Object proxy = MBeanServerInvocationHandler.newProxyInstance(server, delegateName, MBeanServerDelegateMBean.class, true); MBeanServerDelegateMBean delegateMBean = (MBeanServerDelegateMBean)proxy; // The MBeanServer ID String id = delegateMBean.getMBeanServerId();
Usage of the
javax.management.MBeanServerInvocationHandler class is straightforward
for standard MBeans, since they already comply a management interface that is also a Java interface.
This interface can be used directly
as argument for the creation of the proxy (the third parameter of the
MBeanServerInvocationHandler.newProxyInstance() call).
However, usage of MBeanServerInvocationHandler is not limited to standard MBeans, but also to dynamic MBeans
can use it, provided that the management interface they comply to does not change during proxy's life.
It is not necessary that the dynamic MBean implements a Java interface: it is
enough that the Java interface provided to the MBeanServerInvocationHandler is a (sub)set of the
management interface exposed by the dynamic MBean.
The MBeanServerInvocationHandler class can also be used for remote MBeans, in conjuction with the JSR 160 API, like shown in the following code snippet:
Example 2.9. Remote JMX invocation with MBeanServerInvocationHandler
// The address of the connector server JMXServiceURL address = ...; // Create the JMXCconnectorServer JMXConnector cntor = JMXConnectorFactory.connect(address); // Obtain a "stub" for the remote MBeanServer MBeanServerConnection mbsc = cntor.getMBeanServerConnection(); // The ObjectName of a remote delegate MBean ObjectName delegateName = ObjectName.getInstance("JMImplementation:type=delegate"); Object proxy = MBeanServerInvocationHandler.newProxyInstance(mbsc, delegateName, MBeanServerDelegateMBean.class, true); MBeanServerDelegateMBean delegateMBean = (MBeanServerDelegateMBean)proxy; // The MBeanServer ID String id = delegateMBean.getMBeanServerId();
Refer to the javadocs of the javax.management.MBeanServerInvocationHandler class for further details.
The MX4J 1.x API of
mx4j.util.StandardMBeanProxy is very similar to
javax.management.MBeanServerInvocationHandler's.
Below are shown two code snippets that compare the old MX4J 1.x API with the new standard one.
Note how only the line marked with (*) changes from the old version to the new one.
Example 2.10. Old MX4J 1.x proxy API
// The ObjectName of the delegate MBean ObjectName delegateName = ObjectName.getInstance("JMImplementation:type=delegate"); MBeanServer server = ...; Object proxy = StandardMBeanProxy.create(MBeanServerDelegateMBean.class, server, delegateName); (*) MBeanServerDelegateMBean delegateMBean = (MBeanServerDelegateMBean)proxy; // The MBeanServer ID String id = delegateMBean.getMBeanServerId();
Example 2.11. Standard JMX 1.2 proxy API
// The ObjectName of the delegate MBean ObjectName delegateName = ObjectName.getInstance("JMImplementation:type=delegate"); MBeanServer server = ...; Object proxy = MBeanServerInvocationHandler.newProxyInstance(server, delegateName, MBeanServerDelegateMBean.class, true); MBeanServerDelegateMBean delegateMBean = (MBeanServerDelegateMBean)proxy; // The MBeanServer ID String id = delegateMBean.getMBeanServerId();