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

## The `javax.management.MBeanServerBuilder` class

### Introduction

JMX 1.2 introduced the possibility to replace, at runtime, the MBeanServer implementation by specifying a full qualified name of a `javax.management.MBeanServerBuilder` subclass with the system property "javax.management.builder.initial".
When creating a new `MBeanServer` instance, the `MBeanServerFactory` checks (every time) for the value of that system property; if it is not null, loads (using the context classloader), instantiates, and delegates the `MBeanServerBuilder` subclass to create `MBeanServer` instances.

Since now the creation of `MBeanServer` instances can be delegated to a custom `MBeanServerBuilder`, it is possible to achieve two things:

- Use Sun's JMX reference implementation (JMXRI) but telling it to use MX4J's `MBeanServer` implementation
- "Wrap" the `MBeanServer` implementation and "decorate" it with added functionality.

### How to use MX4J's `MBeanServer` implementation with Sun's JMX Reference Implementation.

This is very simple to achieve:

Example 2.1.

    java -cp jmxri.jar;mx4j-impl.jar -Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder <MyClass>

Note how the classpath specifies first the JMXRI jar and then the MX4J implementation jar.

### How to "decorate" `MBeanServer` methods.

A custom `MBeanServerBuilder` allows you to specify how to create an `MBeanServer`.
Any JMX implementation has already in place a mechanism that uses a default `MBeanServerBuilder` to create instances of the default `MBeanServer` implementation.
In order to be able to "decorate" an `MBeanServer` it is sufficient to specify a custom `MBeanServerBuilder` that "decorates" the default one; then the implementation of the custom `MBeanServerBuilder` will "decorate" the default `MBeanServer`.

However, implementing a "decorating" `MBeanServerBuilder` requires a bit of precision.
We will explain how to do this in detail in the following, using as example the MX4J implementation.

Using the `MBeanServerBuilder` to "decorate" an `MBeanServer` requires to write two classes:

- a custom `MBeanServerBuilder`
- a decorating `MBeanServer`

Although it's possible to start from scratch, the MX4J API gives you two base classes to start from:

- `mx4j.server.ChainedMBeanServerBuilder`
- `mx4j.server.ChainedMBeanServer`

Let's suppose we want to decorate the default `MBeanServer` by adding logging statements whenever a `MBeanServer` method is called.
First, we write the "decorating" `MBeanServer`:

Example 2.2. A "decorating" `MBeanServer` that logs method calls.

    public class LoggingMBeanServer extends ChainedMBeanServer
    {
       // Overridden just to make it public
       public void setMBeanServer(MBeanServer server)
       {
          super.setMBeanServer(server);
       }

       public Object getAttribute(ObjectName objectName, String attribute)
          throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException
       {
          Object value = super.getAttribute(objectName, attribute);
          System.out.println("[LOGGER] getAttribute() returned: " + value);
          return value;
       }

       // And so on for all other MBeanServer methods.
    }

The class `ChainedMBeanServer` simply forwards the calls to a nested `MBeanServer`. `ChainedMBeanServer` thus allows to create a "chain" of `MBeanServer`s that are called in succession, one after the other, from the outermost to the innermost.

Second, we write the "decorating" `MBeanServerBuilder`:

Example 2.3. A "decorating" `MBeanServerBuilder`

    public class LoggingBuilder extends ChainedMBeanServerBuilder
    {
       public LoggingBuilder()
       {
          super(new mx4j.server.MX4JMBeanServerBuilder());
       }

       public MBeanServer newMBeanServer(String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate)
       {
          LoggingMBeanServer extern = new LoggingMBeanServer();
          MBeanServer nested = getMBeanServerBuilder().newMBeanServer(defaultDomain, outer == null ? extern : outer, delegate);
          extern.setMBeanServer(nested);
          return extern;
       }
    }

As for the `ChainedMBeanServer` class, also `ChainedMBeanServerBuilder` simply forwards the calls to a nested `MBeanServerBuilder`. Also here, `ChainedMBeanServerBuilder` allows to create a "chain" of `MBeanServerBuilder`s that are called in succession, one after the other, from the outermost to the innermost.

The `MBeanServerBuilder` chain works in parallel with the `MBeanServer` chain in this way:

Example 2.4. The `MBeanServerBuilder` and `MBeanServer` chains

    MBeanServerFactory  -- calls -->   LoggingBuilder     -- calls -->  MX4JMBeanServerBuilder
                                             |                                   |
                                          creates                             creates
                                             |                                   |
                                             V                                   V
           Application  -- calls -->  LoggingMBeanServer  -- calls -->     MX4JMBeanServer

Note the `LoggingBuilder` constructor: there is where the `MBeanServerBuilder` chain is created.
The `LoggingBuilder` specifies a chain of only two rings, the `LoggingBuilder` itself, and MX4J's default `MBeanServerBuilder`, `MX4JMBeanServerBuilder`.
This chain is hardcoded in the builder, meaning that if you want to change it at runtime you cannot: either you change and recompile the custom builder, or you use another custom builder.

Note also the usage of the ternary operator (condition ? this : that) in the nested `newMBeanServer()` call: checking for nullity of the "outer" argument is of fundamental importance for the builder to be "chainable". If this check is not made, then `LoggingBuilder` cannot be reused as a ring of a longer chain if, in future, we modify it to accept as parameter to the constructor other builders (i.e. other "rings").

It is of course possible to use different builders from different vendors, simply by creating a custom builder that "chains" all the other in the desired sequence:

Example 2.5. A "decorating" `MBeanServerBuilder`

    public class ComplexBuilder extends ChainedMBeanServerBuilder
    {
       public LoggingBuilder()
       {
          super(new com.sun.jmx.bar.BarBuilder(new com.ibm.jmx.foo.FooBuilder(new mx4j.server.MX4JMBeanServerBuilder())));
       }
    }

Just remember that `MX4JMBeanServerBuilder` is a "terminal" builder and must always be the last in the chain.
Other vendors are expected to provide an API for their custom builders very similar to `ChainedMBeanServerBuilder` (which is mostly being able to take a `javax.management.MBeanServerBuilder` as argument to a constructor).

### More complex `MBeanServer` "decorations".

We saw above that is possible to "decorate" `MBeanServer`s by decorating the default mechanism of the `MBeanServerBuilder` already in place in any JMX implementation.
We saw that to a chain of builders corresponded a chain of servers.
However, it's possible that a builder specifies more than one ring for the server chain, in the following way:

Example 2.6. A More complex `MBeanServerBuilder` and `MBeanServer` chains

    MBeanServerFactory --calls-->  LoggingBuilder    --calls-->          PerformanceBuilder    --calls-->    MX4JMBeanServerBuilder
                                         |                                        |                                     |
                                      creates                                  creates                               creates
                                         |                                   /         \                                |
                                         V                                  V           V                               V
           Application --calls--> LoggingMBeanServer --calls--> TimingServer --calls--> CountingServer --calls--> MX4JMBeanServer

An example of such chains is present in the MX4J testsuite, in the test class that tests the `MBeanServerBuilder` functionality.

### Possible usages of MBeanServer "decorators"

A (non complete) list of possible "decorators" for `MBeanServer` may include functionality such as:

- Logging the invocation
- Measuring the invocation time
- Counting the number of invocations
- Load-balancing the invocations among server nodes
- Cascading the invocations to child servers
- Notifying a message to someone for a particular invocation
- ...

Prev | Home | Next
Support for remote API | Up | The `javax.management.MBeanServerInvocationHandler` class