Interacting with the MX4J implementation
Prev | Chapter 4. MX4J Extensions and utilities | Next

## Interacting with the MX4J implementation

The MX4J implementation exposes some internal functionality via a public API that can be used by MBeans and applications.
However using these API ties the MBean or the application to the MX4J implementation, making them non-portable across other JMX implementations.

### Internal logging redirection

MX4J has a flexible logging system that allows you to tune the logging priority and to redirect MX4J internal logging to other logging systems such as Commons Logging or Log4J.

The MX4J logging system has six logging priorities; from the lowest priority to the highest they are:

- trace
- debug
- info
- warn
- error
- fatal

The default level is warn, and it can be set to a different value just by setting the system property "mx4j.log.priority" to one of the values above.

For example, you can start the JVM with this command to have MX4J log at a debug level:

java -Dmx4j.log.priority=debug MyMainClass

The fatal level is never used by MX4J.

MX4J default logging is done on the console via `System.out`, but can be redirected to other logging systems using the MX4J logging API, or through the broadcaster MBean (see below).

For example, let's assume you want to redirect MX4J logging to Log4J. Below is the code needed to do so:

Example 4.2. Logging redirection to Log4J

    import org.apache.log4j.PropertyConfigurator;
    import mx4j.log.*;

    public class Main
    {
       public static void main(String[] args) throws Exception
       {
          // Configure Log4J
          PropertyConfigurator.configureAndWatch("log4j.properties");
          // Or use the XML version below
          // DOMConfigurator.configureAndWatch("log4j.xml");

          // Redirect MX4J logging to Log4J
          Log.redirectTo(new Log4JLogger());

          // Normal code here
          MBeanServer server = MBeanServerFactory.createMBeanServer();
          ...

          // Reset redirection, log in the normal way (to console)
          Log.redirectTo(null);
       }
    }

It is also shown how to reset logging redirection to the standard one, that logs on the console.

The prototype for the new Logger, in the example above `Log4JLogger`, can be specified either in the code or by setting the system property "mx4j.log.prototype" to the full qualified name of the Logger subclass, for example:

java -Dmx4j.log.prototype=mx4j.log.Log4JLogger MyMainClass

In this case, using system properties, your MBean or application remains portable across JMX implementations.

It is possible to redirect logging to the MX4J broadcaster MBean, that will send notifications to registered listeners. The MBeanServer mechanism is used to emit these notifications, so that every listener can register itself along with a filter, to exclude notifications in which it's not interested in. The example below shows the code necessary to redirect the logging system to the broadcaster MBean:

Example 4.3. Logging redirection to the broadcaster MBean

    import mx4j.log.*;

    public class Main
    {
       public static void main(String[] args) throws Exception
       {
          MBeanServer server = MBeanServerFactory.createMBeanServer();

          // Register the broadcaster logger mbean
          ObjectName name = new ObjectName("Logger:type=broadcaster");
          server.createMBean("mx4j.log.LoggerBroadcaster", name, null);

          // The filter: only errors are logged
          NotificationFilter filter = new NotificationFilter()
          {
             public boolean isNotificationEnabled(Notification notification)
             {
                if (notification.getType().equals("mx4j.logger.error")) {return true;}
                return false;
             }
          };

          // The listener: logs on System.err instead of System.out
          NotificationListener listener = new NotificationListener()
          {
             public void handleNotification(Notification notification, Object handback)
             {
                System.err.println("[MX4J ERROR]: " + notification);
             }
          };

          // Register the listener along with the filter
          server.addNotificationListener(name, listener, filter, null);

          // Starts the redirector
          LoggerBroadcasterMBean redirector = (LoggerBroadcasterMBean)MBeanServerInvocationHandler.newProxyInstance(server, name, LoggerBroadcasterMBean.class, true);
          redirector.start();

          ...

          // Stops the redirector
          redirector.stop();
       }
    }

It is also shown how to reset logging redirection to the standard one, that logs on the console.

#### Log categories of the MX4J implementation

Various classes in the MX4J implementation log their activities.
Each class logs with a certain category, that organizes logging into a hierarchy of categories, following a dotted scheme introduced by Log4J.
The categories are simply the full qualified names of the classes that log their activities.

### MBeanServerInterceptor configuration

The MX4J implementation allows client code to add custom interceptors for the MBeanServer calls that may end up in a call to an MBean instance.

When the MX4J implementation of the MBeanServer is created, a configurator for the MBeanServer-to-MBean interceptor chain is also created, along with a default set of interceptors (that cannot be removed by the client code).
Each one of the default interceptors is also an MBean, so it can be monitored/managed as a normal MBean, and also the configurator is an MBean, registered with ObjectName "JMImplementation:type=MBeanServerInterceptorConfigurator".

The interceptor configurator exposes a management API that can be invoked as usual via the MBeanServer.
The API allows client code to add and remove custom interceptors, even at runtime, to perform additional tasks such as logging, performance timing, redirection and so on.

Writing a custom interceptor is simple, and requires the client code to implement the interface `mx4j.server.interceptor.MBeanServerInterceptor` or to extend the class `mx4j.server.interceptor.DefaultMBeanServerInterceptor`.

Once you have written your custom interceptor, you can add it to the interceptor chain using the API provided by the `MBeanServerInterceptorConfigurator`, via these methods:

- `addInterceptor(MBeanServerInterceptor interceptor)`
- `registerInterceptor(MBeanServerInterceptor interceptor, ObjectName name)`

See the Javadoc API documentation relative to the class `mx4j.server.interceptor.MBeanServerInterceptorConfigurator` and its management interface for further details.
Below you can find a simple example of how to use the `MBeanServerInterceptorConfigurator` API.

Example 4.4. Using the interceptor configurator API

    public class Main
    {
       public static void main(String[] args) throws Exception
       {
          // Create an MBeanServer instance
          // This will also create and configure an instance of the
          // MBeanServerInterceptorConfigurator MBean
          MBeanServer server = MBeanServerFactory.createMBeanServer();

          // The name under which the configurator is registered
          ObjectName name = new ObjectName("JMImplementation:type=MBeanServerInterceptorConfigurator");

          // Create a custom interceptor
          GetMBeanInfoLoggerInterceptor custom = new GetMBeanInfoLoggerInterceptor();

          // Install the custom interceptor
          server.invoke(name, "addInterceptor", new Object[] {custom}, new String[] {MBeanServerInterceptor.class.getName()});

          // Now every call to getMBeanInfo will be logged
          MBeanInfo info = server.getMBeanInfo(name);
       }

       public static class GetMBeanInfoLoggerInterceptor extends DefaultMBeanServerInterceptor
       {
          public MBeanInfo getMBeanInfo(MBeanMetaData metadata)
          {
             // Use whatever logging system is better for you...
             System.out.println("Call to getMBeanInfo !");
             return super.getMBeanInfo(metadata);
          }
       }
    }

Prev | Home | Next
Chapter 4. MX4J Extensions and utilities | Up | Chapter 5. MX4J HTTP Adaptor