JPPF, java, parallel computing, distributed computing, grid computing, parallel, distributed, cluster, grid, cloud, open source, android, .net
JPPF, java, parallel computing, distributed computing, grid computing, parallel, distributed, cluster, grid, cloud, open source, android, .net
JPPF

The open source
grid computing
solution

 Home   About   Features   Download   Documentation   On Github   Forums 

Pluggable MBeans

From JPPF 6.3 Documentation

Jump to: navigation, search

Contents

Main Page > Customizing JPPF > Pluggable MBeans


Developers can write their own management beans (MBeans) and register them with the JPPF MBean server for a node or a driver. These MBeans can then be accessed, locally or remotely, as any of the built-in JPPF MBeans. Refer to the chapter on Management and monitoring, for details on how to connect to an MBean server and use the registered MBeans.

Note: all JPPF built-in MBeans are implemented via this mechanism.

Related sample: “Custom MBeans” sample in the JPPF samples pack.


1 Elements and constraints common to node and server MBeans

The mechanism for pluggable MBeans is based on the Service Provider Interface, which is a light-weight and standard mechanism to provide extensions to Java applications.

The general workflow for adding a pluggable MBean is as follows:

  • step 1: implement the MBean: MBean interface + MBean implementation class
  • step 2: implement the MBean provider interface provided in JPPF
  • step 3: add or update the corresponding service definition file in the META-INF/services folder
  • step 4: create a jar file containing the above elements and deploy it in the node or server class path


The JPPF MBean handling mechanism relies on standard MBeans that must comply with the following constraints:

  • the MBean interface name must be of the form <MyName>MBean and the MBean implementation class name must be of the form <MyName>. For instance, if we want to add a server health monitor, we would create the interface ServerHealthMonitorMBean and implement it in a class named ServerHealthMonitor.
  • the MBean interface and implementation class must be defined in the same package. This is due to the constraints imposed by the JPPF distributed class loading mechanism, which allows nodes to download their custom MBeans from the server. If this constraint is not followed, the default JMX remote connector will be unable to find the MBean implementation class and it will not be possible to use the MBean. The MBean interface and implementation may, however, be in separate jar files or class folders (as long as they are in the same package).
  • for custom MBeans that access other MBeans, the order in which the service definition files and their entries are read is important, since it is the order in which the MBeans are instantiated. This means that, if an MBean uses an another, the developer must ensure that the dependant MBean is created after the one it depends on.
  • the implementation of the MBean provider interface must have a public no-arg constructor

2 Writing a custom node MBean

In this section we will follow the workflow described in the previous section and create a simple custom node MBean.

2.1 Create the MBean interface and its implementation

In this example, we will create an MBean that exposes a single method to query the number of processors available to the node's JVM. First we create an interface named AvailableProcessorsMBean:

package org.jppf.example.mbean;

// Exposes one method that queries the node's JVM
// for the number of available processors
public interface AvailableProcessorsMBean {
  // return the available processors as an integer value
  Integer queryAvailableProcessors();
}

Now we will create an implementation of this interface, in a class named AvailableProcessors, defined in the same Java package org.jppf.example.node.mbean:

package org.jppf.example.mbean;

// Implementation of the AvailableProcessorsMBean interface
public class AvailableProcessors implements AvailableProcessorsMBean {
  // return the available processors as an integer value
  public Integer queryAvailableProcessors() {
    // we use the java.lang.Runtime API
    return Runtime.getRuntime().availableProcessors();
  }
}

2.2 Implement the node MBean provider interface

To make our MBean pluggable to the nodes, it must be recognized as a corresponding service instance. To this effect, we will create an implementation of the interface JPPFNodeMBeanProvider, which will provide the node with enough information to create the MBean and register it with the MBean server. This interface is defined as follows:

// service provider interface for pluggable management beans for JPPF nodes
public interface JPPFNodeMBeanProvider extends JPPFMBeanProvider {
  // return a concrete MBean instance, whose class must implement the interface defined by
  // JPPFMBeanProvider.getMBeanInterfaceName()
  public Object createMBean(Node node);
}

Please note that the parameter passed to createMBean(Node) allows the MBean to access information on the node via the Node API.

As we can see, this interface declares a single method whose role is to create an instance of our MBean implementation. There is no obligation to use the node parameter, it is provided here because the JPPF built-in node MBean use it. As stated in the method comment, the class of the created object must implement an MBean interface, whose name is given by the method getMBeanInterfaceName() in the super-interface JPPFMBeanProvider, defined as follows:

// service provider interface for pluggable management beans
public interface JPPFMBeanProvider {
  // get the fully qualified name of the management interface defined by this provider
  public String getMBeanInterfaceName();

  // get the name of the specified MBean, under which the MBean will be registered with the MBean server
  public String getMBeanName();
}

Note that the MBean name must follow the specifications for MBean object names.


We will then write our MBean provider implementation. Generally, the convention is to create it in a separate package, whose name is that of the MBean interface with a “.spi” suffix. We will write it as follows:

package org.jppf.example.mbean.node.spi;

// AvailableProcessors MBean provider implementation
public class AvailableProcessorsMBeanProvider implements JPPFNodeMBeanProvider {
  // return the fully qualified name of the MBean interface defined by this provider
  @Override
  public String getMBeanInterfaceName() {
    return "org.jppf.example.mbean.AvailableProcessorsMBean";
  }

