|
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 Names
Every 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 Syntax
An 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 * or ? character then the Object
Name is a pattern. These characters cannot be used in the name of an
MBean, only when matching MBeans.
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 type=Thread.
When there is more
than one key property, they are separated with commas, for example type=Thread,name=DGC.
Spaces are significant everywhere in an Object Name.
Do not write type=Thread, name=DGC (with a space
after the comma) because it will be interpreted
as having a key called " name", with a leading
space in the name.
Object Names are case sensitive.
The order of key properties is not significant. There is no
difference between type=Thread,name=DGC and
name=DGC,type=Thread.
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"
com.sun.someapp:type=Whatsit,name="25,26"
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 *;
or it can be empty (equivalent to a *); or it can be a
list followed by ,*. These forms
match Object Names that have the exact key properties given (if any)
plus any arbitrary other key properties. For example, *:type=Thread,*
matches somedomain:type=Thread and somedomain:type=Thread,name=DGC.
Object Name
Conventions
Object 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
com.sun.appserv.Domain1:type=Whatever
The domain should not contain the character slash (/).
That character is reserved for MBean Server hierarchies ("cascading").
This will be detailed further in a later version of this document.
Every Object Name should contain a type= key property.
This property should be different for every object type in a given
domain. JSR 77 (J2EE management) defines a j2eeType=
key property with essentially the same semantics. Since JSR 77 allows
arbitrary extra keys in addition to the standard ones it defines, it is
possible to add a type= key in addition to the j2eeType=
one. Note that allowing extra keys like this contradicts the
predictability requirement stated above and is not recommended for new
JMX models. It makes writing non-interactive clients unnecessarily
difficult (you always have to query before accessing any object to
discover its actual name).
Every Object Name with a given type should have the
same
set of key properties with the same syntax and semantics for their
values.
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 type.
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 type is
name. Often, type=X,name=Y is enough
to name an MBean. Some JMX-aware consoles are able to display this form
of name using a shorthand that is easier to read than other names.
Sometimes it is useful to define additional properties as well as name,
to facilitate searches using patterns as described above. For example,
there might be a category or group property,
allowing patterns such as:
com.sun.someapp:group=configuration,*
Object containment
Sometimes, 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 domain:type=Server.Application,Server=server5,name=app1 domain:type=Server.Application.WebModule,Server=server5, Application=app1,name=module3 domain:type=Server.Application.WebModule.Servlet,Server=server5, Application=app1,WebModule=module3,name=default
The hierachical type property makes it possible to
understand the meaning of
the other keys without a priori knowledge of the model. Since
Object Name keys are
unordered, it would otherwise not be possible to know whether for
instance, in the third
and fourth names here, an Application
is contained in a Server or vice versa.
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
type property will not be Server.Application.
This is consistent with the rule that a given type always
implies the same list of other key properties.
Standard MBean
interfaces
Most MBeans are specified using Standard MBean interfaces
such as this:
public interface CacheControlMBean { int getSize() throws IOException; void setSize(int size) throws IOException; int getUsage() throws IOException; int dropOldest(int n) throws IOException; }
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 = ...; Integer sizeI = (Integer) mbs.getAttribute(objectName, "Size"); int size = sizeI.intValue(); if (size > desiredSize) { mbs.invoke(objectName, "dropOldest", new Integer[] {new Integer(size - desiredSize)}, new String[] {"int"}); }
with the code that uses a proxy:
MBeanServer mbs = ...; CacheControlMBean cacheControl = (CacheControlMBean) MBeanServerInvocationHandler.newProxyInstance(mbs, objectName, CacheControlMBean.class, false); int size = cacheControl.getSize(); if (size > desiredSize) cacheControl.dropOldest(size - desiredSize);
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 { int getSize(); void setSize(int size); int getUsage(); int dropOldest(int n); }
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 MBeans
Occasionally, 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 MBeans
Model 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:
- They add a level of indirection. This means that you can take an
existing Java object that was not designed as an MBean, and expose one
or more of its public methods as MBean operations.
- They associate additional information with the MBeanInfo
and MBean*Info (e.g. MBeanAttributeInfo) classes,
in the form of descriptors.
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
resources
An 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 ... public int getSize() {...} ... }
public class CacheManager implements CacheManagerMBean { private final Cache cache;
public CacheManager(Cache cache) { this.cache = cache; }
public int getSize() { return cache.getSize(); } ... }
public interface CacheManagerMBean { public int getSize(); ... }
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 MBeans
An MBean references data types in several places:
- Every attribute has a type. In Standard MBeans, this is
the return type of the getter method and/or the parameter type of the
setter method.
- Every operation has a return type, and a type for each of
its parameters. In Standard MBeans, these types are the same as the
return and parameter types of the corresponding Java method.
- A getAttribute, setAttribute, or invoke
can
throw an exception. In Standard MBeans, these exceptions are thrown
from the getter, setter, or operation method; if they are checked
exceptions they must be declared in the
throws clause of
the method. However, the set of thrown exceptions is not in general
visible to management clients.
- A notification can be of any subtype of
javax.management.Notification.
In addition, its userData
field can refer to a Java object of any reference type.
Complex data types
It is often necessary or desirable for these data types to be more
complex than simple Java types such as
int or String. In particular, when an
attribute represents a snapshot of values
such as the state of a thread at a given moment, it may not be
meaningful to see a set of different
values taken at different times. That could lead to meaningless results
such as a thread that appears to
be both running and waiting for a certain lock.
Using multiple
attributes instead of complex data types
It 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 types
Complex data types can also be represented by
defining model-specific types, for example a ThreadInfo
type
for a snapshot of a thread. But this solution presents its own
problems. Chief among these is that the client
must have the same Java classes available. This is very inconvenient
for model-neutral clients such as generic JMX consoles. It also
potentially causes problems for access from languages other than
Java (for instance, from scripts). And it can lead to serious
class-loading headaches if the same client must interact with
servers that have different versions of the model-specific classes.
Finally, using arbitrary Java types can lead to unforeseen problems
with serialization, since when an object is serialized other objects
that it
references may also be serialized, meaning that a client must have the
classes for those other objects available too.
Automatic class
downloading
RMI 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:
- It only works with the RMI connector defined by the JMX Remote
API, not with the JMXMP connector defined there or with other currently
non-standard connectors such as HTTP connectors.
- It requires client and server to have access to a common code
source. Typically, this is an HTTP server where the classes are
installed. Setting up and maintaining this server is non-trivial.
- The client (or server if it is the server that is downloading)
must be configured with a security manager and it must be adjusted with
exactly the right permissions. Getting the permissions wrong may mean
that the downloaded code will not work, or may expose the client to
security attacks.
- Third parties are generally suspicious of code downloading. If
the JMX model is exposed as a public interface, and if people are told
that to use it they must configure their security to allow code
downloading, this will meet with resistance.
- The approach does not map well to access from non-Java clients
such as scripts.
- The approach typically requires client and server to share at
least a Java interface describing the data type, so what is downloaded
is an implementation of this interface. In the cases we are talking
about, the classes are value classes and there is little to be gained
by this separation of interface and implementation. Furthermore, the
interface classes still have to be shared between client and server,
with the problems already discussed above.
Open MBeans
The 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:
- Primitive wrapper classes from
java.lang: Integer,
Boolean, Void etc.
- The classes
String, Date, ObjectName,
BigDecimal, BigInteger.
CompositeData, described below.
TabularData, described below.
- An array of any of the classes in this list.
Notice that primitive types such as int are not in
this list.
In practice there is no difference to a client between an access to int
and an access to java.lang.Integer, because everything
goes through
reflection; but there is a difference between int[] and
Integer[]. We expect that the next version of the JMX spec
will
allow primitive types (and arrays thereof) in Open MBeans; see bug
5045358.
CompositeData
The 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.
TabularData
The 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.
Recommendations
Coding 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(); public static ThreadInfo from(CompositeData cd);
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
notifications
Notifications should be instances of javax.management.Notification
or
one of the subclasses from the javax.management
namespace.
Information that does not fit into one of those subclasses should be
conveyed
by attaching a CompositeData to the notification
using the
setUserData method.
There is unfortunately no OpenMBeanNotificationInfo
class today (see bug 5072197).
If such a class existed, it could be used to indicate what the CompositeData
in the userData for the notification(s) emitted by an MBean
would look like.
A client can send an arbitrary NotificationFilter to a
server in an addNotificationListener operation. However,
using an application-specific filter class is subject to the same sorts
of problems as detailed for model-specific
classes above. It is recommended that only the standard filters
defined in javax.management.* be used. (NotificationFilterSupport,
AttributeChangeNotificationFilter, MBeanServerNotificationFilter.)
Exceptions
It is recommended that exceptions thrown by MBeans be drawn from the
standard set defined in the java.* and javax.*
packages on the Java SE platform. If an MBean throws a non-standard
exception,
a client that does not have that exception class will likely see
another exception such as ClassNotFoundException instead.
Self-referencing
datatypes
Occasionally, 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 { public Node[] getNodes(); } public interface Node { public Node[] getNeighbours(); }
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 { public Map<String,Node> getNodes(); } public interface Node { public String[] getNeighbours(); }
This can now be mapped to Open Types, using a TabularData
to represent the Map<String,Node>.
Evolution of MBean
interfaces
If 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 { void saveConfiguration() throws IOException; }
Given that you have specified that users must not implement your
interface, the changes that you can make to it are essentially:
- adding a new operation
- overloading an existing operation (but overloading is not
recommended in general)
- changing the type of a write-only attribute from a class to a
superclass or superinterface (for example from String to Object
or from HashMap to Map), or from a primitive type
to a wider primitive type (for example from int to long)
- changing the type of a read-only attribute or the return type of
an operation from a class to a subclass (for example from Object
to String)
- adding or removing unchecked exceptions in the throws
clause.
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:
- removing an attribute or operation
- changing the type of a write-only attribute in any way other than
specified above
- changing the type of a read-only attribute or the return type of
an operation in any way other than specified above
- changing the type of a read-write attribute
- changing the parameters of an operation in any way
- adding or removing checked exceptions in the throws
clause (this includes replacing an exception by a subclass or
superclass).
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:
- changing the type of a write-only attribute in any way, provided
that your MBean can still deal with the old type
- changing the type of a read-write attribute from a class to a
subclass, again provided that your MBean can still deal with the old
type when the attribute is set
- changing the parameters of an operation, provided that your MBean
can still deal with the old parameters
- there is no such thing as a throws clause in this case
so the restriction on that is irrelevant.
However it is strongly recommended to provide Standard MBean
interfaces where possible because of the substantial increase in
usability.
Evolution of complex
types
As 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.
Notifications
Source
Although 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:
- an ObjectName, usually that of the MBean that constructed the
Notification object
- a reference to the MBean object that is sending the notification.
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
It is important to be aware of the semantics of notification
delivery when defining how notifications are used in
a model. Remote clients cannot assume that they will receive all
notifications for which they are listening. The JMX Remote API only
guarantees a weaker condition:
A client either receives all
notifications for which it is listening, or can discover that
notifications may have been lost.
A consequence of this weaker guarantee is that notifications should
never be used to deliver information that is not also available in
another way. The typical client observes the initial state of the
information model, then reacts to changes in the model signalled by
notifications. If it sees that notifications may have been lost, it
goes back and observes the state of the model again using the same
logic as it used initially. The information model must be designed so
that this is always possible. Losing a notification must not mean
losing information irretrievably.
When a notification signals an event that might require intervention
from the client, the client should be able to retrieve the information
needed to react. This might be an attribute in an MBean that contains
the same information as was included in the notification. If the
information is just that a certain event occurred, it is often enough
just to have a counter of how many times it occurred. Then a client can
detect that the event occurred just by seeing that the counter has
changed.
A client can discover when notifications are lost by registering a
listener using JMXConnector.addConnectionNotificationListener.
Large data values
The existing JMX protocols are not very well adapted to moving about
large data values (on the order of tens of thousands of bytes or more).
This is true for notification payloads as well as for attribute values
being read or written and for parameters and return values of
operations. Although large data values will work, there may be an
effect on concurrent access
using the same connector client. It is often preferable to send a URL
that allows the other end (client or server) to access the large data
value directly.
This is particularly important for notifications. Because of the way
notification sending works in the current protocols, a notification may
remain in the server for an indefinite period after being sent. Thus,
if many large notifications are sent (for example because they have a
very big string or byte array in the userData field), an OutOfMemoryError
may result.
Related documentation
The article Apply
JMX Best Practices from the Java Pro journal provides a set of
higher-level recommendations that complement the ones in this document.
|