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:
MBeanServer
implementation
MBeanServer
implementation and "decorate" it with added functionality.
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.
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:
MBeanServerBuilder
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
<funcdef>
newMBeanServer()
</funcdef> 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).
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.
A (non complete) list of possible "decorators" for
MBeanServer
may include functionality such as: