Java Dynamic Management Kit 5.0 Tutorial

Chapter 16 Cascading Agents

The cascading service enables you to access the MBeans of a subagent directly through the MBean server of the master agent. The service is implemented in the CascadingAgent MBean that connects to a remote subagent and makes all of the subagent's MBeans visible in the master agent. An agent can have several subagents, and subagents can themselves cascade other agents, forming a hierarchy of cascading agents.

By connecting to the root of an agent hierarchy, managers can have a single access point to many resources and services. All MBeans in the hierarchy are manageable through the top master agent, and a manager does not need to worry about their physical location. Like the other services, the cascading agent is implemented as an MBean that can be managed dynamically. This enables the manager to control the structure of the agent hierarchy, adding and removing subagents as necessary.

In particular, the cascading service MBean can work with any protocol connector, including any custom implementation. Those supplied by the Java Dynamic Management Kit (DMK) give you the choice of using RMI, HTTP, or HTTPS. The cascading service also lets you specify a filter for selecting precisely the MBeans of the subagent that will be mirrored in the master agent. This mechanism lets you limit the number of MBeans that are mirrored in the top agent of a large cascading hierarchy.

The code samples in this topic are from the files in the Cascading directory located in the main examplesDir (see Directories and Classpath in the preface).

This chapter contains the following topics:

CascadingAgent MBean

You should create one CascadingAgent MBean for every subagent you want to manage through the master agent. Each connects to an agent and mirrors all of that agent's registered MBeans in the master agent's MBean server. No other classes are required or need to be generated in order to represent the MBeans.

The agent whose MBean server contains an active cascading service is called a master agent in relation to the other agent that is mirrored. The agent to which the cascading service is connected is called the subagent in relation to its master agent. We say that it creates mirror MBeans to represent the subagent's MBeans. See Mirror MBeans in the Master Agent for a description of these objects.

A master agent can have any number of subagents, each controlled individually by a different CascadingAgent MBean. A subagent can itself contain cascading agents and mirror MBeans, all of which are mirrored again in the master agent. This effectively enables cascading hierarchies of arbitrary depth and width.

Two master agents can also connect to the same subagent. This is similar to the situation where two managers connect to the same agent and can access the same MBean. If the implementation of a management solution permits such a condition, it is the designer's responsibility to handle any synchronization issues in the MBean.

The connection between two agents resembles the connection between a manager and an agent. The cascading service MBean relies on a connector client, and the subagent must have the corresponding connector server. The subagent's connector server must already be instantiated, registered with its MBean server, and ready to receive connections.

In our example application, we use the RMI connector client that we will connect to the RMI connector server of the subagent on port 1099 of the local host. In fact, this is the same as the default values when instantiating a cascading agent MBean, but we also want to specify a pattern for selecting the MBeans to mirror. By default, all MBeans of the subagent are mirrored in the master agent; we provide an object name pattern to only select those in the subagent's CascadedDomain.


Example 16–1 Connecting to a Subagent

ObjectName mbeanObjectName = null;
String domain = server.getDefaultDomain();
mbeanObjectName = new ObjectName(domain + ":type=CascadingAgent");
[...]

RmiConnectorAddress address = new RmiConnectorAddress(
    java.net.InetAddress.getLocalHost().getHostName(),
    1099,
    "name=RmiConnectorServer");
CascadingAgent remAgent = new CascadingAgent(
    address,
    "com.sun.jdmk.comm.RmiConnectorClient",
    new ObjectName("CascadedDomain:*"),
    null);
ObjectInstance remAgentInstance =
    server.registerMBean(remAgent, mbeanObjectName);

[...] // Output omitted
// Now we explicitly start the cascading agent
// as it is not started automatically
//
echo("\nStarting the cascading agent...");
[...]
server.invoke(mbeanObjectName, "start", null, null);
sleep(1000);
echo("\tIs ACTIVE = " + server.getAttribute(mbeanObjectName, "Active"));  
echo("done");

Before the subagent's MBeans are mirrored, the CascadingAgent MBean must be registered in the master agent's MBean server, and its mirroring must be started. When you invoke the start operation of the cascading service MBean, it will connect it to its designated subagent and create one mirror MBean to represent each MBean in the subagent. When its Active attribute becomes true, the cascading mechanism is ready to use.

The CascadingAgent MBean exposes two writable attributes:

Neither of these attributes can be modified when the cascading service is active. You must first call the MBean's stop operation: this will remove all of the mirror MBeans for the given subagent and disconnect from the subagent's connector server. You can then modify the address or the class of the connector client. The new values will be used when you start the mirroring again: this lets you change subagents or even change protocols.

When the cascading service is stopped or its MBean is removed from the master agent, all of its mirror MBeans are unregistered. The MBean server delegate in the master agent will send an unregistration notification for each mirror MBean as it is removed.

