When you are writing software that runs in the background, you will sooner or later have the need to monitor and/or administrate it. There are several ways to add this feature to your program, one of the easiest is to use the Java Management eXtension, JMX in short.
JMX is included since Java 1.5 with a lot of extensions in Java 1.6. If you plan to use it, I recommend using at least Java 1.6.
To put it shortly, every Java program has a built-in service (the JMX agent), which allows a separate program (the JMX client) to monitor it and perform administrative tasks. Clients can connect to your program in different ways, allowing local and remote connections. Most professional and public domain administration/monitoring applications now support JMX. There are also bridges between SNMP (Simple Network Management Protocol) and JMX. Java (the JDK) comes with two administration clients, the older JConsole and the newer JVisualVM.
How to JMX enable your software
To enable your software to be managed by JMX clients, you simply have to register one or more so called Managed Beans (MBeans) with the Java engine. Simply said, an MBean is a Java class that gives a JMX client access to methods and data, you implement.
To show this in a working example, I will create a simple Java program that has a state that can be changed by entering a new state string in the console.
(Listing 1, Test server)
package com.udojava.blog.jmx;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class SimpleTestServer {
private String serverState = "started";
public String getServerState() {
return serverState;
}
public void setServerState(String serverState) {
this.serverState = serverState;
}
public void startServer() throws IOException {
String input = "";
BufferedReader console = new BufferedReader(new InputStreamReader(
System.in));
while (!input.equalsIgnoreCase("q")) {
System.out.println("Enter new state, q to quit:");
input = console.readLine();
setServerState(input);
System.out.println("New state: " + getServerState());
}
System.out.println("Aborted from console.");
}
public static void main(String[] args) throws IOException {
SimpleTestServer server = new SimpleTestServer();
server.startServer();
}
}
In the next step, I will allow a JMX client to show and change the state and also to shut down the program. I will define a managed bean that will do this all. A managed bean is made up by a Java interface, which defines the contract and a Java class that actually implements the interface.
(Listing 2, Interface)
package com.udojava.blog.jmx;
public interface SimpleTestAdminMBean {
public void setServerState(String newState);
public String getServerState();
public void shutDownServer(String reason);
}
In the interface, I have defined the three operations for reading and writing the server state and for shutting down the server. Note that the shutdown method also has a parameter, where the JMX client can give a reason for the shutdown.
(Listing 3, Bean class)
package com.udojava.blog.jmx;
public class SimpleTestAdmin implements SimpleTestAdminMBean {
private SimpleTestServer server;
public SimpleTestAdmin(SimpleTestServer theServer) {
this.server = theServer;
}
@Override
public void setServerState(String newState) {
System.out.println("Setting new state through JMX: " + newState);
server.setServerState(newState);
}
@Override
public String getServerState() {
return server.getServerState();
}
@Override
public void shutDownServer(String reason) {
System.out.println("Shutting down through JMX, reason: " + reason);
/*
* Shut down in a separate thread, so that this method
* can return before the program exits.
*/
new Thread(new Runnable() {
@Override
public void run() {
System.exit(0);
}
}).start();
}
}
Notice that I also defined a constructor that takes the server instance as a parameter, so that I can access the server functionality from the bean. By convention, the bean interface has a name that is the implementation class name plus the extension MBean.
In the last step, I will create and register the managed bean with the built in JMX server. To do this, I add a few lines to the startServer() method of my server class.
(Listing 4, JMX enabled server)
public void startServer() throws IOException {
/*
* Register JMX bean
*/
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName mxBeanName;
try {
mxBeanName = new ObjectName(
"com.udojava.blog.jmx:type=SimpleTestAdmin,name=Server Info");
SimpleTestAdmin mxBean = new SimpleTestAdmin(this);
mbs.registerMBean(mxBean, mxBeanName);
} catch (Exception e) {
System.out.println("Error registering JMX");
e.printStackTrace();
}
String input = "";
BufferedReader console = new BufferedReader(new InputStreamReader(
System.in));
while (!input.equalsIgnoreCase("q")) {
System.out.println("Enter new state, q to quit:");
input = console.readLine();
setServerState(input);
System.out.println("New state: " + getServerState());
}
System.out.println("Aborted from console.");
}
Note that the bean name is not just a simple name string, but an object that is constructed using a domain name, a type and a name. This syntax follows the JMX standard to name managed bean instances.
Testing with a JMX client
First start the demo server, and then go to your Java JDK installation directory. In the bin folder, you will find two JMX clients, JConsole and JVisualVM. When you start them, each one will present you with a list of local running Java programs. Go to the MBeans tab and you can browse there to the defined bean and set/get the server state and shutdown the server from JConsole. With JVisualVM you probably will need to install the MBean plugin first. In that case go to the tools menu, select plugins and available plugins, select the MBeans plugin and follow the instructions.

JConsole MBeans view
Some links for more information:
The Java JMX Tutorial
JVisualVM Home
Like this:
Like Loading...