Home > Articles > Programming > Java

Introduction to JMX

This chapter is from the book

2.6 Quick Tour of JMX

The easiest way to understand JMX is with a simple but thorough example. This example uses Tivoli's TMX4J JMX implementation, but the code should be identical regardless of who the JMX vendor is. The remainder of this chapter is dedicated to demonstrating the major features of JMX—MBeans, the MBeanServer, monitors, and notifications—via the design and implementation of a simple manageable server application.50

2.6.1 todd, the Time of Day Daemon

todd is a simple daemon that does a simple job. It accepts client connections and sends them the current date and time whenever they ask for it. Figure 2.5 shows todd's static structure.

Figure 2.5Figure 2.5 Class Structure of the Unmanaged Time of Day Daemon

Three classes form todd's core: Server, Listener, and Session. The Server class is responsible for starting a listener and assigning sessions to incoming connections. The Listener class accepts incoming connections and queues them for the server. The Session class is responsible for responding to client messages received via a connection. Figure 2.6 illustrates the interaction among todd's classes.

2.6.2 todd Management

todd satisfies its basic functional requirements by accepting client connections and supplying the current date and time on demand, but it's not manageable. We have no way of knowing the total number of sessions that todd has handled, how many sessions are active, how many connections are queued, how long each session has been running, and so on. We can't stop and start the listener without killing todd, and any active sessions along with it. We can't change the size of the connection queue or session pool without recompiling the code. If todd were to become a popular service, our administrator colleagues would not be happy with us.

Figure 2.6Figure 2.6 todd Component Interactions During a Client Session


JMX lets us build manageability into our Java applications. MBeans capture the management interface of the resources that management systems need to monitor and control. The MBeanServer provides a common registry and naming model for all of an application's MBeans. MBean services exist to autonomously monitor MBean attribute values and fire notifications when constraints are violated. Notifications provide both a means to alert an administrator of a problem, and an implicit invocation mechanism that developers can use to make an application self-managing.

In the next few sections we will apply JMX to todd and transform it into a manageable application that will delight the system administration staff, or at least keep them from paging us in the middle of the night. Because the goal of this tour is to demonstrate the major features of JMX in an application, we will introduce them without a lot of explanation. Subsequent chapters will provide details of all the features we use in our example.

Before we start, it would be good to have an idea of the sort of manageability requirements the new version of todd has to satisfy. Table 2.1 provides a minimal list. Modifying todd to satisfy these requirements will involve the following activities: designing and implementing the necessary MBeans, incorporating an MBeanServer into todd, and wiring up the monitors and NotificationListener instances that are needed to complete the implementation.

Table 2.1 Basic todd Management Requirements

Aspect

Requirement

Description

Server control

Stop/start

Stop and start the server without killing the todd process or any active sessions.

 

Shutdown

Shut down the server, killing the todd process and any active sessions.

Server data

Total connections

Show how many connections the server has handled so far.

 

Uptime

Show how long the server has been running.

 

Active sessions

Show how many sessions are currently active.

Session pool management

Grow pool

Increase the size of the session pool by a specified amount.

 

Empty pool management

Stop the server when the pool becomes empty; restart the server when the pool contains at least two sessions.


2.6.3 todd's MBeans

From the requirements in Table 2.1, it's pretty clear that we're concerned with only a couple of todd's resources: the server itself, and the pool of sessions that todd uses to service connections. Because JMX uses MBeans to represent managed resources, it follows that we need to make the Server and SessionPool classes MBeans. There are several ways to accomplish that goal; the simplest is to make them standard MBeans. In general a standard MBean for a given resource is defined by a Java interface named MyResourceMBean and a Java class, MyResource, which implements the MyResourceMBean interface. MyResourceMBean defines the MBean's management interface—that is, the attributes and methods that JMX makes available to management applications.

It's clear from the requirements what the server's management interface should look like:

public interface ServerMBean {
 void shutdown();
 void start();
 void stop();
 Integer getConnections();
 Integer getSessions();
 Long getUptime();
}

A JMX management interface contains attributes and operations. In a standard MBean those attributes and operations are expressed as methods in a Java interface. Methods that have the following form:

AttributeType getAttributeName();
void setAttributeName();

define an attribute named AttributeName that takes values of type AttributeType. If the setAttributeName() method is missing, the attribute is read-only; if the getAttributeName() method is missing, the attribute is write-only. Any method in the MBean interface that doesn't define an attribute defines an operation for the management interface.

The first three methods in the ServerMBean interface define operations that a management application can invoke on ServerMBean instances. The remaining methods define attributes; specifically they define three read-only attributes: Connections, Sessions, and Uptime.

The implementation of the ServerMBean interface in the Server class is straightforward:

