Java Dynamic Management Kit 4.2 Tutorial

Standard MBean Proxies

A standard MBean proxy class is specific to its corresponding MBean class. Furthermore, a proxy instance is always bound to the same MBean instance, as determined by the object name passed to the proxy's constructor. Binding the proxy to its ProxyHandler object can be done through a constructor or set dynamically through the methods of the Proxy interface.

The methods of a standard proxy have exactly the same signature as those of the corresponding standard MBean. Their only task is to construct the complete management request, which necessarily includes the object name, and to transmit it to the MBean server or connector client. They also return any result directly to the caller.

Because the contents of all proxy methods are determined by the management interface of the MBean, the proxy classes can be generated automatically.

Generating Proxies for Standard MBeans

The proxygen tool provided with the Java Dynamic Management Kit takes the class files of an MBean and its MBean interface, and generates the Java source code files of its corresponding proxy object and proxy MBean interface. You then need to compile the two proxy files with the javac command and include the resulting class files in your application's classpath.

The proxygen command is fully documented in the Java Dynamic Management Kit 4.2 Tools Reference guide, and in the Javadoc API for the ProxyGen class. Its command line options allow you to generate read-only proxies where all setter methods are suppressed and to define a package name for your proxies. For the purpose of the examples, we generate the default proxies without any of these options: see the section on "Running the Standard Proxy Example".

The following code sample shows part of the code generated for the SimpleStandard MBean used in the SimpleClients examples.


Example 9-1 Code Generated for the SimpleStandardProxy Class

  public java.lang.String getState()
    throws InstanceNotFoundException, AttributeNotFoundException,
    ReflectionException, MBeanException {

      return ((java.lang.String)server.getAttribute(
                  objectInstance.getObjectName(), "State"));
    }

  public  void setState(java.lang.String value)
    throws InstanceNotFoundException, ReflectionException,
    AttributeNotFoundException,InvalidAttributeValueException,
    MBeanException {

      server.setAttribute(objectInstance.getObjectName(),
                          new Attribute("State",value));
  }

  public void reset()
    throws InstanceNotFoundException, ReflectionException,
    MBeanException {

    Object result;
    result= server.invoke(objectInstance.getObjectName(), "reset",
                          null, null);
  }

You are free to modify the generated code if you wish to customize the behavior of your proxies. However, customization is not recommended if your MBean interfaces are still evolving, because all modifications will need to be redone every time the proxies are generated.

Using Standard MBean Proxies

Once the proxies are generated and available in your application's classpath, their usage is straightforward. For each of the proxy objects it wishes to use, the application needs to instantiate its proxy class and then bind it to a ProxyHandler object. The application is responsible for creating and binding all of the proxies that it wishes to use, and it must unbind and free them when they are no longer needed.


Note -

In previous versions of the Java Dynamic Management Kit, the connector client handled the creation of proxy instances and insured that only one proxy object could exist for each MBean. As of this version (4.2) of the product, connector clients no longer instantiate nor control proxy objects. The corresponding methods of the RemoteMBeanServer interface are now deprecated.

Similarly, the previous binding methods in the Proxy interface are deprecated in favor of the new setServer and getServer methods. This change is necessary so that proxies may be bound to any ProxyHandler object, to allow for both local and remote proxies.


All parameters for binding the proxy can be given in its constructor, which makes it very simple to instantiate and bind a proxy in one step.


Example 9-2 Instantiating and Binding a Proxy In One Step

String mbeanName = "SimpleStandard";

// build the MBean ObjectName instance
ObjectName mbeanObjectName = null;
String domain = connectorClient.getDefaultDomain();
mbeanObjectName = new ObjectName( domain + ":type=" + mbeanName );

// create the MBean in the MBeanServer of the agent
String mbeanClassName = mbeanName;
ObjectInstance mbeanObjectInstance =
    connectorClient.createMBean( mbeanClassName, mbeanObjectName );

// create and bind a proxy MBean on the client side
// that corresponds to the MBean just created in the agent
Proxy mbeanProxy = new SimpleStandardProxy(
                           mbeanObjectInstance, connectorClient );

