The relation service classes, which were briefly mentioned in the previous section, are the basic classes needed to describe relationships between MBeans. In this section, we will take a closer look at these classes. The material here will serve as a reference for the next section, in which we will see how to write code to use the relation service. Examples will be provided in this section to point out some of the features of the various classes. In this section, we assume that the relation service has been created and has been given the variable name relationService. In the next section, Section 11.3, we will look at more detailed examples.
The RoleInfo
class is used to describe the role that one or more MBeans (of the
same Java class) perform. RoleInfo
contains the
following read-only
attributes:
Name
The name of the role. Must be unique for any
given RelationType
object.
RefMBeanClassName
The Java class name of the MBean(s) that will
act in the role described by this RoleInfo
object.
Readable
Indicates whether or not information about the role can be accessed.
Writable
Indicates whether or not information about the role can be modified.
MinimumDegree
The lower bound on the multiplicity (size) of the number of MBeans that may perform the role. Must be less than or equal to the maximum degree.
MaximumDegree
The upper bound on the multiplicity (size) of the number of MBeans that may perform the role. Must be greater than or equal to the minimum degree.
Description
These attributes are set using one of the three
constructors provided by
RoleInfo
:
public RoleInfo(String theName, String theRefMBeanClassName) throws IllegalArgumentException, ClassNotFoundException, NotCompliantException { // . . . } public RoleInfo(String theName, String theRefMBeanClassName, boolean theIsReadable, boolean theIsWritable) throws IllegalArgumentException, ClassNotFoundException, NotCompliantException { // . . . } public RoleInfo(String theName, String theRefMBeanClassName, boolean theIsReadable, boolean theIsWritable, int theMinDegree, int theMaxDegree, String theDescription) throws IllegalArgumentException, InvalidRoleInfoException, ClassNotFoundException, NotCompliantException { // . . . }
The first constructor shows the minimum amount of information that the agent must provide about a role: the name of the role and the class names of the MBean instances that act in that role. When you use this constructor, the other values are set to default values. The current default values in the RI are listed in Table 11-1; however, these default values might change in future releases of the JMX specification, so check the Javadoc before using them.
Table 11-1. Default values for RoleInfo attributes
Attribute |
Default value |
---|---|
|
|
|
|
|
1 |
|
1 |
|
|
The second constructor allows the agent to set the
Readable
and Writable
attributes of the role. MinimumDegree
and
MaximumDegree
are set to their default values.
The third constructor allows the agent to set all of the attributes
of RoleInfo
.
The RelationType
interface is used to describe a relationship between one or more
roles in an n-ary association. In this section,
we will assume that we are going to use the relation service to
create the RelationType
object (most likely an
instance of RelationSupport
) on behalf of the
agent, resulting in an internal relation type. To describe a relation
type to the relation service, the relation service needs to know two
things:
What is the name of the association represented by the relation type?
What RoleInfo
objects are involved in the
association?
The name of the association (i.e., the relation type) is a
String
that must be unique for all relation types
that the relation service knows about (otherwise, an exception will
be thrown). The agent must also create and pass an array of
RoleInfo
objects that represent the roles played
by MBean instances, which may or may not have been instantiated at
this point. The RelationType
interface is
defined as:
package javax.management.relation; public interface RelationType extends Serializable { public String getRelationTypeName( ); public List getRoleInfo( ); public RoleInfo getRoleInfo(String theRoleInfoName) throws IllegalArgumentException, RoleInfoNotFoundException; }
Through the RelationType
interface, we can get
access to the name of the relation type, a
java.util.List
object containing all of the
RoleInfo
objects that have been defined for this
relation type, and a single RoleInfo
object that
corresponds to a specific role name. As we mentioned earlier, when
discussing RoleInfo
, the name given to a
RoleInfo
object must be unique within any instance
of RelationType
.
A role is named
collection of one or more MBean object names that corresponds to a
RoleInfo
object. The MBeans do not have to be
registered, or even instantiated, to be added to a role. When
creating a Role
object, we must know the name of
the RoleInfo
object that describes the role the
collection of MBeans will perform—otherwise, the relation
service will not correctly map the Role
object
with its corresponding RoleInfo
metadata object
and will throw an exception when we attempt to create a relation. By
the same token, the MBeans whose object names are part of the role
must be instantiated and registered with the MBean server before we
attempt to create a relation using the Role
object
that contains them.
A Role
object is created using its lone
constructor:
public Role(java.lang.String theRoleName, java.util.List theRoleValue) throws java.lang.IllegalArgumentException { // . . . }
The first argument is the name of the role. It must match the name of
a RoleInfo
object that has been used to create a
relation type. The second argument is a List
of
MBean object names (i.e., ObjectName
objects) that
correspond to the MBean objects that will perform the role. If either
of the theRoleName or the
theRoleValue parameters are
null
, an
IllegalArgumentException
will be thrown.
The RoleList
class extends java.util.ArrayList
and is a list of
Role
objects. A RoleList
object
is used primarily to create a relation through the
createRelation( ) method of the relation
service. The RoleList
class is
defined as:
public class RoleList extends ArrayList { public RoleList( ) { // . . . } public RoleList(int theInitialCapacity) { // . . . } public RoleList(List theList) throws IllegalArgumentException { // . . . } public void add(Role theRole) throws IllegalArgumentException { // . . . } public void add(int theIndex, Role theRole) throws IllegalArgumentException, IndexOutOfBoundsException { // . . . } public void set(int theIndex, Role theRole) throws IllegalArgumentException, IndexOutOfBoundsException { // . . . } public boolean addAll(RoleList theRoleList) throws IndexOutOfBoundsException { // . . . } public boolean addAll(int theIndex, RoleList theRoleList) throws IllegalArgumentException, IndexOutOfBoundsException { // . . . } public Object clone( ) { // . . . } }
A few convenience methods are provided on RoleList
that make using it more type-safe with respect to the relation
service. For example, one version of the add( )
method takes a role parameter, instead of the
object parameter for the corresponding version
of add( ) found in ArrayList
.
This
class
is at the heart of the relation service. The methods on this class
allow agents to create and remove relation types and relations, find
relationships between MBeans, and retrieve specific information about
the relations that are maintained by the relation service. The
relation service implementation class,
RelationService
, is too large to show a complete
listing here. The
methods that we will use most often are:
Retrieves the list of MBean object names for a specific role name within a specific internal relation
Removes a specific internal relation from the relation service
Removes a specific internal relation type from the relation service
You probably noticed that most of the methods on the
RelationService
class deal with internal
relations. As we mentioned earlier, for external relations the
relation service provides a class called
RelationSupport
, which we will discuss later in
this chapter. The above list of RelationService
methods is not exhaustive—in the interests of space, I have
omitted the less frequently used methods from this discussion. All of
the methods are described in the Javadoc delivered with the JMX RI.
The RelationService
class provides a single
constructor:
public RelationService(boolean theImmediatePurgeFlg) { // . . . }
The boolean
argument to this constructor indicates
whether or not the relation service should search for and remove
invalid relations from its internal implementation immediately after
an MBean that is referenced in a relation is unregistered. If the
value of this parameter is true
, as soon as any
referenced MBean is unregistered, the relation service will check to
see if the unregistration of the MBean causes any relations to become
invalid. Any invalid relations will then be removed from the relation
service. If the value of this parameter is false
,
the agent must invoke the relation service’s
purgeRelations(
)
method in order for this check to be
made and any necessary processing to be performed.
For all internal relations, it is the job of the relation service to ensure the consistency of relations.
The RelationService
class implements an MBean
interface, which allows it to be controlled by a management
application. Before the relation service can be used, the
RelationService
instance created by the agent must
be registered with the MBean server.
This class
is
provided by the relation service as a convenience to agent developers
so that relation types can be created that are external to the
relation service. Typically, we would subclass the
RelationTypeSupport
class, provide our own
constructor, and override any methods we deem necessary. For each
internal relation type defined using the
createRelationType( ) method of the relation
service implementation, an instance of this class is created and
maintained by the relation service. However, internal relation types
are not directly accessible once they are created. Creating external
relation types gives us more flexibility in terms of how to create
and maintain relation types. The
RelationTypeSupport
class implements the
RelationType
interface and adds a
protected
method called addRoleInfo(
)
, which allows subclasses to add a
RoleInfo
object to the relation type. There are
two constructors for RelationTypeSupport
:
public RelationTypeSupport(String theRelTypeName, RoleInfo[] theRoleInfoArray) throws IllegalArgumentException, InvalidRelationTypeException { // . . . } protected RelationTypeSupport(String theRelTypeName) { // . . . }
The RelationTypeSupport
class does not have to be
subclassed, and it provides a public constructor that allows us to
specify the relation type name and an array of
RoleInfo
objects. We can use this constructor to
create a relation type that is external to the relation service,
without having to subclass RelationTypeSupport
.
Should we choose to subclass RelationTypeSupport
,
however, there is a protected constructor that allows us to specify
the name of the relation type. This constructor may be called only
from a subclass. Typically we will subclass
RelationTypeSupport
, and in our
subclass’s constructor we will do two things:
Delegate the relation type name to the protected constructor of
RelationTypeSupport
.
Create the necessary RoleInfo
objects and add them
to the parent class one at a time, via its protected
addRoleInfo( ) method.
Subclasses are also free to override the implementation of the
RelationType
interface provided by
RelationTypeSupport
as necessary.
Like
RelationTypeSupport
,
this class is provided by the relation service as a convenience to
agent developers so that relations can be created that are external
to the relation service. As with the
RelationTypeSupport
class, we subclass the
RelationSupport
class, provide our own
constructor, and override any methods we deem necessary. For each
internal relation defined using the createRelation(
) method of the relation service implementation, an
instance of this class is created and maintained by the relation
service. However, internal relations are not directly accessible once
they are created. Creating external relations gives us more
flexibility in terms of how to create and maintain the consistency of
relations. The RelationSupport
class implements an
MBean
interface—RelationSupportMBean
—that
allows external relations to be controlled by a management
application. This gives external relations an advantage over internal
relations when it is necessary to monitor or control MBean
relationships through a management application.
RelationSupport
provides two
constructors, defined as:
public RelationSupport(String theRelId, ObjectName theRelServiceName, String theRelTypeName, RoleList theRoleList) throws InvalidRoleValueException, IllegalArgumentException { // . . . } public RelationSupport(String theRelId, ObjectName theRelServiceName, MBeanServer theRelServiceMBeanServer, String theRelTypeName, RoleList theRoleList) throws InvalidRoleValueException, IllegalArgumentException { // . . . }
In creating a RelationSupport
instance, we must
provide (at minimum) the
following parameters:
As we mentioned earlier, the RelationService
instance created by the agent must be registered with the MBean
server in order to be used. As we can see from the second parameter
to both RelationSupport
constructors, the object
name that is assigned by the agent to the relation service is
required in order to create an internal relation. In fact, not only
must the object name of the relation service be provided, but the
RelationService
object must have been instantiated
and registered with the MBean server prior to creating an external
relation. This is because of certain consistency checks that the
relation service makes about the external relation that is
created—it cannot make these checks unless the relation service
is running (and registered). In addition, the
RelationSupport
object maintains a reference to
the MBean server with which it is registered and uses this reference
to indirectly invoke methods on the relation service MBean.
The second constructor is provided only as a convenience to those
agents that have not registered the external relation MBean with the
MBean server, but will do so before the relation is actually
referenced. The third parameter is a reference to the MBean server
with which the external relation will be registered. This constructor
must be used with care. Under normal circumstances, the external
relation is immediately registered with the MBean server when it is
created. The RelationSupport
class implements the
MBeanRegistration
interface, so it has access to a
reference to the MBean server in which it is registered (this
reference is passed to the preRegister( )
method). Because the specification does not dictate when the initial
consistency checks are made, it is safer to immediately register any
external relations with the MBean server once they are instantiated.