public class Server implements ServerMBean, NotificationListener {
 private SessionPool sessions;
 private SortedSet connectionQueue;
 private Listener listener;
 private int connections; // incremented for each new connection
 private int tzero;  // System.currentTimeMillis at Server start
 ...
 // Other Server methods that aren't part of the MBean interface

/**
  * Shut down the server, killing the process and any active sessions
  */
 public void shutdown() {
  System.exit(0);
 }

/**
  * Start a listener thread that will queue incoming connections
  */
 public void start() {
  listener = new Listener(connectionQueue);
  listener.start();
 }

/**
  * Stop the server's listener thread; active sessions continue to
  * handle requests
  */
 public void stop() {
  listener.stopListening();
 }

/**
  * Connections attribute getter
  * @returns total number of connections handled
  */
 public Integer getConnections() {
  return new Integer(connections);
 }

/**
  * Sessions attribute getter
  * @returns number of active sessions
  */
 public Integer getSessions() {
  int as = sessions.getAvailableSessions().intValue();
  int sz = sessions.getSize().intValue();
  return new Integer(sz – as);
 }

/**
  * Uptime attribute getter
  * @returns number of milliseconds since the server was started
  */
 public Long getUptime() {
  return new Long(System.currentTimeMillis() – tzero);
 }
}

The shape of the SessionPool management interface requires a little more thought. Clearly it needs a grow operation to satisfy the first session pool management requirement. What about the empty pool management requirement? We could specify a monitorPoolSpace operation that would provide the necessary behavior, but as we'll see in a moment, that would be reinventing a perfectly good JMX wheel. Instead, let's just satisfy the underlying data requirement by providing access to the number of sessions left in the pool. A glance back at the ServerMBean implementation will reveal that we've already assumed that this information, along with the session pool size, is available, so we have this:

public interface SessionPoolMBean {
 void grow(int increment);
 Integer getAvailableSessions();
 Integer getSize();
}

todd uses java.util.Set as the underlying data structure for the SessionPool implementation:

public class SessionPool implements SessionPoolMBean {
 private static final int DEFAULT_POOLSIZE = 8;
 private Set sessions;
 private int size;

/**
  * Default constructor creates a SessionPool instance of size 
  * DEFAULT_POOLSIZE
  */
 public SessionPool() {
  this(DEFAULT_POOLSIZE);
 }

/**
  * Creates a SessionPool instance of the specified size and 
  * fills it with Session instances
  */
 public SessionPool(int size) {
  this.size = size;
  sessions = new HashSet(size);
  fill();
 }

/**
  * Increase the number of Session instances in SessionPool by  
 * increment
  * @param increment the number of Session instances to add to  
 * the pool
  */
 public synchronized void grow(int increment) {
  for (int i = 0; i < increment; i++) {
   Session s = new Session(this);
   sessions.add(s);
  }
  size = size + increment;
 }

/**
  * AvailableSessions attribute getter
  * @returns number of sessions remaining in the pool
  */
 public Integer getAvailableSessions() {
  return new Integer(sessions.size());
 }

/**
  * Size attribute getter
  * @returns size of the session pool
  */
 public Integer getSize() {
  return new Integer(size);
 }
  ...
  // Other SessionPool methods that are not part of the MBean 
  // interface
}

You've probably noticed that all of our attribute getters return Java numeric wrapper types—Integer, Long, and so on. We do that so that we can use JMX monitors such as GaugeMonitor, which we'll use in the implementation of the empty pool management requirement, to observe the values taken by those attributes. Note also that we have kept the operations in the ServerMBean and SessionPoolMBean interfaces very simple.

2.6.4 Incorporating an MBeanServer

Now that we've got some MBeans, what do we do with them? Because a JMX-based management application can access MBeans only if they are registered with an MBeanServer, we should register them. Unfortunately, we don't have an MBeanServer in todd to register any MBeans with at the moment. That problem can be solved with a single line of code in todd's main() method:

MBeanServer mbs = MBeanServerFactory.createMBeanServer();

In the interest of minimizing the impact of incorporating the MBeanServer, we will instantiate both the Server and the SessionPool MBeans and then register them, rather than creating and automatically registering them via the MBeanServer. Server is instantiated in main(), and SessionPool is created as part of the Server instantiation:

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

Server server = new Server(mbs);
 ObjectName son = new ObjectName("todd:id=Server");
 mbs.registerMBean(server, son);

...

while (server.isActive()) {
  Connection k = server.waitForConnection()
  server.activateSession(k);
 }
}

public Server(MBeanServer mbs) throws Exception {
 this.mbs = mbs;

connectionQueue = new TreeSet();
 connections = 0;

sessions = new SessionPool();
 ObjectName spon = new ObjectName("todd:id=SessionPool");
 mbs.registerMBean(sessions, spon);

active = true;
 tzero = System.currentTimeMillis();
}

The MBeanServer associates an ObjectName instance with each MBean. We've registered Server and SessionPool under the names todd:id=Server and todd:id=SessionPool. The portion of the name to the left of the colon is the domain, which is an arbitrary string that is opaque to the MBeanServer but may have meaning to one or more management applications. On the right are the key properties, a set of name/value pairs that help distinguish one MBean from another. Together they must form a unique name, within a given MBeanServer, for the associated MBean.

2.6.5 Monitoring todd

We still haven't satisfied the SessionPool empty pool management requirement. The SessionPool MBean tells us how many sessions are left in the pool. What we need is a way to react to these two events: (1) AvailableSessions has become zero, and (2) AvailableSessions has increased from zero to one or more.

