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 java source files can be found in the examples directory under mbeans/rmi, they include:
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 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.
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
To run the example, three consoles are needed:
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