Trail: Java Management Extensions (JMX)
The Java Management Extensions (JMX) trail provides an introduction to the JMX technology, which is included in the Java Platform, Standard Edition (Java SE platform). This trail presents examples of how to use the most important features of the JMX technology.
Overview of the JMX Technology provides a brief description of the JMX technology, including its purpose and principal features.
Introducing MBeans introduces the fundamental concept of the JMX technology, managed beans, otherwise known as MBeans. This lesson also introduces MXBeans.
Notifications introduces the JMX technology's notification mechanism.
Remote Management shows how to implement the JMX API's remote management capabilities and how to create a JMX client application.
Where to Go From Here provides pointers to more advanced documentation that describes the JMX technology.
Lesson: Overview of the JMX Technology
The Java Management Extensions (JMX) technology is a standard part of the Java Platform, Standard Edition (Java SE platform). The JMX technology was added to the platform in the Java 2 Platform, Standard Edition (J2SE) 5.0 release.
The JMX technology provides a simple, standard way of managing resources such as applications, devices, and services. Because the JMX technology is dynamic, you can use it to monitor and manage resources as they are created, installed and implemented. You can also use the JMX technology to monitor and manage the Java Virtual Machine (Java VM).
The JMX specification defines the architecture, design patterns, APIs, and services in the Java programming language for management and monitoring of applications and networks.
Using the JMX technology, a given resource is instrumented by one or more Java objects known as Managed Beans, or MBeans. These MBeans are registered in a core-managed object server, known as an MBean server. The MBean server acts as a management agent and can run on most devices that have been enabled for the Java programming language.
The specifications define JMX agents that you use to manage any resources that have been correctly configured for management. A JMX agent consists of an MBean server, in which MBeans are registered, and a set of services for handling the MBeans. In this way, JMX agents directly control resources and make them available to remote management applications.
The way in which resources are instrumented is completely independent from the management infrastructure. Resources can therefore be rendered manageable regardless of how their management applications are implemented.
The JMX technology defines standard connectors (known as JMX connectors) that enable you to access JMX agents from remote management applications. JMX connectors using different protocols provide the same management interface. Consequently, a management application can manage resources transparently, regardless of the communication protocol used. JMX agents can also be used by systems or applications that are not compliant with the JMX specification, as long as those systems or applications support JMX agents
Why Use the JMX Technology?
The JMX technology provides developers with a flexible means to instrument Java technology-based applications (Java applications), create smart agents, implement distributed management middleware and managers, and smoothly integrate these solutions into existing management and monitoring systems.
The JMX technology enables Java applications to be managed without heavy investment.
A JMX technology-based agent (JMX agent) can run on most Java technology-enabled devices. Consequently, Java applications can become manageable with little impact on their design. A Java application needs only to embed a managed object server and make some of its functionality available as one or several managed beans (MBeans) registered in the object server. That is all it takes to benefit from the management infrastructure.
The JMX technology provides a standard way to manage Java applications, systems, and networks.
For example, the Java Platform, Enterprise Edition (Java EE) 5 Application Server conforms to the JMX architecture and consequently can be managed by using JMX technology.
The JMX technology can be used for out-of-the-box management of the Java VM.
The Java Virtual Machine (Java VM) is highly instrumented using the JMX technology. You can start a JMX agent to access the built-in Java VM instrumentation, and thereby monitor and manage a Java VM remotely.
The JMX technology provides a scalable, dynamic management architecture.
Every JMX agent service is an independent module that can be plugged into the management agent, depending on the requirements. This component-based approach means that JMX solutions can scale from small-footprint devices to large telecommunications switches and beyond. The JMX specification provides a set of core agent services. Additional services can be developed and dynamically loaded, unloaded, or updated in the management infrastructure.
The JMX technology leverages existing standard Java technologies.
Whenever needed, the JMX specification references existing Java specifications, for example, the Java Naming and Directory Interface (J.N.D.I.) API.
The JMX technology-based applications (JMX applications) can be created from a NetBeans IDE module.
You can obtain a module from the NetBeans Update Center (select Tools -> Update Center in the NetBeans interface) that enables you to create JMX applications by using the NetBeans IDE. This reduces the cost of development of JMX applications.
The JMX technology integrates with existing management solutions and emerging technologies.
The JMX APIs are open interfaces that any management system vendor can implement. JMX solutions can use lookup and discovery services and protocols such as Jini network technology and the Service Location Protocol (SLP).
Architecture of the JMX Technology
The JMX technology can be divided into three levels, as follows:
· Instrumentation
· JMX agent
· Remote management
Instrumentation
To manage resources using the JMX technology, you must first instrument the resources in the Java programming language. You use Java objects known as MBeans to implement the access to the resources' instrumentation. MBeans must follow the design patterns and interfaces defined in the JMX specification. Doing so ensures that all MBeans provide managed resource instrumentation in a standardized way. In addition to standard MBeans, the JMX specification also defines a special type of MBean called an MXBean. An MXBean is an MBean that references only a pre-defined set of data types. Other types of MBean exist, but this trail will concentrate on standard MBeans and MXBeans.
Once a resource has been instrumented by MBeans, it can be managed through a JMX agent. MBeans do not require knowledge of the JMX agent with which they will operate.
MBeans are designed to be flexible, simple, and easy to implement. Developers of applications, systems, and networks can make their products manageable in a standard way without having to understand or invest in complex management systems. Existing resources can be made manageable with minimum effort.
In addition, the instrumentation level of the JMX specification provides a notification mechanism. This mechanism enables MBeans to generate and propagate notification events to components of the other levels.
JMX Agent
A JMX technology-based agent (JMX agent) is a standard management agent that directly controls resources and makes them available to remote management applications. JMX agents are usually located on the same machine as the resources they control, but this arrangement is not a requirement.
The core component of a JMX agent is the MBean server, a managed object server in which MBeans are registered. A JMX agent also includes a set of services to manage MBeans, and at least one communications adaptor or connector to allow access by a management application.
When you implement a JMX agent, you do not need to know the semantics or functions of the resources that it will manage. In fact, a JMX agent does not even need to know which resources it will serve because any resource instrumented in compliance with the JMX specification can use any JMX agent that offers the services that the resource requires. Similarly, the JMX agent does not need to know the functions of the management applications that will access it.
Remote Management
JMX technology instrumentation can be accessed in many different ways, either through existing management protocols such as the Simple Network Management Protocol (SNMP) or through proprietary protocols. The MBean server relies on protocol adaptors and connectors to make a JMX agent accessible from management applications outside the agent's Java Virtual Machine (Java VM).
Each adaptor provides a view through a specific protocol of all MBeans that are registered in the MBean server. For example, an HTML adaptor could display an MBean in a browser.
Connectors provide a manager-side interface that handles the communication between manager and JMX agent. Each connector provides the same remote management interface through a different protocol. When a remote management application uses this interface, it can connect to a JMX agent transparently through the network, regardless of the protocol. The JMX technology provides a standard solution for exporting JMX technology instrumentation to remote applications based on Java Remote Method Invocation (Java RMI).
Monitoring and Management of the Java Virtual Machine
The JMX technology can also be used to monitor and manage the Java virtual machine (Java VM).
The Java VM has built-in instrumentation that enables you to monitor and manage it by using the JMX technology. These built-in management utilities are often referred to as out-of-the-box management tools for the Java VM. To monitor and manage different aspects of the Java VM, the Java VM includes a platform MBean server and special MXBeans for use by management applications that conform to the JMX specification.
Platform MXBeans and the Platform MBean Server
The platform MXBeans are a set of MXBeans that is provided with the Java SE platform for monitoring and managing the Java VM and other components of the Java Runtime Environment (JRE). Each platform MXBean encapsulates a part of Java VM functionality, such as the class-loading system, just-in-time (JIT) compilation system, garbage collector, and so on. These MXBeans can be displayed and interacted with by using a monitoring and management tool that complies with the JMX specification, to enable you to monitor and manage these different VM functionalities. One such monitoring and management tool is the Java SE platform's JConsole graphical user interface (GUI).
The Java SE platform provides a standard platform MBean server in which these platform MXBeans are registered. The platform MBean server can also register any other MBeans you wish to create.
JConsole
The Java SE platform includes the JConsole monitoring and management tool, which complies with the JMX specification. JConsole uses the extensive instrumentation of the Java VM (the platform MXBeans) to provide information about the performance and resource consumption of applications that are running on the Java platform.
Out-of-the-Box Management in Action
Because standard monitoring and management utilities that implement the JMX technology are built into the Java SE platform, you can see the out-of-the-box JMX technology in action without having to write a single line of JMX API code. You can do so by launching a Java application and then monitoring it by using JConsole.
Monitoring an Application by Using JConsole
This procedure shows how to monitor the Notepad Java application. This procedure assumes that you are running the Java SE 6 platform.
- Start the Notepad Java application, by using the following command in a terminal window:
java -jar jdk_home/demo/jfc/Notepad/Notepad.jar
Where jdk_home
is the directory in which the Java Development Kit (JDK) is installed.
- Once Notepad has opened, in a different terminal window, start JConsole by using the following command:
jconsole
A New Connection dialog box is displayed.
- In the New Connection dialog box, select
Notepad.jar
from the Local Process list, and click the Connect button.
JConsole opens and connects itself to the Notepad.jar
process. When JConsole opens, you are presented with an overview of monitoring and management information related to Notepad. For example, you can view the amount of heap memory the application is consuming, the number of threads the application is currently running, and how much central procesing unit (CPU) capacity the application is consuming.
- Click the different JConsole tabs.
Each tab presents more detailed information about the different areas of functionality of the Java VM in which Notepad is running. All the information presented is obtained from the various JMX technology MXBeans mentioned in this trail. All the platform MXBeans can be displayed in the MBeans tab. The MBeans tab is examined in the next section of this trail.
- To close JConsole, select Connection -> Exit.
Lesson: Introducing MBeans
This lesson introduces the fundamental concept of the JMX API, namely managed beans, or MBeans.
An MBean is a managed Java object, similar to a JavaBeans component, that follows the design patterns set forth in the JMX specification. An MBean can represent a device, an application, or any resource that needs to be managed. MBeans expose a management interface that consists of the following:
A set of readable or writable attributes, or both.
A set of invokable operations.
A self-description.
The management interface does not change throughout the life of an MBean instance. MBeans can also emit notifications when certain predefined events occur.
The JMX specification defines five types of MBean:
Standard MBeans
Dynamic MBeans
Open MBeans
Model MBeans
MXBeans
The examples in this trail demonstrate only the simplest types of MBean, namely standard MBeans and MXBeans.
Standard MBeans
This section presents an example of a straightforward, standard MBean.
A standard MBean is defined by writing a Java interface called SomethingMBean
and a Java class called Something
that implements that interface. Every method in the interface defines either an attribute or an operation in the MBean. By default, every method defines an operation. Attributes and operations are methods that follow certain design patterns. A standard MBean is composed of an MBean interface and a class. The MBean interface lists the methods for all exposed attributes and operations. The class implements this interface and provides the functionality of the instrumented resource.
The following sections examine an example of a standard MBean and a simple JMX technology-enabled agent (JMX agent) that manages the MBean.
MBean Interface
An example of a basic MBean interface, HelloMBean
, follows:
package com.example;
public interface HelloMBean {
public void sayHello();
public int add(int x, int y);
public String getName();
public int getCacheSize();
public void setCacheSize(int size);
}
By convention, an MBean interface takes the name of the Java class that implements it, with the suffix MBean
added. In this case, the interface is called HelloMBean
. The Hello
class that implements this interface is described in the next section.
According to the JMX specification, an MBean interface consists of named and typed attributes that are readable and possibly writable, in addition to the named and typed operations that can be invoked by the applications that are managed by the MBean. The HelloMBean
interface declares two operations: the Java methods add()
and sayHello()
.
HelloMBean
declares two attributes: Name
is a read-only string, and CacheSize
is an integer that can be both read and written. Getter and setter methods are declared to allow the managed application to access and possibly change the attribute values. As defined by the JMX specification, a getter is any public method that does not return void and whose name begins with get
. A getter enables a manager to read the value of the attribute, whose type is that of the returned object. A setter is any public method that takes a single parameter and whose name begins with set
. A setter enables a manager to write a new value in the attribute, whose type is the same as that of the parameter.
The implementation of these operations and attributes is shown in the following section.
MBean Implementation
The Hello
Java class that follows implements the HelloMBean
MBean interface:
package com.example;
public class Hello [...] implements HelloMBean {
public void sayHello() {
System.out.println("hello, world");
}
public int add(int x, int y) {
return x + y;
}
public String getName() {
return this.name;
}
public int getCacheSize() {
return this.cacheSize;
}
public synchronized void setCacheSize(int size) {
[...]
this.cacheSize = size;
System.out.println("Cache size now " + this.cacheSize);
}
[...]
private final String name = "Reginald";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int DEFAULT_CACHE_SIZE = 200;
}
The straightforward Hello
class provides the definitions of the operations and attributes that are declared by HelloMBean
. The sayHello()
and add()
operations are extremely simple, but real-life operations can be as simple or as sophisticated as needed.
The methods to get the Name
attribute and to get and set the CacheSize
attribute are also defined. In this example, the Name
attribute value never changes. However, in a real scenario this attribute might change as the managed resource runs. For example, the attribute might represent statistics such as uptime or memory usage. Here, the attribute is merely the name Reginald
.
Calling the setCacheSize
method enables you to alter the CacheSize
attribute from its declared default value of 200. In a real scenario, changing the CacheSize
attribute could require other operations to be performed, such as discarding entries or allocating new entries. This example merely prints a message to confirm that the cache size has changed. However, more sophisticated operations could be defined instead of the simple call to println()
.
With the Hello
MBean and its interface thus defined, they can now be used to manage the resource they represent, as shown in the following section.
Creating a JMX Agent to Manage a Resource
Once a resource has been instrumented by MBeans, the management of that resource is performed by a JMX agent.
The core component of a JMX agent is the MBean server. An MBean server is a managed object server in which MBeans are registered. A JMX agent also includes a set of services to manage MBeans. See the API documentation for the MBeanServer
interface for details of the MBean server implementation.
The Main
class that follows represents a basic JMX agent:
package com.example;
import java.lang.management.*;
import javax.management.*;
public class Main {
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("com.example:type=Hello");
Hello mbean = new Hello();
mbs.registerMBean(mbean, name);
[...]
System.out.println("Waiting forever...");
Thread.sleep(Long.MAX_VALUE);
}
}
The JMX agent Main
begins by obtaining an MBean server that has been created and initialized by the platform, by calling the getPlatformMBeanServer()
method of the java.lang.management.ManagementFactory
class. If no MBean server has been created by the platform already, then getPlatformMBeanServer()
creates an MBean server automatically by calling the JMX method MBeanServerFactory.createMBeanServer()
. The MBeanServer
instance obtained by Main
is named mbs.
Next, Main
defines an object name for the MBean instance that it will create. Every JMX MBean must have an object name. The object name is an instance of the JMX class ObjectName
and must conform to the syntax defined by the JMX specification. Namely, the object name must contain a domain and a list of key-properties. In the object name defined by Main
, the domain is com.example
(the package in which the example MBean is contained). In addition, the key-property declares that this object is of the type Hello
.
An instance of a Hello
object, named mbean
, is created. The Hello
object named mbean
is then registered as an MBean in the MBean server mbs
with the object name name
, by passing the object and the object name into a call to the JMX method MBeanServer.registerMBean()
.
With the Hello
MBean registered in the MBean server, Main
simply waits for management operations to be performed on Hello
. In this example, these management operations are invoking sayHello()
and add()
, and getting and setting the attribute values.
Running the Standard MBean Example
Having examined the example classes, you can now run the example. In this example, JConsole is used to interact with the MBean.
To run the example, follow these steps:
- Save the bundle of JMX API sample classes,
jmx_examples.zip
, to your working directory, work_dir
.
- Unzip the bundle of sample classes by using the following command in a terminal window.
unzip jmx_examples.zip
- Compile the example Java classes from within the
work_dir
directory.
javac com/example/*.java
- Start the
Main
application.
java com.example.Main
A confirmation that Main
is waiting for something to happen is displayed.
- Start JConsole in a different terminal window on the same machine.
jconsole
The New Connection dialog box is displayed, presenting a list of running JMX agents that you can connect to.
- In the New Connection dialog box, select
com.example.Main
from the list and click Connect.
A summary of your platform's current activity is displayed.
- Click the MBeans tab.
This panel shows all the MBeans that are currently registered in the MBean server.
- In the left frame, expand the
com.example
node in the MBean tree.
You see the example MBean Hello
that was created and registered by Main
. If you click Hello
, you see its associated Attributes and Operations nodes in the MBean tree.
- Expand the Attributes node of the
Hello
MBean in the MBean tree.
The MBean attributes that were defined by the Hello
class are displayed.
- Change the value of the
CacheSize
attribute to 150.
In the terminal window in which you started Main
, a confirmation of this attribute change is generated.
- Expand the Operations node of the
Hello
MBean in the MBean tree.
The two operations declared by the Hello
MBean, sayHello()
and add()
, are visible.
- Invoke the
sayHello()
operation by clicking the sayHello
button.
A JConsole dialog box informs you that the method was invoked successfully. The message "hello, world" is generated in the terminal window in which Main
is running.
- Provide two integers for the
add()
operation to add and click the add
button.
The answer is displayed in a JConsole dialog box.
- To close JConsole, select Connection -> Exit.
MXBeans
This section explains a special type of MBean, called MXBeans.
An MXBean is a type of MBean that references only a predefined set of data types. In this way, you can be sure that your MBean will be usable by any client, including remote clients, without any requirement that the client have access to model-specific classes representing the types of your MBeans. MXBeans provide a convenient way to bundle related values together, without requiring clients to be specially configured to handle the bundles.
In the same way as for standard MBeans, an MXBean is defined by writing a Java interface called SomethingMXBean
and a Java class that implements that interface. However, unlike standard MBeans, MXBeans do not require the Java class to be called Something
. Every method in the interface defines either an attribute or an operation in the MXBean. The annotation @MXBean
can be also used to annotate the Java interface, instead of requiring the interface's name to be followed by the MXBean suffix.
MXBeans existed in the Java 2 Platform, Standard Edition (J2SE) 5.0 software, in the package java.lang.management
. However, users can now define their own MXBeans, in addition to the standard set that is defined in java.lang.management
.
The main idea behind MXBeans is that types such as java.lang.management.MemoryUsage
that are referenced in the MXBean interface, java.lang.management.MemoryMXBean
in this case, are mapped into a standard set of types, the so-called Open Types that are defined in the package javax.management.openmbean
. The exact mapping rules appear in the MXBean specification. However, the general principle is for simple types such as int or String to remain unchanged, while complex types such as MemoryUsage
get mapped to the standard type CompositeDataSupport
.
The MXBean example consists of the following files, which are found in jmx_examples.zip
:
QueueSamplerMXBean
interface
QueueSampler
class that implements the MXBean interface
QueueSample
Java type returned by the getQueueSample()
method in the MXBean interface
Main
, the program that sets up and runs the example
The MXBean example uses these classes to perform the following actions:
- Defines a simple MXBean that manages a resource of type
Queue<String>
- Declares a getter,
getQueueSample
, in the MXBean that takes a snapshot of the queue when invoked and returns a Java class QueueSample
that bundles the following values together:
- The time the snapshot was taken
- The queue size
- The head of the queue at that given time
- Registers the MXBean in an MBean server
MXBean Interface
The following code shows the example QueueSamplerMXBean
MXBean interface:
package com.example;
public interface QueueSamplerMXBean {
public QueueSample getQueueSample();
public void clearQueue();
}
Note that you declare an MXBean interface in exactly the same way as you declare a standard MBean interface. The QueueSamplerMXBean
interface declares a getter, getQueueSample
and an operation, clearQueue
.
Defining MXBean Operations
The MXBean operations are declared in the QueueSampler
example class, as follows:
package com.example;
import java.util.Date;
import java.util.Queue;
public class QueueSampler implements QueueSamplerMXBean {
private Queue queue;
public QueueSampler(Queue queue) {
this.queue = queue;
}
public QueueSample getQueueSample() {
synchronized (queue) {
return new QueueSample(new Date(), queue.size(), queue.peek());
}
}
public void clearQueue() {
synchronized (queue) {
queue.clear();
}
}
}
QueueSampler
defines the getQueueSample()
getter and clearQueue()
operation that were declared by the MXBean interface. The getQueueSample()
operation returns an instance of the QueueSample
Java type which was created with the values returned by the java.util.Queue
methods peek()
and size()
, and an instance of java.util.Date
.
Defining the Java Type Returned by the MXBean Interface
The QueueSample
instance returned by QueueSampler
is defined in the QueueSample
class, as follows:
package com.example;
import java.beans.ConstructorProperties;
import java.util.Date;
public class QueueSample {
private final Date date;
private final int size;
private final String head;
@ConstructorProperties({"date", "size", "head"})
public QueueSample(Date date, int size, String head) {
this.date = date;
this.size = size;
this.head = head;
}
public Date getDate() {
return date;
}
public int getSize() {
return size;
}
public String getHead() {
return head;
}
}
In the QueueSample
class, the MXBean framework calls all the getters in QueueSample
to convert the given instance into a CompositeData
instance and uses the @ConstructorProperties
annotation to reconstruct a QueueSample
instance from a CompositeData
instance.
Creating and Registering the MXBean in the MBean Server
So far, the following have been defined: an MXBean interface and the class that implements it, as well as the Java type that is returned. Next, the MXBean must be created and registered in an MBean server. These actions are performed by the same Main
example JMX agent that was used in the standard MBean example, but the relevant code was not shown in the Standard MBean lesson.
package com.example;
import java.lang.management.ManagementFactory;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import javax.management.MBeanServer;
import javax.management.ObjectName;
public class Main {
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
[...]
ObjectName mxbeanName = new ObjectName("com.example:type=QueueSampler");
Queue queue = new ArrayBlockingQueue(10);
queue.add("Request-1");
queue.add("Request-2");
queue.add("Request-3");
QueueSampler mxbean = new QueueSampler(queue);
mbs.registerMBean(mxbean, mxbeanName);
System.out.println("Waiting...");
Thread.sleep(Long.MAX_VALUE);
}
}
The Main
class performs the following actions:
- Gets the platform MBean server.
- Creates an object name for the MXBean
QueueSampler.
- Creates a
Queue
instance for the QueueSampler
MXBean to process.
- Feeds the
Queue
instance to a newly created QueueSampler
MXBean.
- Registers the MXBean in the MBean server in exactly the same way as a standard MBean.
Running the MXBean Example
The MXBean example uses classes from the jmx_examples.zip
bundle that you used in the Standard MBeans section. To run the MXBeans example follow these steps:
- If you have not done so already, save
jmx_examples.zip
into your work_dir
directory.
- Unzip the bundle of sample classes by using the following command in a terminal window.
unzip jmx_examples.zip
- Compile the example Java classes from within the
work_dir
directory.
javac com/example/*.java
- Start the
Main
application.
java com.example.Main
A confirmation that Main
is waiting for something to happen is generated.
- Start JConsole in a different terminal window on the same machine.
jconsole
The New Connection dialog box is displayed, presenting a list of running JMX agents that you can connect to.
- In the New Connection dialog box, select
com.example.Main
from the list and click Connect.
A summary of your platform's current activity is displayed.
- Click the MBeans tab.
This panel shows all the MBeans that are currently registered in the MBean server.
- In the left frame, expand the
com.example
node in the MBean tree.
You see the example MBean QueueSampler
that was created and registered by Main
. If you click QueueSampler
, you see its associated Attributes and Operations nodes in the MBean tree.
- Expand the Attributes node.
You see the QueueSample
attribute appear in the right pane, with its value of javax.management.openmbean.CompositeDataSupport
.
- Double-click the
CompositeDataSupport
value.
You see the QueueSample
values date
, head
, and size
because the MXBean framework has converted the QueueSample
instance into CompositeData
. If you had defined QueueSampler
as a standard MBean rather than as an MXBean, JConsole would not have found the QueueSample
class because it would not be in its class path. If QueueSampler
had been a standard MBean, you would have received a ClassNotFoundException
message when retrieving the QueueSample
attribute value. The fact that JConsole finds QueueSampler
demonstrates the usefulness of using MXBeans when connecting to JMX agents through generic JMX clients such as JConsole.
- Expand the Operations node.
A button to invoke the clearQueue
operation is displayed.
- Click the
clearQueue
button.
A confirmation that the method was invoked successfully is displayed.
- Expand the Attributes node again, and double click on the
CompositeDataSupport
value.
The head
and size
values have been reset.
- To close JConsole, select Connection -> Exit.
Lesson: Notifications
The JMX API defines a mechanism to enable MBeans to generate notifications, for example, to signal a state change, a detected event, or a problem.
To generate notifications, an MBean must implement the interface NotificationEmitter
or extend NotificationBroadcasterSupport
. To send a notification, you need to construct an instance of the class javax.management.Notification
or a subclass (such as AttributeChangedNotification
), and pass the instance to NotificationBroadcasterSupport.sendNotification
.
Every notification has a source. The source is the object name of the MBean that generated the notification.
Every notification has a sequence number. This number can be used to order notifications coming from the same source when order matters and there is a risk of the notifications being handled in the wrong order. The sequence number can be zero, but preferably the number increments for each notification from a given MBean.
The Hello
MBean implementation in Standard MBeans actually implements the notification mechanism. However, this code was omitted in that lesson for the sake of simplicity. The complete code for Hello
follows:
package com.example;
import javax.management.*;
public class Hello
extends NotificationBroadcasterSupport implements HelloMBean {
public void sayHello() {
System.out.println("hello, world");
}
public int add(int x, int y) {
return x + y;
}
public String getName() {
return this.name;
}
public int getCacheSize() {
return this.cacheSize;
}
public synchronized void setCacheSize(int size) {
int oldSize = this.cacheSize;
this.cacheSize = size;
System.out.println("Cache size now " + this.cacheSize);
Notification n =
new AttributeChangeNotification(this,
sequenceNumber++,
System.currentTimeMillis(),
"CacheSize changed",
"CacheSize",
"int",
oldSize,
this.cacheSize);
sendNotification(n);
}
@Override
public MBeanNotificationInfo[] getNotificationInfo() {
String[] types = new String[] {
AttributeChangeNotification.ATTRIBUTE_CHANGE
};
String name = AttributeChangeNotification.class.getName();
String description = "An attribute of this MBean has changed";
MBeanNotificationInfo info =
new MBeanNotificationInfo(types, name, description);
return new MBeanNotificationInfo[] {info};
}
private final String name = "Reginald";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int DEFAULT_CACHE_SIZE = 200;
private long sequenceNumber = 1;
}
This Hello
MBean implementation extends the NotificationBroadcasterSupport
class. NotificationBroadcasterSupport
implements the NotificationEmitter
interface.
The operations and attributes are set in the same way as in the standard MBean example, with the exception that the CacheSize
attribute's setter method now defines a value of oldSize
. This value records the CacheSize
attribute's value prior to the set operation.
The notification is constructed from an instance, n
, of the JMX class AttributeChangeNotification
, which extends javax.management.Notification
. The notification is constructed within the definition of the setCacheSize()
method from the following information. This information is passed to AttributeChangeNotification
as parameters.
- The object name of the source of the notification, namely the
Hello
MBean, represented by this
- A sequence number, namely
sequenceNumber
, that is set to 1 and that increases incrementally
- A timestamp
- The content of the notification message
- The name of the attribute that has changed, in this case,
CacheSize
- The type of attribute that has changed
- The old attribute value, in this case,
oldSize
- The new attribute value, in this case,
this.cacheSize
The notification n
is then passed to the NotificationBroadcasterSupport.sendNotification()
method.
Finally, the MBeanNotificationInfo
instance is defined to describe the characteristics of the different notification instances generated by the MBean for a given type of notification. In this case the type of notifications sent is AttributeChangeNotification
notifications.
Running the MBean Notification Example
Once again, you will use JConsole to interact with the Hello
MBean, this time to send and receive notifications.
- If you have not done so already, save
jmx_examples.zip
into your work_dir
directory.
- Unzip the bundle of sample classes by using the following command in a terminal window.
unzip jmx_examples.zip
- Compile the example Java classes from within the
work_dir
directory.
javac com/example/*.java
- Start the
Main
application.
java com.example.Main
A confirmation that Main
is waiting for something to happen is generated.
- Start JConsole in a different terminal window on the same machine.
jconsole
The New Connection dialog box is displayed, presenting a list of running JMX agents that you can connect to.
- In the New Connection dialog box, select
com.example.Main
from the list and click Connect.
A summary of your platform's current activity is displayed.
- Click the MBeans tab.
This panel shows all the MBeans that are currently registered in the MBean server.
- In the left frame, expand the
com.example
node in the MBean tree.
You see the example MBean Hello
that was created and registered by Hello
. If you click Hello
, you see its Notifications node in the MBean tree.
- Expand the Notifications node of the
Hello
MBean in the MBean tree.
Note that the panel is blank.
- Click the Subscribe button.
The current number of notifications received (0) is displayed in the Notifications node label.
- Expand the Attributes node of the
Hello
MBean in the MBean tree, and change the value of the CacheSize
attribute to 150.
In the terminal window in which you started Main
, a confirmation of this attribute change is displayed. Note that the number of received notifications displayed in the Notifications node has changed to 1.
- Expand again the Notifications node of the
Hello
MBean in the MBean tree.
The details of the notification are displayed.
- To close JConsole, select Connection -> Exit.
Lesson: Remote Management
The JMX API enables you to perform remote management of your resources by using JMX technology-based connectors (JMX connectors). A JMX connector makes an MBean server accessible to remote Java technology-based clients. The client end of a connector exports essentially the same interface as the MBean server.
A JMX connector consists of a connector client and a connector server. A connector server is attached to an MBean server and listens for connection requests from clients. A connector client is responsible for establishing a connection with the connector server. A connector client is usually in a different Java Virtual Machine (Java VM) from the connector server and is often running on a different machine. The JMX API defines a standard connection protocol based on Remote Method Invocation (RMI). This protocol enables you to connect a JMX client to an MBean in an MBean server from a remote location and perform operations on the MBean, exactly as if the operations were being performed locally.
The Java SE platform provides an out-of-the-box means to monitor applications remotely by using the JMX API's standard RMI connector. The out-of-the-box RMI connector automatically exposes applications for remote management, without requiring you to create a dedicated remote connector server yourself. The out-of-the-box remote management agent is activated by starting your Java application with the correct properties. Monitoring and management applications that are compatible with the JMX technology can then connect to these applications and monitor them remotely.
Exposing a Resource for Remote Management By JConsole
Exposing your Java applications for remote management by using the JMX API can be extremely simple, if you use the out-of-the-box remote management agent and an existing monitoring and management tool such as JConsole.
To expose your application for remote management, you need to start it with the correct properties. This example shows how to expose the Main JMX agent for remote management.
Security consideration: For the sake of simplicity, the authentication and encryption security mechanisms are disabled in this example. However, you should implement these security mechanisms when implementing remote management in real-world environments. What Next? provides pointers to other JMX technology documentation that shows how to activate security.
To monitor the Main JMX agent remotely, follow these steps:
1. If you have not done so already, save jmx_examples.zip into your work_dir directory.
2. Unzip the bundle of sample classes by using the following command in a terminal window.
unzip jmx_examples.zip
3. Compile the example Java classes from within the work_dir directory.
javac com/example/*.java
4. Start the Main application, specifying the properties that expose Main for remote management:
java -Dcom.sun.management.jmxremote.port=9999 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
com.example.Main
A confirmation that Main is waiting for something to happen is generated.
5. Start JConsole in a different terminal window on a different machine:
jconsole
The New Connection dialog box is displayed, presenting a list of running JMX agents that you can connect to locally.
6. Select Remote Process, and type the following in the Remote Process field:
hostname:9999
In this address, hostname is the name of the remote machine on which the Main application is running and 9999 is the number of the port on which the out-of-the-box JMX connector will be connected.
7. Click Connect.
A summary of the current activity of the Java Virtual Machine (Java VM) in which Main is running is displayed.
8. Click the MBeans tab.
This panel shows all the MBeans that are currently registered in the remote MBean server.
9. In the left-hand frame, expand the com.example node in the MBean tree.
You see the example MBean Hello that was created and registered by Main. If you click Hello, you see its associated Attributes and Operations nodes in the MBean tree, even though it is running on a different machine.
10. To close JConsole, select Connection -> Exit.
Creating a Custom JMX Client
The previous lessons in this trail have shown you how to create JMX technology MBeans and MXBeans, and register them with a JMX agent. However, all the previous examples have used an existing JMX client, JConsole. This lesson will demonstrate how to create your own custom JMX client.
An example of a custom JMX client, Client
is included in jmx_examples.zip
. This JMX client interacts with the same MBean, MXBean and JMX agent as were seen in the previous lessons. Due to the size of the Client
class, it will be examined in chunks, in the following sections.
Importing the JMX Remote API Classes
To be able to create connections to JMX agents that are running remotely from the JMX client, you need to use the classes from the javax.management.remote
.
package com.example;
[...]
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class Client {
[...]
The Client
class will be creating JMXConnector
instances, for which it will need a JMXConnectorFactory
and a JMXServiceURL
.
Creating a Notification Listener
The JMX client needs a notification handler, to listen for and to process any notifications that might be sent by the MBeans that are registered in the JMX agent's MBean server. The JMX client's notification handler is an instance of the NotificationListener
interface, as shown below.
[...]
public static class ClientListener implements NotificationListener {
public void handleNotification(Notification notification,
Object handback) {
echo("\nReceived notification:");
echo("\tClassName: " + notification.getClass().getName());
echo("\tSource: " + notification.getSource());
echo("\tType: " + notification.getType());
echo("\tMessage: " + notification.getMessage());
if (notification instanceof AttributeChangeNotification) {
AttributeChangeNotification acn =
(AttributeChangeNotification) notification;
echo("\tAttributeName: " + acn.getAttributeName());
echo("\tAttributeType: " + acn.getAttributeType());
echo("\tNewValue: " + acn.getNewValue());
echo("\tOldValue: " + acn.getOldValue());
}
}
}
[...]
This notification listener determines the origin of any notifications it receives, and retrieves the information stored in the notification. It then performs different actions with the notification information according to the type of notification received. In this case, when the listener receives notifications of the type AttributeChangeNotification
it will obtain the name and type of the MBean attribute that has changed, as well as its old and new values, by calling the AttributeChangeNotification
methods getAttributeName
, getAttributeType
, getNewValue
and getOldValue
.
A new ClientListener
instance is created by later in the code.
ClientListener listener = new ClientListener();
Creating an RMI Connector Client
The Client
class creates an RMI connector client that is configured to connect to an RMI connector server that you will launch when you start the JMX agent, Main
. This will allow the JMX client to interact with the JMX agent as if they were running on the same machine.
[...]
public static void main(String[] args) throws Exception {
echo("\nCreate an RMI connector client and " +
"connect it to the RMI connector server");
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
[...]
As you can see, the Client
defines a JMXServiceURL
named url
, that represents the location at which the connector client expects to find the connector server. This URL allows the connector client to retrieve the RMI connector server stub jmxrmi
from the RMI registry running on port 9999 of the local host, and to connect to the RMI connector server.
With the RMI registry thus identified, the connector client can be created. The connector client, jmxc
, is an instance of the interface JMXConnector
, created by the connect()
method of JMXConnectorFactory
. The connect()
method is passed the parameters url
and a null environment map when it is called.
Connecting to the Remote MBean Server
With the RMI connection in place, the JMX client must connect to the remote MBean server, so that it can interact with the various MBeans registered in it by the remote JMX agent.
[...]
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
[...]
An instance of MBeanServerConnection
, named mbsc, is then created by calling the getMBeanServerConnection()
method of the JMXConnector
instance jmxc
.
The connector client is now connected to the MBean server created by the JMX agent, and can register MBeans and perform operations on them with the connection remaining completely transparent to both ends.
To start with, the client defines some simple operations to discover information about the MBeans found in the agent's MBean server.
[...]
echo("\nDomains:");
String domains[] = mbsc.getDomains();
Arrays.sort(domains);
for (String domain : domains) {
echo("\tDomain = " + domain);
}
[...]
echo("\nMBeanServer default domain = " + mbsc.getDefaultDomain());
echo("\nMBean count = " + mbsc.getMBeanCount());
echo("\nQuery MBeanServer MBeans:");
Set names =
new TreeSet(mbsc.queryNames(null, null));
for (ObjectName name : names) {
echo("\tObjectName = " + name);
}
[...]
The client calls various methods of MBeanServerConnection
in order to obtain the domains in which the different MBeans are operating, the number of MBeans registered in the MBean server, and the object names for each of the MBeans it discovers.
Performing Operations on Remote MBeans via Proxies
The client accesses the Hello
MBean in the MBean server through the MBean server connection by creating an MBean proxy. This MBean proxy is local to the client, and emulates the remote MBean.
[...]
ObjectName mbeanName = new ObjectName("com.example:type=Hello");
HelloMBean mbeanProxy =
JMX.newMBeanProxy(mbsc, mbeanName, HelloMBean.class, true);
echo("\nAdd notification listener...");
mbsc.addNotificationListener(mbeanName, listener, null, null);
echo("\nCacheSize = " + mbeanProxy.getCacheSize());
mbeanProxy.setCacheSize(150);
echo("\nWaiting for notification...");
sleep(2000);
echo("\nCacheSize = " + mbeanProxy.getCacheSize());
echo("\nInvoke sayHello() in Hello MBean...");
mbeanProxy.sayHello();
echo("\nInvoke add(2, 3) in Hello MBean...");
echo("\nadd(2, 3) = " + mbeanProxy.add(2, 3));
waitForEnterPressed();
[...]
MBean proxies allow you to access an MBean through a Java interface, allowing you to make calls on the proxy rather than having to write lengthy code to access a remote MBean. An MBean proxy for Hello
is created here by calling the method newMBeanProxy()
in the javax.management.JMX
class, passing it the MBean's MBeanServerConnection
, object name, the class name of the MBean interface and true
, to signify that the proxy must behave as a NotificationBroadcaster
. The JMX client can now perform the operations defined by Hello
as if they were the operations of a locally registered MBean. The JMX client also adds a notification listener and changes the MBean's CacheSize
attribute, to make it send a notification.
Performing Operations on Remote MXBeans via Proxies
You can create proxies for MXBeans in exactly the same way as you create MBean proxies.
[...]
ObjectName mxbeanName =
new ObjectName("com.example:type=QueueSampler");
QueueSamplerMXBean mxbeanProxy =
JMX.newMXBeanProxy(mbsc, mxbeanName, QueueSamplerMXBean.class);
QueueSample queue1 = mxbeanProxy.getQueueSample();
echo("\nQueueSample.Date = " + queue1.getDate());
echo("QueueSample.Head = " + queue1.getHead());
echo("QueueSample.Size = " + queue1.getSize());
echo("\nInvoke clearQueue() in QueueSampler MXBean...");
mxbeanProxy.clearQueue();
QueueSample queue2 = mxbeanProxy.getQueueSample();
echo("\nQueueSample.Date = " + queue2.getDate());
echo("QueueSample.Head = " + queue2.getHead());
echo("QueueSample.Size = " + queue2.getSize());
[...]
As shown above, to create a proxy for an MXBean, all you have to do is call JMX.newMXBeanProxy
instead of newMBeanProxy
. The MXBean proxy mxbeanProxy
allows the client to invoke the QueueSample
MXBean's operations as if they were the operations of a locally registered MXBean.
Closing the Connection
Once the JMX client has obtained all the information it needs and performed all the required operations on the MBeans in the remote JMX agent's MBean server, the connection must be closed down.
jmxc.close();
The connection is closed with a call to the JMXConnector.close
method.
To Run the Custom JMX Client Example
To monitor the Main
JMX agent remotely using a the custom JMX client Client
, follow these steps:
- If you have not done so already, save
jmx_examples.zip
into your work_dir
directory.
- Unzip the bundle of sample classes by using the following command in a terminal window.
unzip jmx_examples.zip
- Compile the example Java classes from within the
work_dir
directory.
javac com/example/*.java
- Start the
Main
application, specifying the properties that expose Main
for remote management:
java -Dcom.sun.management.jmxremote.port=9999 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
com.example.Main
A confirmation that Main
is waiting for something to happen is generated.
- Start the
Client
application in a different terminal window:
java com.example.Client
A confirmation that an MBeanServerConnection
has been obtained is displayed.
- Press Enter.
The domains in which all the MBeans that are registered in the MBean server started by Main
are displayed.
- Press Enter again.
The number of MBeans that are registered in the MBean server is displayed, as well as the object names of all these MBeans. The MBeans displayed include all the standard platform MXBeans running in the Java VM, as well as the Hello
MBean and the QueueSampler
MXBean that were registered in the MBean server by Main
.
- Press Enter again.
The Hello
MBean's operations are invoked by Client
, with the following results:
- A notification listener is added to
Client
to listen for notifications from Main
.
- The value of the
CacheSize
attribute is changed from 200 to 150.
- In the terminal window in which you started
Main
, confirmation of the CacheSize
attribute change is displayed.
- In the terminal window in which you started
Client
, a notification from Main
is displayed, informing Client
of the CacheSize
attribute change.
- The
Hello
MBean's sayHello
operation is invoked.
- In the terminal window in which you started
Main
, the message "Hello world" is displayed.
- The
Hello
MBean's add
operation is invoked, with the values 2 and 3 as parameters. The result is displayed by Client
.
- Press Enter again.
The QueueSampler
MXBean's operations are invoked by Client
, with the following results:
- The
QueueSample
values date
, head
, and size
are displayed.
- The
clearQueue
operation is invoked.
- Press Enter again.
The Client
closes the connection to the MBean server and a confirmation is displayed.
Java Management Extensions (JMX): End of Trail
You've reached the end of the "Java Management Extensions (JMX)" trail.
If you have comments or suggestions about this trail, use our feedback page to tell us about it.
What next?
Once you've caught your breath, you have several choices of where to go next. You can go to the front page to see all of your choices, or you can go directly to one of the following related trails:
The purpose of this trail has been to provide you with a brief introduction to the basic elements of the JMX technology. More advanced materials can be found elsewhere.
The following resources will be useful if you wish to study the JMX technology further:
- JMX Technology documentation for the Java SE Platform. The JMX Technology documentation is included in the Java SE platform documentation set.
- JMX Technology Overview. The Java SE platform documentation for the JMX technology contains the JMX Technology Overview, which provides a more detailed description of the JMX Technology than is provided in the present trail.
- JMX Technology Tutorial. The lessons in this trail are based on the examples used in the JMX Technology Tutorial. In addition to the basic elements presented in the present trail, the JMX Technology Tutorial presents more advanced aspects of the JMX technology.
- In addition to the examples presented in the above tutorial, once you have installed the Java Development Kit (JDK) 6, a sample application that demonstrates a real-life implementation of the JMX API can be found in the following directory:
jdk_home
/sample/jmx/jmx-scandir
Where jdk_home
is the directory in which the JDK software is installed. The jmx-scandir
example is an advanced example, which presents advanced concepts of the JMX API in a real-world scenario.
</script>