echo("\tPROXY CLASS NAME  = " +
      mbeanProxy.getClass().getName() );
echo("\tMBEAN OBJECT NAME = " +
      mbeanProxy.getMBeanObjectInstance().getObjectName() );
echo("\tCONNECTOR CLIENT  = " +
      mbeanProxy.getServer().getClass().getName() );

If the class name of your proxy is not known at compile time, you will have to instantiate its class dynamically. In the following code, we obtain the proxy class name which corresponds to an MBean, and we call its first constructor. This must be the constructor which takes an ObjectInstance identifying the MBean, and we must dynamically build the call to this constructor. We then call the setServer method to bind the new proxy instance.


Example 9-3 Instantiating and Binding a Proxy Class Dynamically

// Get the class name of the MBean's proxy
Class proxyClass = Class.forName(
    connectorClient.getClassForProxyMBean( mbeanObjectInstance ));

// Find the constructor with takes an ObjectInstance parameter
Class[] signature = new Class[1];
signature[0] = Class.forName("javax.management.ObjectInstance");
Constructor proxyConstr = proxyClass.getConstructor( signature );

// Call the constructor to instantiate the proxy object
Object[] initargs = new Object[1];
initargs[0] = mbeanObjectInstance;
Proxy proxy2 = (Proxy) proxyConstr.newInstance( initargs );

// Bind the proxy
proxy2.setServer( connectorClient );

echo("\tPROXY CLASS NAME  = " +
      proxy2.getClass().getName());
echo("\tMBEAN OBJECT NAME = " +
      proxy2.getMBeanObjectInstance().getObjectName());
echo("\tCONNECTOR CLIENT  = " +
      proxy2.getServer().getClass().getName());

// We no longer need proxy2, so we unbind it
proxy2.setServer( null );

Once a proxy is bound, you can access the attributes and operations of its MBean through direct calls to the proxy object, as shown in the following example.


Example 9-4 Accessing a Standard MBean Through Its Proxy

try {
    // cast mbeanProxy to SimpleStandardProxy, so we can
    // call its MBean specific methods
    SimpleStandardProxy simpleStandardProxy =
        (SimpleStandardProxy) mbeanProxy;

    [...]

    // Change the "State" attribute
    simpleStandardProxy.setState("new state from client");

    // Get and display the new attribute values
    echo("\tState     = \"" + simpleStandardProxy.getState() + "\"");
    echo("\tNbChanges = " + simpleStandardProxy.getNbChanges());

    // Invoke the "reset" operation
    simpleStandardProxy.reset();
    [...]

    // We are done with the MBean, so we
    // unbind the proxy and unregister the MBean
    simpleStandardProxy.setServer( null );
    connectorClient.unregisterMBean( mbeanObjectName );

} catch (Exception e) {
    echo("\t!!! Error accessing proxy for " + 
          mbeanProxy.getMBeanObjectInstance().getObjectName() );
    e.printStackTrace();
}

Running the Standard Proxy Example

The examplesDir/SimpleClients directory contains all of the files for the ClientMBeanProxy application which demonstrates the use of standard MBean proxies.

If you haven't done so already, 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/SimpleClients/
$ javac -classpath classpath *.java

Before running the example, you must also generate the proxy MBeans classes and compile them as well. From the same directory as above, type the following commands:


$ installDir/SUNWjdmk/jdmk4.2/JDKversion/proxygen SimpleStandard
$ javac -classpath classpath SimpleStandardProxy.java
Instructions
  1. Launch the base agent in a terminal window with the following command:


    $ java -classpath classpath BaseAgent
    

    The agent creates the RMI connector server to which the client application will establish a connection, and then it waits for management operations.

  2. Wait for the agent to be completely initialized, then, in another window on the same host, launch the management application with the following command:


    $ java -classpath classpath ClientMBeanProxy
    
  3. Press <Enter> in the manager window to step through the example.

    As seen in the code examples, the client application instantiates the proxy objects to access the MBean it has created in the base agent.

  4. Press <Enter> one last time to exit the manager application, but leave the base agent running for the next example.