Java Dynamic Management Kit 4.0 Tutorial

The M-Let Loader (JDK 1.1)

In an agent application, we might need to load MBeans from remote hosts during the initialization. Or we might have local threads which need to load MBeans in the agent. In this example we demonstrate how to create the m-let loader service and use it to dynamically load new MBean classes.

In an installation of the Java Dynamic Management Kit for the JDK 1.1.x, the m-let loader is the MLetSrv class in the javax.management.loading package. It is an MBean which needs to be registered in the MBean server before we can use it to load classes.


Example 6-1 Instantiating the MLetSrv Class

MBeanServer server = MBeanServerFactory.createMBeanServer();

// Get the domain name from the MBeanServer.
String domain = server.getDefaultDomain();

// Create a new MLetSrv MBean and add it to the MBeanServer.
String mletClass = "javax.management.loading.MLetSrv";
ObjectName mletName = new ObjectName(domain + ":name=" + mletClass);
server.createMBean(mletClass, mletName);

There is no special initialization that needs to be done for the m-let loader.

Loading MBeans from a URL

In order to download an MBean, we must first have its corresponding m-let definition in an HTML file. In our example, we define the following file with three MLET tags:


Example 6-2 The M-Let File

<HTML>
<MLET
  CODE=Square.class
  ARCHIVE=Square.jar
  NAME=MLetExample:name=Square,id=1
>
<ARG TYPE=java.lang.Integer VALUE=10>
</MLET>
<MLET
  CODE=EquilateralTriangle.class
  ARCHIVE=EquilateralTriangle.jar
  NAME=MLetExample:name=EquilateralTriangle,id=1
>
<ARG TYPE=java.lang.Integer VALUE=8>
</MLET>
<MLET
  CODE=EquilateralTriangle.class
  ARCHIVE=EquilateralTriangle.jar
  NAME=MLetExample:name=EquilateralTriangle,id=2
>
<ARG TYPE=java.lang.Integer VALUE=15>
</MLET>
</HTML>

This file tells the m-let loader to create three MBeans with the given object names, using the given classes in the jar files. The ARG tag gives a parameter to be passed to the class' constructor. The number and type of ARG tags specified must match one of the public constructors for the class

The jar files must be located in the same directory as this file, regardless of whether the directory is on a local or remote host. The MLET tag may also specify a CODEBASE, which is an alternate location for the jar file. This m-let loader relies on the definition of MLET tag given by the JMX specification.

Now we are ready to call the performLoadURL method of our m-let loader. In parsing the result vector, we use our knowledge of the class names that we wrote in the m-let file.


Example 6-3 Calling the performLoadURL Method

ObjectName squareMLetClassLoader = null;
ObjectName triangleMLetClassLoader = null;

// The url string is read from the command line
Object mletParams[] = {url};
String mletSignature[] = {"java.lang.String"};
Vector mbeanList = (Vector) server.invoke(
    mletName, "performLoadURL", mletParams, mletSignature);

for (Enumeration enum = mbeanList.elements();
     enum.hasMoreElements(); ) {
    Object element = enum.nextElement();
    if (element instanceof Vector) {
        // Success, we retrieve the new object name
        Vector v = (Vector) element;
        ObjectInstance objectInstance = (ObjectInstance) v.elementAt(0);
        ObjectName classLoaderObjectName = (ObjectName) v.elementAt(1);
        if (objectInstance.getClassName().equals("Square")) {
            // Retrieve MBean that loaded the class Square
            squareMLetClassLoader = classLoaderObjectName;

        } else if (objectInstance.getClassName().equals(
                       "EquilateralTriangle")) {
            // Retrieve MBean that loaded the class EquilateralTriangle
            triangleMLetClassLoader = classLoaderObjectName;
        }
        println("\tOBJECT NAME = " + objectInstance.getObjectName());
    } else {
        // Failure, find out why
        println("\tEXCEPTION = " + ((Throwable)element).getMessage());
    }
}

The result of the call to performLoadURL is a Vector object containing as many elements as there are MLET tags in the file designated by the URL. Each element is either a vector containing the object instance of the new MBean and the object name of its class loader, or a Throwable object containing the exception or error that prevented the MBean from being loaded. The order of the elements may differ from the order of the tags in the file.

In the result, we obtain the object name of the MBeans that were created from the downloaded classes. The management architecture specified by JMX is designed so that objects are manipulated through the MBean server, not by direct reference. Therefore, downloaded classes are directly registered in the MBean server by the m-let loader, and the caller never receives a direct reference to the new object.