In JMX, events are called notifications. Every JMX notification has a class and a type; its class is either javax.management.Notification or one of its subclasses; its type is String expressed in dot notation—for example, jmx.mbean.registered. Notifications are handled by calls to one of the MBeanServer's addNotificationListener() methods:

public void addNotificationListener(ObjectName objname,
                  NotificationListener listener,
                  NotificationFilter filter,
                  Object handback);

public void addNotificationListener(ObjectName objname,
                  ObjectName listener,
                  NotificationFilter filter,
                  Object handback);

The only difference between the two method calls is the second parameter. In the first version the second parameter is a reference to a NotificationListener instance—that is, an instance of a class that implements the NotificationListener interface. In the second version the second parameter is the ObjectName instance of an MBean that implements NotificationListener.

Careful readers will have noticed that the Server class implements ServerMBean and NotificationListener. Satisfying the empty pool management requirement involves stopping and starting the server that makes the Server class. These actions provide the stop() and start() methods with a natural place to handle the notifications that trigger those actions. The NotificationListener interface declares a single method, handleNotification(). Here is the Server implementation of the method:

public void handleNotification(Notification n, Object hb) {
 String type = n.getType();
 if (type.compareTo    (MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED) == 0) {
  stop();
 } else if (type.compareTo    
     (MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED) == 0) {
  if (isActive() == false) start();
 }
}

Now all that's required is a mechanism for generating notifications at the appropriate times. We need something that will monitor SessionPool's AvailableSessions attribute, send a notification when it becomes zero, and then send another notification later when AvailableSessions increases to one or more.

The JMX GaugeMonitor class provides just such a mechanism. A GaugeMonitor instance is configured to monitor a specific attribute of an MBean registered with the MBeanServer. The GaugeMonitor class has two thresholds: high and low. A MonitorNotification instance with type jmx.monitor.threshold.high is sent when the attribute value increases to or past the high threshold value. Similarly, when the attribute value decreases to or below the low threshold value, a MonitorNotification instance with type jmx.monitor.threshold.low is sent.

The Server.configureMonitor() method sets up a GaugeMonitor instance that completes the implementation of the empty pool management requirement:

public static void configureMonitor(MBeanServer mbs) throws 
 Exception {
 ObjectName spmon = new ObjectName("todd:id=SessionPoolMonitor");
 mbs.createMBean("javax.management.monitor.GaugeMonitor", spmon);

AttributeList spmal = new AttributeList();
 spmal.add(new Attribute("ObservedObject", new 
  ObjectName("todd:id=SessionPool")));
 spmal.add(new Attribute("ObservedAttribute", 
  "AvailableSessions"));
 spmal.add(new Attribute("GranularityPeriod", new Long(10000)));
 spmal.add(new Attribute("NotifyHigh", new Boolean(true)));
 spmal.add(new Attribute("NotifyLow", new Boolean(true)));
 mbs.setAttributes(spmon, spmal);

mbs.invoke(
  spmon,
  "setThresholds",
  new Object[] { new Integer(1), new Integer(0)},
  new String[] { "java.lang.Number", "java.lang.Number" });

mbs.addNotificationListener(
  spmon,
  new ObjectName("todd:id=Server"),
  null,
  new Object());

mbs.invoke(spmon, "start", new Object[] {}, new String[] {});
}

The first two lines here create and register a GaugeMonitor MBean named todd:id=SessionPoolMonitor. The next seven lines set attributes that tell GaugeMonitor which attribute of which MBean should be monitored (ObservedAttribute or ObservedObject), how often (GranularityPeriod, in milliseconds), and whether or not to send a notification on high-threshold and low-threshold violations. Then we invoke the setThresholds() method, via the MBeanServer, to set the actual high and low threshold values. Finally, we make the server listen for session pool monitor notifications and start the gauge monitor.

2.6.6 Browser Control

The new version of todd satisfies all of the management requirements specified in Table 2.1. There is, however, one more issue to address: We would like to be able to control todd interactively. For example, an administrator should be able to connect to todd from home to check the values of key MBean attributes, stop the server, increase the size of the session pool, and restart the server if necessary.

Although there are as many ways to address this issue as there are communication protocols, most JMX implementations provide an HTTP adapter that allows a user to "surf" an MBeanServer—inspecting MBean attributes, invoking operations, and so on—using a standard Web browser. Here's the code necessary to start the TMX4J HTTP adapter:

ObjectName httpon = new ObjectName("adapters:id=Http");
mbs.createMBean("com.tivoli.jmx.http_pa.Listener", httpon);
mbs.invoke(httpon, "startListener", 
new Object[] {}, new String[] {});

Once the adapter has been started, you can connect to the MBeanServer via a Web browser. In the case of the TMX4J HTTP adapter, you would direct your browser to http://<your-server>:6969. You can change the port the adapter listens on in the jmx.properties file that the TMX4J implementation reads on startup. Figure 2.7 shows the TMX4J view of the todd MBeans.

Figure 2.7Figure 2.7 The TMX4J HTTP Adapter's MBean View


InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020