The external class representation of a relation instance must implement the Relation interface so that it can be handled by the relation service. The RelationSupport class is the implementation provided which is also used internally by the service.
The methods of the relation interface expose all of the information needed to operate on a relation instance: the getters and setters for roles and the defining relation type. Because the relation support class must represent any possible relation type, it has a constructor that takes a relation type and a role list, and it uses a generic mechanism internally to represent any roles.
You could implement a simpler relation class that implements a specific relation type, in which case it would know and initialize its own roles. The class could also interact with the relation service to create its specific relation type before adding itself as a relation.
However, the simplest way to define a relation object is to extend the RelationSupport class and provide any additional functionality you require. In doing so, you can rely on the relation support class's own methods for getting and setting roles, thereby taking advantage of their built-in consistency mechanisms.
import javax.management.ObjectName; import javax.management.relation.*; public class SimpleRelation extends RelationSupport implements SimpleRelationMBean { // Constructor public SimpleRelation(String theRelId, ObjectName theRelServiceName, String theRelTypeName, RoleList theRoleList) throws InvalidRoleValueException, IllegalArgumentException { super(theRelId, theRelServiceName, theRelTypeName, theRoleList); } [...] // Implementation of the SimpleRelationMBean interface } |
Our MBean's SimpleRelationMBean interface extends the RelationSupportMBean in order to expose its operations for management. In order to represent a relation, the class must be an MBean registered in the MBean server. This allows the relation service to rely on unregistration notifications in order to find out if the object name is no longer valid.
When instantiating our SimpleRelation MBean, we use the relation type defined in Example 15–3. We also reuse the role list from Example 15–5 that contains a single MBean in each of two roles. Before adding the relation to the relation service, we must create it as an MBean in the MBean server. We then call the addRelation operation of the relation service with our relation's object name.
// Using relTypeName="myRelationType" // and roleList1={container,contained} String relMBeanClassName = "SimpleRelation"; String relId2 = relTypeName + "_instance"; ObjectName relMBeanObjName = new ObjectName( "DefaultDomain:type=SimpleRelation2"; try { Object[] params1 = new Object[4]; params1[0] = relId2; params1[1] = relServObjName; params1[2] = relTypeName; params1[3] = roleList1; String[] signature1 = new String[4]; signature1[0] = "java.lang.String"; signature1[1] = "javax.management.ObjectName"; signature1[2] = "java.lang.String"; signature1[3] = "javax.management.relation.RoleList"; server.createMBean(relMBeanClassName, relMBeanObjName, params1, signature1); } catch(Exception e) { echo("\t Could not create relation MBean for relation " + relId2); printException(e); } // Add our new MBean as a relation to the relation service try { Object[] params2 = new Object[1]; params2[0] = relMBeanObjName; String[] signature2 = new String[1]; signature2[0] = "javax.management.ObjectName"; server.invoke(relServObjName, "addRelation", params2, signature2); } catch(Exception e) { echo("\t Could not add relation MBean " + relMBeanObjName); printException(e); } |
After a relation instance is added to the relation service, it can be accessed normally like other relations. Management operations can either operate on the MBean directly or access it through its identifier in the relation service. Two methods of the service are specific to external relation MBeans:
isRelationMBean - Takes a relation identifier and returns the object name of the relation MBean, if it is defined
isRelation - Takes an object name and returns its relation identifier, if it is a relation MBean that has been added to the relation service
In our example, our MBean does not expose any functionality that interacts with the relation service. It relies fully on the support class and only adds the implementation of its own simple MBean interface. In a more realistic example, the MBean would expose attributes or operations related to its role values.
For example, Personal Library could be a unary relation type containing the Books role. We could then design an Owner MBean to be a relation of this type. In addition to exposing attributes about the owner, the MBean would give the number of books in the library, return an alphabetized list of book titles, and provide an operation for selling a book. All of these would need to access the role list, and the sale operation would need to modify the role to remove a book MBean.
All of these operations would need to keep the consistency of the relation. To do this, the relation service exposes several methods that relation MBeans must call:
checkRoleReading: Verifies the read access for the role of a given relation type, before it is read
checkRoleWriting: Verifies the write access, multiplicity and MBean class of a role value before it can be written
updateRoleMap: Provides the old and new values of a role so that the relation service can update its internal lists of referenced MBeans
SendRoleUpdateNotification: Instructs the relation service to send a notification containing the given old and new values of a role; since the relation service must be the broadcaster for all relation notifications, relation MBeans must call this method after modifying a role value