  // create a concrete MBean instance
  @Override
  public Object createMBean(Node node) {
    return new AvailableProcessors();
  }

  // return the object name of the specified MBean
  @Override
  public String getMBeanName() {
    return "org.jppf.example.node.mbean:name=AvailableProcessors,type=node";
  }
}

2.3 Create the service definition file

If it doesn't already exist, we create, in the source folder, a subfolder named META-INF/services. In this folder, we will create a file named org.jppf.management.spi.JPPFNodeMBeanProvider, and open it in a text editor. In the editor, we add a single line containing the fully qualified name of our MBean provider class:

org.jppf.example.mbean.node.spi.AvailableProcessorsMBeanProvider

2.4 Deploy the MBean

First, create a jar that contains all the artifacts we have created: MBean interface, MBean implementation and MBean provider class files, along with the META-INF/services folder. We now have two deployment choices: we can either deploy the MBean on a single node, or deploy it on the server side to make it available to all the nodes attached to the server. To do so, we simply add our deployment jar file to the class path of the node or of the server.

2.5 Using the MBean

We can now write a simple class to test our new custom MBean:

package org.jppf.example.node.test;

import org.jppf.management.JMXNodeConnectionWrapper;

// simple class to test a custom node MBean
public class AvailableProcessorsMBeanTest {
  public static void main(String...args) throws Exception {
    // we assume the node is running on localhost and uses the management port 12001
    JMXNodeConnectionWrapper wrapper = 
      new JMXNodeConnectionWrapper("localhost", 12001);
    wrapper.connectAndWait(5000L);
    // query the node for the available processors
    int n = (Integer) wrapper.invoke(
      "org.jppf.example.mbean:name=AvailableProcessors,type=node",
      "queryAvailableProcessors", (Object[]) null, (String[]) null);
    System.out.println("The node has " + n + " available processors");
  }
}

3 Writing a custom server MBean

The process is almost exactly the same as for adding custom MBeans to a node. In this example, we will reuse the MBean that we wrote in the previous section, as it applies to any JVM, whether node or server.

3.1 Create the MBean interface and its implementation

We will simply reuse the interface AvailableProcessorsMBean and its implementation AvailableProcessors that we have already created.

3.2 Implement the server MBean provider interface

This time , we will implement the interface JPPFDriverMBeanProvider, defined as follows:

public interface JPPFDriverMBeanProvider extends JPPFMBeanProvider {
  // Return a concrete MBean instance
  Object createMBean();

  // Return a concrete MBean instance
  default Object createMBean(JPPFDriver driver) {
    return createMBean();
  }
}

The JPPF driver will always call createMBean(JPPFDriver) when creating a custom MBean. Note that its default implementation merely delegates to createMBean() without using the parameter. Implementations that wish to use the JPPFDriver API should overrride this method.

Our server MBean provider implementation is like this:

package org.jppf.example.mbean.driver.spi;

import org.jppf.example.mbean.AvailableProcessors;
import org.jppf.management.spi.JPPFDriverMBeanProvider;

// AvailableProcessors MBean provider implementation
public class AvailableProcessorsMBeanProvider implements JPPFDriverMBeanProvider {
  // return the fully qualified name of the MBean interface defined by this provider
  public String getMBeanInterfaceName() {
    return "org.jppf.example.mbean.AvailableProcessorsMBean";
  }

  // create a concrete MBean instance
  public Object createMBean() {
    return new AvailableProcessors();
  }

  // return the object name of the specified MBean
  public String getMBeanName() {
    return "org.jppf.example.mbean:name=AvailableProcessors,type=driver";
  }
}

This looks almost exactly the same as for the node MBean provider, except for the following differences:

  • the implemented interface is JPPFDriverMbeanProvider, and its createMBean() method takes no parameter
  • we gave a different object name to our MBean: “...,type=driver
  • we created the MBean provider in a different package named org.jppf.example.mbean.driver.spi.

3.3 Create the service definition file

If it doesn't already exist, we create, in the source folder, a subfolder named META-INF/services. In this folder, we will create a file named org.jppf.management.spi.JPPFDriverMBeanProvider, and open it in a text editor. In the editor, we add a single line containing the fully qualified name of our MBean provider class:

org.jppf.example.mbean.driver.spi.AvailableProcessorsMBeanProvider

3.4 Deploy the MBean

Now we just create a jar that contains all the artifacts we have created: MBean interface, MBean implementation and MBean provider class files, along with the META-INF/services folder, and add it to the class path of the server.

3.5 Using the MBean

We can write the following simple class to test our new server custom MBean:

package org.jppf.example.driver.test;

import org.jppf.management.JMXDriverConnectionWrapper;

// simple class to test a custom node MBean
public class AvailableProcessorsMBeanTest {
  public static void main(String...args) throws Exception {
    // we assume the server is running on localhost and uses the management port 11198
    JMXDriverConnectionWrapper wrapper = 
      new JMXDriverConnectionWrapper("localhost", 11198);
    wrapper.connectAndWait(5000L);
    // query the node for the available processors
    int n = (Integer) wrapper.invoke(
      "org.jppf.example.mbean:name=AvailableProcessors,type=driver",
      "queryAvailableProcessors", (Object[]) null, (String[]) null);
    System.out.println("The server has " + n + " available processors");
  }
}
Main Page > Customizing JPPF > Pluggable MBeans



JPPF Copyright © 2005-2020 JPPF.org Powered by MediaWiki