Mirror MBeans in the Master Agent

Once the cascading service is active, you interact directly with the mirror MBeans representing the subagent's MBeans. You can access and manage a mirror MBean as if you are connected to the subagent and accessing or managing the original MBean. The mirror MBeans are actual MBean objects registered in the master agent's MBean server with the same object name.

All management operations that you can perform on the original MBean can be performed identically on its mirror MBean. You can modify attributes, invoke operations and add or remove listeners, all with exactly the same result as if the manager were connected to the subagent when performing the action.

The behavior of a mirror MBean is to transmit the action to the subagent's MBean and return with an answer or result. The actual computation is performed by the original MBean running in its own agent.

In our example, we know that there is a timer MBean that was created in the subagent. Once the cascading service is active for our subagent, we operate the timer through its local mirror MBean. We can never have the direct reference to a mirror MBean, so we always invoke operations through the master agent's MBean server.


Example 16–2 Managing Mirrored MBeans

// Here we know the object name of the MBean we want to access, the
// object name of its mirrored MBean in the master agent will be identical.
ObjectName timerName = new ObjectName("CascadedDomain:type=timer");

echo("\n>>>  Ask the Timer MBean to send a notification every 5 seconds ");
java.util.Date currentDate = new java.util.Date();
Object params[] = { 
    "Timer",
    "Message",
    new Integer(5),
    new java.util.Date (currentDate.getTime() + new Long (2).longValue()),
    new Long(1000) };

String signatures[]={ "java.lang.String",
                      "java.lang.String",
                      "java.lang.Object",
                      "java.util.Date",
                      "long"};

server.invoke(timerName, "addNotification", params, signatures);
server.invoke(timerName, "start", null, null);

echo("\n>>>  Add ourselves as a listener to the Timer MBean");       
server.addNotificationListener(timerName, this, null, null);

echo("\nPress <Enter> to remove the listener from the Timer MBean ");
waitForEnterPressed();
server.removeNotificationListener(timerName, this);

For the managing application, the mirror MBean in the master agent is the MBean. Unregistering a mirror MBean in the master agent will unregister the mirrored MBean in the subagent. If you want to control the number of mirror objects without removing the originals, you must use filters and/or queries of the subagent's MBeans in the constructor of the cascading service MBean.

The mirror and its mechanism make the cascading totally transparent: a manager has no direct way of knowing whether an object is a mirror or not. Neither does it have any direct information about the topology of the cascading hierarchy rooted at the agent that it accesses. If this information is necessary, the MBeans should expose some kind of identification through their attributes, operations, or object names.

Class of a Mirror MBean

Mirror MBeans are implemented as dynamic MBeans; they are instances of the CascadeGenericProxy class. The cascading service gives them the MBeanInfo object that they will expose and establishes their connection with the original MBean. The MBean information contains the class name of the original MBean, not their own class name. Exposing this borrowed class name guarantees that the cascading service is completely transparent.

The symmetry of the Java dynamic management architecture means that this cascading mechanism is scalable to any number of levels. The mirror object of a mirror object is again an instance of the CascadeGenericProxy class, and it borrows the same object name and class name. Any operation on the top mirror will be propagated to its subagent, where the intermediate mirror will send it its own subagent, and so forth. The cost of cascading is the cost of accessing the subagent: the depth of your cascading hierarchy should be adapted to your management solution.

Because the cascading service MBean instantiates and controls all mirror MBeans, the CascadeGenericProxy class should never be instantiated through a management operation, nor by the code of the agent application. We have described it here only to provide an example application of dynamic MBeans.

Cascading Issues

In this section, we explain some of the design issues that are determined by the implementation of the cascading service.

Dynamic Mirroring

Any changes in the subagent's MBeans are automatically applied to the set of mirror MBeans, to ensure that both master agent and subagent remain consistent.

When an MBean is unregistered from the subagent, the cascading service MBean removes its mirror MBean from the master agent. When a new MBean is registered in the subagent, the cascading service instantiates its mirror MBean, sets up its connection to the new MBean, and registers the mirror with the master agent's MBean server.

Both of these mechanisms scale to cascading hierarchies: adding or removing an MBean in the master agent will trigger a notification that any cascading service connected to the master agent will receive. This will start a chain reaction up to the top of the hierarchy. Removing an MBean from the middle of a hierarchy also triggers a similar reaction down to the original MBean that is finally removed.

Dynamic unregistration only applies to subagent MBeans that are actually mirrored. Dynamic registration is also subject to filtering, as described in the next section.

MBean Filtering

When the cascading service MBean is instantiated, you can pass it an object name pattern and a query expression. These will be applied to the list of MBeans in the subagent to determine those that will be mirrored in the master agent. The filtering will be in effect for the life of the cascading service connected to this MBean.

