MBeans

RMI MBean example

Introduction

The purpose of this example is to give some guideline on how to expose RMI remote objects also as MBeans.

This will give to server administrators the possibility to manage RMI remote objects in the JMX sense. This means that may be possible to start, stop and restart the service implemented by the remote object; and also checking if it is running, or ask to reload configurations files.

The example classes

The example java source files can be found in the examples directory under mbeans/rmi, they include:

  • Server (the class that starts the remote service)
  • Client (the client class)
  • MyRemoteService (the remote interface)
  • MyRemoteServiceObjectMBean (the management interface)
  • MyRemoteServiceObject (the MBean that implements the remote interface)

Understanding the example

The remote object is, at the same time an MBean and an RMI remote object.

Clients can see it through 2 interfaces: users of the service see it through the remote interface ( MyRemoteService), while management application (such as the HTTP adaptor) see it through the management interface ( MyRemoteServiceObjectMBean).
The remote interface contains only one method:

public void sayHello(String name)

that will execute client's requests.
The management interface, conversely, contains 3 methods:

public void start()
public void stop()
public boolean isRunning()

that will be used by management application such as the HTTP adaptor.

Notice that users of the remote interface cannot invoke methods of the management interface, as well as management application cannot invoke methods of the remote interface.

The implementation

The purpose of the Server class is only to start a JMX Agent by instantiating the MBeanServer, register the service we want to expose, and starting it.

Example 7.4. The Server class

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

      ObjectName name = new ObjectName("examples:type=remote");
      MyRemoteServiceObject remote = new MyRemoteServiceObject();
      server.registerMBean(remote, name);

      MyRemoteServiceObjectMBean managed = (MyRemoteServiceObjectMBean)MBeanServerInvocationHandler.newProxyInstance(server, name, MyRemoteServiceObjectMBean.class, false);
      managed.start();
   }
}
               
               

The remote object, instance of MyRemoteServiceObject class, is worth some more detail.
First notice that it extends java.rmi.server.RemoteServer and not java.rmi.server.UnicastRemoteObject. This is done to avoid that the object is automatically exported to the RMI runtime when creating it, since we want to control the export and unexport via the start() and stop() methods of the management interface.
Second, notice the symmetry of the start() and stop() methods: start() export the object to the RMI runtime and binds it in the naming, while stop() unbinds it from the naming and unexport it from the RMI runtime.

Example 7.5. The MyRemoteServiceObject class

                  
public class MyRemoteServiceObject extends RemoteServer implements MyRemoteService, MyRemoteServiceObjectMBean
{
   private boolean m_running;

   public MyRemoteServiceObject() throws RemoteException {}

   public void sayHello(String name) throws RemoteException
   {
      System.out.println("Hello, " + name);
   }

   public void start() throws Exception
   {
      if (!m_running)
      {
         UnicastRemoteObject.exportObject(this);
         InitialContext ctx = new InitialContext();
         ctx.rebind(JNDI_NAME, this);
         m_running = true;
         System.out.println("My remote service started successfully");
      }
   }

   public void stop() throws Exception
   {
      if (m_running)
      {
         InitialContext ctx = new InitialContext();
         ctx.unbind(JNDI_NAME);
         UnicastRemoteObject.unexportObject(this, false);
         m_running = false;
         System.out.println("My remote service stopped successfully");
      }
   }

   public boolean isRunning()
   {
      return m_running;
   }
}
               
               

Thus, will be possible to start the service via a management application and let it available to users; and will be possible to stop it, maybe changing some configuration file (not in this simple example, but you got the picture), and restarting it, WITHOUT shutting down other services that may have been started by the same JMX Agent.

The implementation of the sayHello(String name) method is straightforward, as well as the isRunning() one that, accessible from management applications, returns if the service is running or not.

Compiling the example files

The above classes must be compiled using javac, and the MyRemoteServiceObject class must be compiled using rmic.

Let's suppose you unpack the MX4J distribution in the mx4j- ver directory; from this directory you issue these commands:

C:\mx4j- ver>javac -classpath lib\mx4j-jmx.jar examples\mbeans\rmi\*.java
C:\mx4j- ver>rmic mx4j.examples.mbeans.rmi.MyRemoteServiceObject

Running the example

To run the example, three consoles are needed:

  • One for the rmiregistry
  • One for the server
  • One for the client

For the rmiregistry, you need to have in the classpath the RMI stub of the MyRemoteServiceObject class you just compiled with rmic. Then you can start it by typing the following command:

C:\mx4j- ver>set classpath=.
C:\mx4j- ver>rmiregistry

For the server, you need all the compiled classes (apart for the Client class), mx4j-jmx.jar (the JMX implementation), and a suitable jndi.properties file (there is a default one shipped with this example) in the classpath. Then you can start the server with the following command:

C:\mx4j- ver>java -cp .;examples;lib\mx4j-jmx.jar mx4j.examples.mbeans.rmi.Server

For the client, you need the Client class, the remote interface and the RMI stub, and a suitable jndi.properties file (there is a default one shipped with this example). Then you can start the client with the following command:

C:\mx4j- ver>java -cp .;examples mx4j.examples.mbeans.rmi.Client