Java
Java SE
Technologies
| »
Overview
| »
Basic
| »
CORBA
| »
HotSpot VM
| »
JNDI
| »
Mntr-Mgmt
| »
Tools APIs
| »
XML
|
|
This document describes best practices that have been identified for modeling using the JMX API. The suggestions here are not carved in stone, but if you find that they are inappropriate for your modeling effort, please
let us know so that we can discuss your situation and if necessary update this document. Some of the conventions described here are inconsistent with parts of the JMX API or of JSR 77 (J2EE management). They represent lessons learnt since those APIs were defined. Although the APIs cannot be changed to conform to the conventions here, these conventions should probably be followed in future additions to the APIs.
Contents
Object NamesEvery JMX MBean has an Object Name. It is very important to choose consistent and usable Object Names as described here. Bear in mind that the client interacting with your model might be showing these Object Names directly to a human (for example, it is a JMX-aware console); or it might be a program that is accessing MBeans in your model whose names you have clearly defined. Also, of course, MBeans should be named consistently across the model and, as far as possible, between models.
Object Name SyntaxAn Object Name is an instance of javax.management.ObjectName . An Object Name is either the name of an MBean, or it is a pattern, potentially matching the names of many MBeans. It looks like this: domain: key-property-list For example:
com.sun.someapp:type=Whatsit,name=25
Here, domain is an arbitrary string. If the domain is empty, it implies the default domain for the MBean Server where the Object Name is used. If the
domain contains at least one
The
domain cannot contain the colon character (
The
key-property-list in an MBean name contains one or more
key properties. A
key property looks like
name=
value, for example
Spaces are significant everywhere in an Object Name. Do not write
Object Names are case sensitive. The order of key properties is not significant. There is no difference between
The set of characters in a key is limited. It is recommended to stick to legal Java identifiers. The set of characters in a value is also limited. If special characters may occur, it is recommended that the value be quoted, using
ObjectName.quote. If the value for a given key is sometimes quoted, then it should always be quoted. By default, if a value is a string (rather than a number, say), then it should be quoted unless you are sure that it will never contain special characters. Here are some examples of Object Names containing quoted values:
com.sun.someapp:type=Whatsit,name="25"
The second example would be illegal without quoting.
In a pattern, the
key-property-list can have the same form as just described; or it can be a single
Object Name ConventionsObject Names should be predictable. This means that if you know that there is going to be an MBean representing a certain object, then you should be able to know what its name will be. The name should not contain properties that are not an inherent part of the object's identity. The name of the same object should not change between different executions of the application, so for example it should not contain items like a "JVM id" or the "MBean Server Id" that will change with each execution. (The concept of "the same object" is not always clear or meaningful, but when it is, the same object should always have the same name.) The domain part of an Object Name should start with a Java package name. This prevents collisions between MBeans coming from different subsystems. There might be additional text after the package name. Examples:
com.sun.someapp:type=Whatsit,name=5
The domain should not contain the character slash (
Every Object Name should contain a
Every Object Name with a given
If there can only be one instance of a given type in a given domain, there should not usually be any other key properties than
If there can be several instances of a given type, they can be differentiated either by being in different domains or by further key properties. Most often, domains are relatively fixed, and variable parts of names are in key properties. The most usual key property in addition to
Sometimes it is useful to define additional properties as well as
com.sun.someapp:group=configuration,* Object containmentSometimes, there are managed objects that are logically contained in other managed objects. An object is logically contained in another if it cannot exist independently. In this case, the following scheme is often appropriate. Suppose you have Server objects which contain Application objects which contain WebModule objects which contain Servlet objects. Then their names would look like this:
domain:type=Server,name=server5
The hierachical
This scheme implies that if an object of a given type is sometimes contained in an object of another type, then it is always so contained. So here, for example, a
Server.Application is always contained in a
Server. If there are other
Application objects that are not contained in
Server objects, then they are of a different type, and that is reflected in the fact that their
Standard MBean interfacesMost MBeans are specified using
Standard MBean interfaces such as this:
public interface CacheControlMBean {
It is strongly recommended that MBeans be specified in this way where possible. This allows them to be documented using the familiar Javadoc tool, and it allows client code to interact with them straightforwardly via proxies, using
MBeanServerInvocationHandler
. Contrast the code without a proxy:
MBeanServer mbs = ...;
with the code that uses a proxy:
MBeanServer mbs = ...;
The creation of the proxy is somewhat verbose, but once it is available, the MBean can be accessed like a local object. This is much easier to write and read, and much less error-prone, than accessing the
MBeanServer method directly.
It is good practice for every method in a Standard MBean interface to be declared to throw
java.io.IOException as shown here. This forces the code using the proxy to handle this exception explicitly. Otherwise, a communication problem while using the proxy will show up as the unchecked exception
UndeclaredThrowableException wrapping the original
IOException. If your MBean will only ever be accessed locally (from within the same Java Virtual Machine) then declaring
IOException is not necessary, but this case is rare. One way to simplify local access is just to declare a subinterface that redeclares all the same methods but without
IOException:
public interface LocalCacheControlMBean extends CacheControlMBean {
This is essentially the approach adopted in the JMX API itself, between the remote interface
MBeanServerConnection and the local interface
MBeanServer. The Java class that implements the interface can implement
LocalCacheControlMBean rather than
CacheControlMBean - this will help prevent having the two interfaces get out of sync.
Dynamic MBeansOccasionally, Standard MBeans are not enough. Dynamic MBeans should be used when the interface of a managed object is not known at compile time. For example, you might have an MBean that represents an XML configuration file. Each configuration item is reflected by a read/write attribute in the MBean. The list of attributes for the MBean is constructed at runtime by examining the file.
It is almost never necessary to implement the
DynamicMBean interface for an MBean whose management interface is known at compile time. If you need some particular abilities of Dynamic MBeans, for example the ability to supply descriptions for the attributes or operations, or the ability to disable certain attributes or operations, then you should consider subclassing
javax.management.StandardMBean rather than implementing the
DynamicMBean interface. That means that the management interface is still described by a Java interface, which in turn means that clients can use that interface to make a proxy for convenient access.
Model MBeansModel MBeans are a particularly advanced feature of the JMX API. It is perfectly possible to produce an entirely adequate set of MBeans without ever using Model MBeans. Model MBeans are harder to program so they should only be used when there is a clear benefit.
The two main features of Model MBeans that are potentially useful are:
The predefined Model MBean class
RequiredModelMBean additionally can support features such as logging and persistence, but, because these are optional, portable code can not rely on them.
Item 1, concerning indirection, is usually a minor convenience. It may be useful when creating MBeans remotely, however, since the
RequiredModelMBean class is guaranteed to be present, whereas a custom MBean class that exposes methods of another Java object might not be.
Item 2, concerning additional metadata, may be useful in certain applications.
The
Jakarta Commons Modeler from the Apache Software Foundation builds on the Model MBean framework to allow you to specify MBean interfaces, including descriptors etc, using XML. The attributes and operations mentioned in XML are forwarded to an instance of a Java class that does not have to be an MBean class. The main advantage of this approach is perhaps that the entire information model can be contained in a single XML file. The main disadvantage is that there is no Java interface corresponding to the management interface of a given MBean, which means that clients cannot construct proxies.
Linking MBeans to resourcesAn MBean is not just an interface. There must be some behavior associated with that interface. Most often, that behavior depends on the application or resource being managed or monitored. In other words, the MBean must interact with other Java objects.
The simplest way to achieve this is to take an existing Java object that is part of the application and make it into an MBean. For example, you might take a
Cache object and add a
CacheMBean interface to it. Then your object is both an integral part of the application and a remotely-accessible management point.
From an object-oriented programming standpoint, it is preferable not to make the same object do two different things. Here the
Cache object is both a cache and the management of a cache, which violates this principle. An alternative approach is for the MBean to be a separate object that has a
reference to the application object. Very often this reference is passed as a parameter to the constructor of the MBean. As mentioned
above, Model MBeans provide one way to do this. Another way is to code a Standard MBean as illustrated here:
public class Cache { // the original application object
The original
Cache object from the application is unaware of management concerns. It only needs to export enough methods to allow the separate
CacheManager MBean to manage it.
Data types in MBeansAn MBean references data types in several places:
Complex data typesIt is often necessary or desirable for these data types to be more complex than simple Java types such as
Using multiple attributes instead of complex data typesIt is sometimes possible to address situations like this by breaking out the set of values into separate attributes and stipulating that those attributes must be read or written with a single getAttributes or setAttributes operation. But this tends to be a special-case solution that is difficult to implement and error-prone when clients fail to respect the requirement for using a single operation. It is also fragile in the face of evolution of the model. For example it does not extend to operation parameters or return values, and it does not work well if the values broken out into attributes are themselves complex types. So in general it is better to have a single data type representing the atomic set of values. Using model-specific classes for complex data typesComplex data types can also be represented by defining model-specific types, for example a
Automatic class downloadingRMI can be configured to automatically download classes from server to client, or more rarely from client to server, that are not already present. Jini is fundamentally based on this idea, for example. However, this approach is generally not recommended for JMX-based management for a number of reasons:
Open MBeansThe JMX API addresses the question of complex data types with Open MBeans. A normal MBean has an MBeanInfo that describes the names and types of its attributes, operations, and notifications. An Open MBean defines an OpenMBeanInfo that supplements this information with an OpenType for each attribute and operation type in addition to its Java type. Only a predefined set of Java classes can be described with Open Types. Thus, if an MBean is an Open MBean, then any client can interact with its attributes and operations, without needing model-specific classes. Additionally, the OpenMBeanInfo can describe allowed and default values for attributes, parameters, and return values. The classes that can be described in an Open Type are these:
Notice that primitive types such as
CompositeDataThe Java type of an attribute, parameter, or return value in an Open MBean can be CompositeData. In this case, the corresponding OpenType in the OpenMBeanInfo will be CompositeType. The CompositeType defines a set of items or fields. Each item has a name and an associated type, which is an Open Type. Thus, a complex thread state attribute can be represented in an Open MBean by an attribute whose Java type is CompositeData and whose corresponding Open Type is a CompositeType that describes the names and types of the thread state items.
TabularDataThe Java type of an attribute, parameter, or return value in an Open MBean can be TabularData. In this case, the corresponding OpenType in the OpenMBeanInfo will be TabularType. The TabularType describes a table in which each row is a CompositeData (with a single CompositeType describing all rows), and one or more items in the CompositeData are identified as forming the key for the table.
RecommendationsCoding Open MBeans leads to guaranteed interoperability with respect to data types. Coding Open MBeans is currently rather awkward, because they must be Dynamic MBeans. Thus, an alternative is to write MBeans that use only the Open MBean data types ( CompositeData etc), but are not actually Open MBeans (their MBeanInfo is not an OpenMBeanInfo). Such MBeans can be coded as Standard MBeans. For example, instead of referring to ThreadInfo in your MBean, you would refer to CompositeData. The CompositeData in question would have the same fields ( name, blockedCount, suspended) as the original ThreadInfo. For convenience, you can add conversion methods to the ThreadInfo class:
public CompositeData toCompositeData();
It is possible to automate the conversion from arbitrary Java classes (with certain constraints) to Open-MBean-compatible classes. Java SE 6 will add user-defined
MXBeans. This
makes it possible to use any Java type that respects a certain number of constraints. It converts types into Open Types such as
CompositeType where necessary. MXBeans already exist in
java.lang.management in version 5.0 (Tiger) of the Java platform, but only a fixed set is defined.
Datatypes for notificationsNotifications should be instances of
There is unfortunately no
A client can send an arbitrary
NotificationFilter to a server in an
ExceptionsIt is recommended that exceptions thrown by MBeans be drawn from the standard set defined in the
Self-referencing datatypesOccasionally, an information model may contain data types that are
self-referencing, that is where the definition of the type includes, directly or indirectly, a reference to the type itself. For example:
public interface Graph {
There is no way to represent such a type directly using Open Types. This is a consequence of the fact that the classes representing Open Types are immutable. The problem can be avoided by adding a level of indirection. In the example, every
Node could be given a name:
public interface Graph {
This can now be mapped to Open Types, using a
TabularData to represent the
Map<String,Node>.
Evolution of MBean interfacesIf your API includes a Standard MBean interface, then you must specify whether or not users are allowed write their own Java classes that implement it. If they are, then almost any change to the interface will risk breaking user classes that implemented it. So it is safest to spell out that the interface is only intended to specify the MBean's attributes and operations, or to facilitate the creation of proxies (for example with MBeanServerInvocationHandler ). Otherwise, you can still add new attributes and operations by putting them in a subinterface and leaving the original interface intact:
public interface CacheControl2MBean extends CacheControlMBean {
Given that you have specified that users must not implement your interface, the changes that you can make to it are essentially:
You cannot do any of the following, in each case because it would break code that accesses the MBean through MBeanServer operations such as getAttribute and invoke, and/or because it would break compilation or execution of code that accesses the MBean through a dynamic proxy using MBeanServerInvocationHandler:
If your MBean is a Dynamic MBean and does not have a Standard MBean interface that clients can use to make a dynamic proxy, then the above restrictions are slightly relaxed and the following become possible:
However it is strongly recommended to provide Standard MBean interfaces where possible because of the substantial increase in usability.
Evolution of complex typesAs described
above, an MBean may use complex types in attributes, notifications, and operation parameters and return values. It is recommended that Open Types be used, which for complex types means
ArrayType,
CompositeType, or
TabularType.
Where one of these complex types appears in a model, it cannot in general be changed in a subsequent version. However, the
contents of the type can be changed. So for example, in version 1 of a model,
getThreadInfo might return a
CompositeData with items
name,
blockedCount,
suspended; while in version 2,
getThreadInfo still returns a
CompositeData, but it now also has a
blockedTime item in addition to the previous ones. A version 1 client or server that gets the
CompositeData from a version 2 peer will simply ignore the new item. A version 2 client or server that gets the
CompositeData from a version 1 peer must be able to cope with the missing
blockedTime item.
Arrays have no real structure, so there are no particular rules for their evolution. If the description of a model explicitly states constraints on the length of an array (for example, it is always 3, or it is always at most 8), then those constraints cannot usually be violated in a subsequent version without breaking existing code.
A
TabularType is characterized by its
rowType and its
indexNames. The
indexNames cannot change in a compatible evolution, because an older peer might try to call
get(key) with a key based on the former
indexNames. The
rowType, which is a
CompositeType, can change in accordance with the rules for
CompositeType detailed next.
A
CompositeType can evolve by adding new items. An older peer will ignore these items. This is not completely bullet-proof, because the older peer might call
CompositeData.values() and be surprised to see the extra values; or it might call
oldCompositeType.isValue(newCompositeData) which will currently return
false because of the extra items. (
CompositeData.values() will probably be deprecated in a future version of the JMX API since it is of little use in practice.)
When a server adds new items, clients that know about the new items can refer to them, but they must also be prepared to handle the case when the new items are missing, because they are talking to an older server. Likewise when the server expects a
CompositeData to which new items have been added, it must be prepared to receive a
CompositeData from an older client, where the new items are missing.
NotificationsSourceAlthough the JMX API allows any object to be used as the
source field of a notification, in practice it should be one of the following:
When the MBean Server is about to forward a notification whose source is a reference to the MBean sending the notification, it changes the source into the MBean's ObjectName. In this case, if the notification is forwarded to another MBean and then resent by that MBean, the MBean Server will not rewrite the source. So relying on this rewriting is discouraged.
Semantics of notification delivery
|