The `javax.management.MBeanServerInvocationHandler` class
Prev | Chapter 2. JMX 1.2 Explained | Next

## The `javax.management.MBeanServerInvocationHandler` class

### Introduction

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.

### MBeanServerInvocationHandler usage

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.MBeanException`s 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.

### Porting examples for `mx4j.util.StandardMBeanProxy`

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();

Prev | Home | Next
The `javax.management.MBeanServerBuilder` class | Up | Chapter 3. JSR 160 (JMX Remoting) Explained