The object names of the class loaders are references to the internal class loader objects used by the m-let service to actually fetch the classes. We save them because they can be used if we ever need to instantiate these classes again. We will see how in the next section.

Shortcut for Loading MBeans

Loading MBeans from a URL requires some preparation and additional files. In some cases, we don't have the ability to create files ahead of time or modify them when we need different classes. In these cases, we would just like to load a class from a jar file and create its MBean.

The MLetSrv is not a class loader, we only ask it to load a class from a URL and it instantiates its private class loader for doing this. Even though the internal class loader object used by the m-let loader is a public type, it should not be instantiated to act as a class loader. The m-let loader stores internal information about its private class loaders, and it won't be able to handle one outside of its control.

Instead, use the class loader name that is returned when an MBean is successfully loaded. You can specify this class loader name when creating a class through the MBean server. You will be able to create new MBeans from the same class or from other classes in the associated archive (jar file).

This implies that you must first call the performLoadURL with a known URL and a known m-let file. The m-let loader will create one class loader for each code-base specified in the file, and one for the code-base of the file itself. For example, the class loader name returned with the "Square" MBean name is the one used to load its class from the Square.jar file in the same directory as the HTML file. We can create other instances of that MBean now just through the MBean server, without needing to call the m-let loader.

The following code sample uses the object name references that were declared and assigned in Example 6-3.


Example 6-4 Loading Classes Directly

// Create a new Square MBean from its class in the Square.jar file
String squareClass = "Square";
ObjectName squareName = new ObjectName(
    "MLetExample:name=" + squareClass + ",id=2");
Object squareParams[] = {new Integer(12)};
String squareSignature[] = {"java.lang.Integer"};
server.createMBean(squareClass, squareName, squareMLetClassLoader,
                   squareParams, squareSignature);

// Create a new EquilateralTriangle MBean from its class in the
// EquilateralTriangle.jar file
String triangleClass = "EquilateralTriangle";
ObjectName triangleName = new ObjectName(
    "MLetExample:name=" + triangleClass + ",id=3");
Object triangleParams[] = {new Integer(20)};
String triangleSignature[] = {"java.lang.Integer"};
server.createMBean(triangleClass, triangleName, triangleMLetClassLoader,
                   triangleParams, triangleSignature);

Running the M-Let Agent Example

To run the m-let agent example for the JDK 1.1.x, you must have installed the Java Dynamic Management Kit for 1.1, and set your classpath accordingly. This example is located in the examplesDir/MLetAgent/ directory, see "Directories and Classpath" in the preface for details.

In our example, we have two MBeans representing geometrical shapes. Before running the example, we compile them and create a jar file for each. We also compile the agent application at the same time.


$ cd examplesDir/MLetAgent/
$ javac -classpath classpath *.java

$ jar cf Square.jar Square.class SquareMBean.class
$ rm Square.class SquareMBean.class

$ jar cf EquilateralTriangle.jar EquilateralTriangle.class \
EquilateralTriangleMBean.class
$ rm EquilateralTriangle.class EquilateralTriangleMBean.class

Since the MBean classes are only found in the jar files now, they cannot be found in our usual classpath, even if it includes the current directory (.). However, these jar files are given as the archive in the MLET tags of the HTML file, so the m-let loader should find them.

The agent requires you to specify the URL of the m-let file on command line. We have left this file in the examples directory, but you could place it and the jar files on a remote machine. With the Korn shell on the Solaris platform, you would type the following command:


$ java -classpath classpath Agent file:${PWD}/GeometricShapes.html

In the output of the agent, you can see it create the m-let service MBean, and then load the HTML file which specifies the three MBeans to be loaded. Once these have been loaded, we can see the two MBeans that were loaded directly through the class loader shortcut.

This agent uses the tracing mechanism, and you can select to receive the messages from the m-let loader by specifying the -DINFO_MLET property on the command line. The tracing mechanism is covered in the Java Dynamic Management Kit 4.0 Tools Reference guide and in the Javadoc API of the Trace class.

The agent then launches an HTML adaptor so that we can easily view the new MBeans. In them we can see that the values contained in the ARG tags of the m-let file were used to initialize the MBeans. Point your web browser to the following URL and click on the MBeans in the MLetExample domain:http://localhost:8082/. When you are done, type "Control-C" in the window where you launched the agent.