Filtering the mirrored MBeans reduces the number of MBeans in the master agent. It also provides a way of identifying mirror MBeans in the master agent, as in our example where cascading is limited to MBeans in the CascadedDomain.

Both the object name pattern and query expression will be used to filter any new MBean that is registered in the subagent. If the new MBean meets the filter criteria, it will become visible and mirrored in the master agent. Since the query expression applies to attribute values of the MBean, you must be careful to initialize the new MBean before registering it so that its values are significant when the filter is applied by the cascading service.

Naming in Cascading Agents

Mirror MBeans are registered in the master agent with the same object name as the mirrored MBean in the subagent. If the registration fails in the master agent's MBean server, no error is raised and no action is taken: the corresponding MBean will simply not be mirrored in the master agent.

The most likely cause for registration to fail is that the object name already exists in the master agent. An MBean cannot be registered if its chosen object name already exists in the MBean server.

If your management solution has potential naming conflicts, you will need a design that is guaranteed to assign unique object names throughout the cascade hierarchy. You can set the default domain name in your subagents or use the MBeanServerId attribute of the delegate MBean to give MBeans a unique object name.

Running the Cascading Example

The examplesDir/Cascading directory contains all of the files for the two agent applications, along with a simple MBean.

To Run the Cascading Example
  1. Compile all files in this directory with the javac command. For example, on the Solaris platform with the Korn shell, you would type:


    $ cd examplesDir/Cascading/
    $ javac -classpath classpath *.java
    
  2. Start the subagent in another terminal window with the following command. Be sure that the classes for the SimpleStandard MBean can be found in its classpath.


    $ java -classpath classpath SubAgent
    
  3. Wait for the agent to be completely initialized, then start the master agent with the following command:


    $ java -classpath classpath MasterAgent
    

    When started, the master agent application first creates the CascadingAgent MBean and then sets up its connection to the subagent. The master agent then performs operations on the mirrored MBeans of the subagent. Press Enter to step through the example when the application pauses.

  4. You can also interact with the example through the HTML adaptor of the master agent and subagent. If you are still receiving timer notification on the master agent, press Enter once more to remove the listener, but leave both agent applications running.

How to Interact with a Cascade Hierarchy
  1. Open two browser windows side by side and load the following URLs:

    Subagent

    http://localhost:8082/

    Master Agent

    http://localhost:8084/

    In the subagent, you should see the timer MBean in the CascadedDomain and a SimpleStandard MBean in the DefaultDomain.

    The master agent is recognizable by the cascading service MBean in the DefaultDomain. Otherwise it has an identical timer MBean registered in the CascadedDomain: this is the mirror for the timer in the subagent. The SimpleStandard MBean is not mirrored because our cascading service instance filters with the following object name pattern:

    CascadedDomain:*

  2. Create four MBeans of the SimpleStandard class in following order:

    On the Master Agent: 

    CascadedDomain:name=SimpleStandard,number=1

    On the Subagent: 

    CascadedDomain:name=SimpleStandard,number=1

     

    CascadedDomain:name=SimpleStandard,number=2

     

    CascadedDomain:name=SimpleStandard,number=3

  3. Reload the agent view on the master agent.

    The mirror MBeans for the last two agents have been created automatically. Look at the MBean view of either of these mirror MBeans on the master agent. Their class name appears as SimpleStandard.

  4. In the master agent, set a new value for the State string attribute of all 3 of its SimpleStandard MBeans.

    When you look at the corresponding MBeans in the subagent, you see that number=2 and number=3 were updated by their mirror MBean. However, number=1 has not changed on the subagent. Because it was created first in the master agent, it is not mirrored and exists separately on each agent.

  5. In the subagent, invoke the reset operation of all 3 of its SimpleStandard MBeans.

    When you inspect the MBeans in the master agent, the values for number=2 and number=3 were reset. Remember that the HTML adaptor must get the values of attributes for displaying them, so they were correctly retrieved from the mirrored MBeans that we reset.

  6. In the master agent, unregister MBeans number=1 and number=2, then update the agent view of the subagent.

    In the subagent, you should still see the local version of number=1, but number=2 has been removed at the same time as its mirror MBean.

    We are in a state where number=1 is a valid MBean for mirroring but it is not currently mirrored. This incoherence results from the fact that we did not have unique object names throughout the cascading hierarchy. Only new MBeans are mirrored dynamically, following the notification that signals their creation. We would have to stop and restart the master agent's cascading service MBean to mirror number=1.

  7. In the subagent, unregister MBeans number=1 and number=3, then update the agent view on the master agent.

    The mirror MBean for number=3 was automatically removed by the cascading service, so none of the MBeans we added now remain.

  8. Invoke the stop operation of the CascadingAgent MBean in the master agent.

    The last mirror MBean for the timer is removed from the master agent. The two agents are no longer connected.

  9. If you have finished with the agents, press Enter in both of their terminal windows to exit the applications.