An MBean server forwards requests it receives to its default interceptor. A feature of the Java Dynamic Management Kit (Java DMK) enables you to modify this behavior of the MBean server and replace the default interceptor by another object implementing the same interface.
The example provided demonstrates how you can use the concept of MBean server interceptors to forward requests to a specific interceptor, and to support “virtual” MBeans. The code samples in this chapter are from the files in the MBeanServerInterceptor example directory located in the main examplesDir/current directory (see “Directories and Classpath” in the Preface).
This chapter covers the following topics:
The concept of interceptors exploits the proxy design pattern to enable you to modify the behavior of the MBean server. By default, the MBean server appears from the outside like a hollow shell that simply forwards every operation to the default interceptor. You can replace this default interceptor by another object implementing the same interface, to change the semantics of the MBean server. In most cases, you would use this other object to forward most or all operations to the default interceptor after doing some processing. However, you can also use it to forward some operations to other handlers instead, for instance depending on the object names involved. Figure 7–1 shows schematically how you can insert an interceptor between the MBean server and the default interceptor.
Some examples of the uses of interceptors are as follows:
Imposing security checks – The interceptor performs checks, for example it checks permissions, and only forwards operations that pass the security checks to the default interceptor.
Logging – The interceptor forwards all operations to the default interceptor, but also logs their parameters and results.
Creating virtual MBeans – The interceptor handles operations on MBeans it owns itself, and forwards others to the default interceptor. An interceptor might own all MBeans whose names match a particular pattern, for instance. In this way, MBeans do not necessarily have to be Java objects. This is very useful when there are a great many managed objects, or when they are very volatile.
Interceptors can be composed. When an interceptor is added, it is usually inserted between the MBean server shell and the current interceptor. Initially, the current interceptor is the default one. But if another interceptor has already been inserted, this other interceptor is the current one. Hence, a request could pass through several interceptors on its way to the default interceptor, for example a security checker and a logger.
The behavior to be implemented by an interceptor is specified by means of the MBeanServerInterceptor interface. An MBean server interceptor has essentially the same interface as an MBean server. An MBean server forwards received requests to its default interceptor, which might handle them itself or forward them to other interceptors.
The default interceptor can be changed by using the setMBeanServerInterceptor method of the JdmkMBeanServer interface. The JdmkMBeanServer interface provides methods for getting and setting the default MBeanServerInterceptor used for request treatment.
By default, the MBeanServer implementation returned by the MBeanServerFactory is not a JdmkMBeanServer, and does not support MBeanServerInterceptors. To use interceptor you have to set the javax.management.builder.initial System property to com.sun.jdmk.JdmkMBeanServerBuilder before obtaining an MBean server from the MBeanServerFactory. How to set this system property is shown in Step 2.
Particular care must be taken when replacing the default MBean server interceptor with a user interceptor. The MBean server implemented in the Java DMK 5.1 passes requests to its default interceptor without checking the result returned, or the exceptions thrown by the interceptor.
Consequently, user interceptors, which implement most of the methods defined in the MBeanServer interface, must behave as specified for the corresponding MBeanServer methods in the JMX specification. In particular, a method in an MBean server interceptor must not throw any exceptions apart from the following:
Exceptions explicitly declared in the throws clause of the same method in the interface com.sun.jdmk.interceptor.MBeanServerInterceptor
JMRuntimeException or a subclass of it
If an MBean server interceptor does not respect this condition, and, for example, throws a NullPointerException exception, this might have unexpected effects on calling code, which might not be protected against such behavior.
The MBean server interceptor example in the examples directory shows you two of the main functions of MBean server interceptors, forwarding requests to a specific MBean server interceptor, and creating virtual MBeans.
The examplesDir/current/MBeanServerInterceptor directory contains the following source files:
MasterMBeanServerInterceptor.java. This master interceptor receives all requests from the MBean server and, depending on the value of the domain part of the ObjectName, forwards them to one of the following interceptors:
The default MBean server interceptor.
Another MBean server interceptor, the FileMBeanServerInterceptor.
FileMBeanServerInterceptor.java. This is an MBean server interceptor that mirrors the contents of a file system directory by faking MBeans which represent files and directories. These MBeans are completely virtual. The FileMBeanServerInterceptor owns a reserved domain name, the file domain in this example, which is used by the MasterMBeanServerInterceptor to decide which requests to divert to the FileMBeanServerInterceptor.
Agent.java. This class implements a simple Java DMK agent which instantiates a MasterMBeanServerInterceptor and plugs in a FileMBeanServerInterceptor. This class shows how to instantiate the MasterMBeanServerInterceptor, how to plug it into the MBean Server, and how to plug the DefaultMBeanServerInterceptor and FileMBeanServerInterceptor into the MasterMBeanServerInterceptor.
Compile all files in the examplesDir/current/MBeanServerInterceptor directory with the javac command.
For example, on the Solaris platform, type:
$ cd examplesDir/current/MBeanServerInterceptor/ $ javac -classpath classpath *.java
Run the example using the classes you have just built, by typing the following command in a terminal window:
$ java \ -Djavax.management.builder.initial=com.sun.jdmk.JdmkMBeanServerBuilder \ Agent
Here, you can see that the javax.management.builder.initial system property is set to com.sun.jdmk.JdmkMBeanServerBuilder before the Agent is started, as explained in 7.3 Changing the Default Interceptor.
Interact with the agent through the standard input and output in the window where it was started.
Load the agent's URL in your web browser:
You only see the MBeans registered in the DefaultMBeanInterceptor, namely the connector and adaptor MBeans, and the MBeanServerDelegate.
Press Enter to insert the FileMBeanServerInterceptor and view the files from the local directory as virtual MBeans.
Reload the agent's URL in your web browser to view the new MBeans:
Press Enter to stop the agent.