By far the most straightforward type of MBean to create, standard MBeans are a logical starting place for our voyage into the world of JMX. In this chapter, we will begin by defining a management interface, then we will look at the design patterns we must use when building standard MBeans. Next, we will discuss some of the issues involved when using inheritance among standard MBean classes. Then we will look at some common pitfalls of using standard MBeans that might leave you scratching your head, wondering why your MBeans aren’t working as expected. Finally, we will discuss some advanced topics and things to consider when creating standard MBeans. This chapter includes several examples from the sample application that is used throughout this book. When you have completed this chapter, you should be able to create standard MBeans and understand the issues involved in doing so.
The idea of a management interface revolves around the notion of an application resource, which is any abstraction within an application that provides value. A resource can be, for example, a business component of the application, an infrastructure component such as a cache or queue, or even the application itself. With respect to JMX (and more broadly, system management), only those resources that must be managed are significant. Each resource that is to be managed must provide a management interface, which consists of the attributes and operations it exposes so that it can be monitored and controlled by a management application.
For example, suppose a resource we wish to manage in our application is a queue. A queue is generally used to temporarily store a logical unit of work provided by a supplier until that unit of work is removed from the queue by a consumer for further processing. This is typically done asynchronously, via a multithreaded design, so the queue must also be thread-safe. Let’s suppose there is a single supplier thread in the application and a single consumer thread, and that the queue is thread-safe, so that the supplier will wait to add an item to the queue if it is full (and conversely, the consumer will wait on the queue to remove an item if the queue is empty). In monitoring the queue, we want to know two things:
How long has the supplier waited (i.e., the accumulated wait time) to add an item to the queue because the queue is full?
How long has the consumer waited to remove an item from the queue because the queue is empty?
Because these two pieces of information are important to us for
monitoring the application, it makes sense that we expose them as two
attributes on the management interface of the queue. Of course, the
queue must be written so that this information is captured, so that
it can be exposed in the first place! But that is very
straightforward to do and will be handled by our
application’s Queue
class.
I won’t spend a lot of time explaining all of the attributes and operations exposed on the management interface of the queue, because the goal of this chapter is to illustrate the mechanics and theory of standard MBeans, not how to design queues.
One other thing to consider is whether the values of these attributes
are in milliseconds (the clock tick count, on most systems). If so,
and if our application is long-running, we should probably use a
long
as the data type for these attributes to
allow them to contain very large values.
Now that we have decided to expose these two attributes, we must decide whether to make them read-only, write-only, or read/write when we expose them on the management interface. It doesn’t make much sense for these attributes to be write-only (because then we could only set them and not look at their values at any particular point in time), so we rule that option out right away. Making these attributes readable makes sense, but should we allow the management application to set their values? We could allow the management application to reset both of these values to zero by exposing an operation to handle this action, thus preventing a user of the management application from setting these values to something unreasonable.
The management interface for our queue now has the following:
A read-only attribute whose value is the total accumulated time spent by the supplier waiting to add a unit of work to the queue because the queue is full
A read-only attribute whose value is the total accumulated time spent by the consumer waiting to remove a unit of work from the queue because the queue is empty
An operation that resets both attributes to zero
We may also want to be able to manage the size of the queue. To allow
this, we can define an attribute on the queue and expose that
attribute on the management interface as a read/write attribute. This
allows us to view the current size of the queue and to modify that
value to tweak the queue for maximum performance at runtime. In
addition, we might be interested in the total number of work units
processed by the queue, so that we can get an idea of the throughput
of the application with respect to any particular instance of our
queue. As long as it makes sense and fits in with the design of the
queue, the sky’s the limit on what we can expose on
our queue’s management interface. Table 2-1 summarizes the attributes we will expose on
our Queue
resource.
Table 2-1. Attributes exposed for management on the Queue class
Name |
Data type |
Read/write |
---|---|---|
Add Wait Time |
|
Read-only |
Remove Wait Time |
|
Read-only |
Queue Size |
|
Read/write |
Number of Items Processed |
|
Read-only |
Queue Full |
|
Read-only |
Queue Empty |
|
Read-only |
Suspended |
|
Read-only |
Number of Suppliers |
|
Read-only |
Number of Consumers |
|
Read-only |
These attributes will be discussed in detail in the next section, where we will actually implement the queue’s management interface as a standard MBean.
Next, let’s consider the operations
to expose on the
management interface of the Queue
class. We
touched briefly on the reset operation earlier in this chapter. Other
operations we may want to include offer the management application
the ability to suspend and resume activity in the queue. This allows
the management application to halt processing so that, for example,
an operator can look at a
“snapshot” of what is happening
inside the queue. It may also be helpful for the operator to be able
to turn on and off tracing. Table 2-2 summarizes
the operations on our queue’s management interface.
Table 2-2. Operations exposed for management on the Queue class
Name |
Purpose |
---|---|
Reset |
Resets the state of the queue |
Suspend |
Suspends activity in the queue; all suppliers and consumers sleep until Resume is called |
Resume |
Signals to sleeping suppliers and consumers that activity may continue |
Enable Tracing |
Turns on any tracing done by the queue |
Disable Tracing |
Turns off tracing |
Now that we have defined the management interface for our
Queue
class, it’s time to see how
to instrument our class as a standard MBean using the design patterns
in
the
JMX specification.