In this section we will walk through the development of standard and dynamic MBeans for a simple web server.
The UML diagram below illustrates the static structure of a simple HTTP daemon:
Disclaimer: this code provides none of the usual web server security features and will happily retrieve any file on your computer.
The daemon uses a simple pipeline to handle HTTP GET requests. The listener encapsulates a server socket upon which it waits for HTTP requests. As requests come in they get placed in the request queue. Handlers from the HandlerPool pick up requests from the queue, log the request in a LogFile, and return the requested file to the client.
Suppose that we want to make the following elements of this design JMX manageable:
Listener, HandlerPool, and LogFile are all classes we've written so we will turn them into standard MBeans. The RequestQueue is implemented via a java.util.SortedSet. Since we don't have the source for java.util.SortedSet RequestQueue will be a dynamic MBean.
To turn Listener, HandlerPool, and LogFile into standard MBeans we must define a management interface for each class. The management interface is specified by a Java interface that follows the JMX standard MBean naming convention: the management interface of a given class, say Foo, is specified by an interface named FooMBean. Dynamic MBeans are created by implementing the DynamicMBean interface.
Applying these conventions to our design yields the following structure:
A management interface should expose the resource attributes that will be monitored and the methods that will be used to control the resource. Keep in mind that the management interface may be exposed to administrators on remote consoles. In general, simpler is better.
The listener's management interface
exposes three attributes: Port
, Requests
, and Listening
. The first attribute
is the IP port upon which the listener listens, the second is the number of
requests the daemon has handled, and the third indicates whether or not the
daemon is listening for requests. The port is a read/write attribute;
the interface contains both a getPort()
and a
setPort()
method. The requests and listening attributes are
read-only; the interface includes only a getRequests()
method and an isListening()
method - the latter form is
permissable for boolean attributes. Note that, as with
JavaBean properties, an attribute is exposed via methods in an interface not
by direct access to a data member. The listener exposes two control methods:
startListening()
and stopListening()
. Their meaning
should be obvious.
The handler pool's management interface
exposes one attribute and one method. The Size
attribute determines the number
of handlers in the handler pool. The refill()
method allows an administrator
to reinitialize the handler pool at runtime.
The log file's management interface exposes
two read-only attributes: Size
and LastModified
, and
a method: rollOver
. The size
attributes indicates
the logfile's size in bytes. The lastModified
attribute indicates
when the log file was last updated. The rollOver
method renames
the current log file: Httpd.log.backup, and creates a new Httpd.log.
Naturally having defined their management interfaces both the Listener and HandlerPool classes must be altered to appropriately implement those interfaces. No changes are necessary to the LogFile class since it already provides support for its management interface.
The request queue's dynamic MBean management
interface exposes two attributes: Capacity
and Length
. The former is the space available for requests,
the latter is the number of requests currently in the queue. Only one method: clear()
, is supported. Note that
unlike standard MBeans which must use reflection to discover and use the
resource's management interface no reflection is necessary with dynamic
MBeans. This makes them a better choice for platforms where java.lang.reflect
is not supported, e.g,. J2ME and IBM's VisualAge MicroEdition.
Because the MBeanServer does no introspection of a dynamic MBean we have to
create its meta data, the MBeanInfo structure, manually in our
implementation of the getMBeanInfo()
method. This is the
most tedious part of creating a dynamic MBean.