Chapter 8. Dynamic Loading

In this chapter, we will discuss a facility provided by JMX that allows MBeans to be loaded into an agent dynamically. This facility, called the M-Let (short for management applet) service, is the first agent-level service we have discussed so far. There are two major sections in this chapter. The first section is an overview of the M-Let service, including the various facets of it that make it work. The second section deals with the details of the M-Let service and provides examples of code that executes in the JMX agent that uses the M-Let service.

Overview

In this section, we will look at the M-Let service, whose purpose is to provide an agent with a means to load MBeans from a Universal Resource Locator (URL). There are two ways that an agent can use the M-Let service to accomplish this. First, the agent can specify an M-Let file to the M-Let service, which uses the contents of this file to load the MBeans. The M-Let file is an XML-like text file that contains various tags that describe the MBeans to be loaded. The second method of loading MBeans is to use the M-Let service itself to load the MBeans without the use of an M-Let file. The M-Let service extends URLClassLoader from the java.net package and is thus capable of fetching bytecode from any valid URL into the JVM in which the agent is running.

The M-Let Service

In the RI, the M-Let service is implemented in a class called MLet, which implements an interface called MLetMBean (so it is instrumented as a standard MBean). The MLetMBean interface allows agents (and management applications) to manipulate the M-Let service to load MBeans and to manage the M-Let service itself. The MLetMBean interface is defined as:

public interface MLetMBean {
  public Set getMBeansFromURL(String url) throws ServiceNotFoundException;
  public Set getMBeansFromURL(URL url) throws ServiceNotFoundException;
  public void addURL(URL url);
  public void addURL(String url) throws ServiceNotFoundException;
  public URL[] getURLs(  );
  public URL getResource(String name);
  public InputStream getResourceAsStream(String name);
  public  Enumeration getResources(String name) throws IOException;
  public String getLibraryDirectory(  );
  public void setLibraryDirectory(String libdir);
}

In this section, we will discuss only those methods that are part of the MLetMBean interface. Primary emphasis will be placed on those methods that are mentioned in the specification, with secondary emphasis placed on the others.

There are two methods of primary concern when using the M-Let service: getMBeansFromURL( ) and addURL( ) . The getMBeansFromURL( ) method has two versions: the first takes a String that contains the URL of the text file that describes the MBeans to load, and the second takes a URL object that contains the URL of the M-Let file. The addURL( ) method is used to add a URL to the list of URLs that are to be searched when loading MBeans while using the M-Let service as the class loader. These two methods are the ones you will use when writing agents that use dynamic loading as a part of your MBean deployment strategy.

The other methods on the MLetMBean interface provide functionality that you would expect to see in a class loader. For example, the getURLs( ) method returns an array of the URL objects that are searched when loading classes and resources, and the getResourceAsStream( ) method takes a String containing the name of a resource and returns an InputStream object so the resource can be read.

The M-Let service must be created and registered with the MBean server before you can use it. The examples that follow assume that a reference to the MBean server has been obtained (we saw how to do this in earlier chapters) and that the M-Let service is created by simply using the Java new keyword on the RI class MLet. The MLet class implements the MBeanRegistration interface, so it is capable of creating its own object name. In the examples that follow, we will allow it to do so.

The M-Let File

The M-Let file is a text file that looks like XML but is not required to be well-formed XML. Each of the components of the M-Let file is called a tag (even though the “tag” may resemble an XML attribute; remember, it’s not well-formed XML) The JMX specification defines several tags that are used in the M-Let file, which we will look at in this section. The format of the M-Let file is:

<MLET
  CODE="className" | OBJECT="serializedObjectFileName"
  ARCHIVE="classOrJarFileName"
  [CODEBASE="relativePathToArchive"]
  [NAME="mbeanObjectName"]
  [VERSION="version"]
>
[<ARG TYPE="type" VALUE="value">]
</MLET>
.
.
.

There is one MLET tag for each MBean to be loaded. For example, if there were five MBeans to load, there would be five MLET tags in the M-Let file. Each MBean specified in the M-Let file is required to provide either the full string representation of its class name (by using the CODE tag) or the name of a file that contains the MBean’s serialized state (by using the OBJECT tag). The CODE and OBJECT tags are mutually exclusive (i.e., for any given MBean, one or the other may be specified, but not both). In addition, the name of the JAR file in which the bytecode is archived must be specified. The other tags are not required. Let’s look at each of these tags in detail.

MLET

As we mentioned, each MBean to be loaded by the M-Let service must have its own MLET tag in the M-Let file. It’s as simple as that.

CODE

The value of this tag is designated by className in the example above and must be the string representation of the MBean’s class name. For example, suppose the MBean’s class name is sample.mlet_loadable.Queue. The CODE tag would then look like:

CODE="sample.mlet_loadable.Queue"

If we had simply specified "Queue" as the CODE value, the M-Let service would not be able to locate the bytecode for our MBean class. As you might expect, the M-Let service must be able to locate this class relative to one of the URLs that it is using as its search path. We will see how to set this URL later.

OBJECT

The value of this tag is designated by serializedObjectFileName in the example above and is the name of the file that contains the MBean’s serialized state. Suppose that we serialized the state of the Queue class in a file named Queue.ser. We would then instruct the M-Let service to load the MBean from that file:

OBJECT="Queue.ser"

Of course, the M-Let service must be able to locate this file relative to one of the URLs that it is using as its search path.

ARCHIVE

The value of this tag is designated by classOrJarFileName in the example above and is the names of one or more JAR files, one of which contains the .class file for the MBean. Suppose the JAR that contains the Queue class is called mlet_loadable.jar. In this case, the ARCHIVE tag would look like:

ARCHIVE="mlet_loadable.jar"

Multiple JAR files are separated by commas:

ARCHIVE="mlet_loadable.jar,another.jar,yetanother.jar"

The M-Let service will search the URLs that constitute its search path for all of the JAR files that are specified by the ARCHIVE tag. At least one of the JAR files must contain the bytecode for the MBean.

CODEBASE (optional)

The value of this tag is designated by relativePathToArchive in the example above and is the relative path to the JAR file specified by the ARCHIVE tag. But relative to what? The M-Let service uses the URL of the M-Let file as the default URL (minus the M-Let filename, of course) to the JAR file specified by ARCHIVE. If no CODEBASE tag is specified, the default URL is used as the code base from which to load the bytecode for the MBean. This is useful when the JAR file is located in the same directory as the M-Let file.

Suppose that the URL to the M-Let file is http://myserver/mbeans/mbeans.txt. The default URL in this case is http://myserver/mbeans. Now suppose that we specify the value of the ARCHIVE tag to be mlet_loadable.jar, located at http://myserver/mbeans/jars, and we do not provide a CODEBASE tag. The M-Let service will use the default as the base URL for locating mlet_loadable.jar. It will try to load http://myserver/mbeans/mlet_loadable.jar, but it will not be able to find it.

However, if we specify a CODEBASE value relative to the default URL:

CODEBASE="jars"

the M-Let service will add the CODEBASE value to the default URL, resulting in http://myserver/mbeans/jars/mlet_loadable.jar, and the JAR file will be located. Because the CODEBASE value is added to the default URL, specifying:

CODEBASE="."

and omitting the CODEBASE tag altogether have the same effect. As you might expect, you can use "." and ".." to represent the current directory and parent directory, respectively. Suppose that instead of mlet_loadble.jar being subordinate to the M-Let file, the two files are located in peer directories, with mlet_loadable.jar being located at http://myserver/jars. In this case, the CODEBASE tag would have to be specified as:

CODEBASE="../jars"

NAME (optional)

The value of this tag is designated by mbeanObjectName in the example above and is the string representation of the object name for the MBean. Suppose the object name string for the Queue class is ":name=Queue,loadedFrom=MLET", where the domain is the default domain. The NAME tag could then be specified as:

NAME=":name=Queue,loadedFrom=MLET"

When the Queue MBean is loaded by the M-Let service, it will be given this object name. If the object name already exists, the MBean will not be loaded and an exception will be returned to the agent that is using the M-Let service.

If this tag is omitted, the M-Let service assumes that the MBean implements the MBeanRegistration interface and will provide its own object name.

VERSION (optional)

The value of this tag is designated by version in the example above and represents the version of the JAR file specified by ARCHIVE and/or the MBean to be loaded. The primary purpose of this tag is to support versioning and caching in the implementation. The format of this tag is one or more nonnegative integers separated by a dot (.):

VERSION="1.0.1"

Note that the JMX 1.0 RI does not support this tag. Support for the VERSION tag will most likely be present in a future release of the JMX RI.

ARG

This tag represents an argument that is to be passed to the constructor of the MBean when it is loaded and instantiated. The tags that accompany this tag are TYPE and VALUE, which represent the argument’s data type and its value, respectively. Only fundamental types (boolean, byte, char, short, int, long, float, and double), java.lang fundamental wrapper types (Boolean, Byte, Char, Short, Int, Long, Float, Double, and String) are supported, as they may all have a string representation (unlike complex user-defined types). The ARG tag must follow the closing > of the MLET tag.

Using the Queue class, which has an alternate constructor that takes a single int to set the queue depth, we can specify a single ARG tag to set the queue depth to seven items:

<ARG TYPE="int" VALUE="7">

Multiple arguments to the MBean constructor may be specified. The order of the arguments in the M-Let file must correspond to the order of the arguments to the constructor. Suppose that a constructor takes a String, a float, and an Integer, in that order. The ARG tags must also be supplied in that order:

<ARG TYPE="java.lang.String" VALUE="Hello, world">
<ARG TYPE="float" VALUE="3.14159">
<ARG TYPE="java.lang.Integer" VALUE="104">

Notice that the JDK wrapper classes String and Integer must be fully qualified. If we had written the ARG tags as:

<ARG TYPE="String" VALUE="Hello, world">
<ARG TYPE="float" VALUE="3.14159">
<ARG TYPE="Integer" VALUE="104">

the MBean would not be loaded, because the M-Let service cannot fetch the bytecode for the String and Integer parameters. However, fundamental types simply require the name of the type, as that is the name of the Class object that represents fundamental type inside the JVM.

Bringing it all together

Now that we’re familiar with the tags that can be used in the M-Let file, let’s look at a simple example. Suppose that we want to load the sample.mlet_loadable.Queue MBean from mlet_loadable.jar, giving it the name ":name=Queue,loadedFrom=MLET" and passing an int argument value of 8 to its constructor:

<MLET
  CODE="sample.mlet_loadable.Queue"
  ARCHIVE="mlet_loadable.jar"
  NAME=":name=Queue,loadedFrom=MLET"
>
<ARG TYPE="int" VALUE="8">
</MLET>

We will see later exactly how to use the M-Let file, the URL describing its location, and the getMBeansFromURL( ) method of the MLetMBean interface to load the MBeans.

What about comments in the M-Let file? The specification does not mention them, so it’s not a good idea to expect support for comments to be in every implementation of JMX. However, in the JMX 1.0 RI, the parser that reads the M-Let file allows for any text to be placed in the file as long as it is outside of a “< . . . >” construct. In other words, no text other than the tags we have discussed is allowed anywhere inside the <MLET . . . > tag, the </MLET> closing tag, or the <ARG . . . > tag. You can place whatever text you like outside of those tags. For example:

                  This text will be ignored by the parser
<MLET
  Oops, text cannot go here!
  CODE="sample.mlet_loadable.Queue"
  ARCHIVE="mlet_loadable.jar"
  NAME=":name=Queue,loadedFrom=MLET"
> This text is ignored
                  This text is ignored
<ARG TYPE="int" VALUE="8">
</MLET>

The line of text following the MLET opening tag will cause the parser to report an error with the M-Let file. All of the other text will be ignored by the parser.

Loading MBeans Without an M-Let File

As mentioned earlier, the MLet class, which is the RI’s implementation of the M-Let service, is a class loader capable of fetching bytecode from a URL and creating a Class object for an MBean. We have already looked at how the M-Let service uses its class loader functionality in conjunction with an M-Let file to load MBeans. In this section, we will see how to use the M-Let service to load MBeans without the use of an M-Let file.

The MLetMBean interface—implemented by the MLet class—provides a method that allows an agent to add one or more URLs that the M-Let service will search when loading MBeans. This method, addURL( ), works in conjunction with the MBean server methods instantiate( ) and createMBean( ) to load MBeans from a URL. instantiate( ) and createMBean( ) each have two versions that take as a parameter the object name of the loader to be used when fetching the bytecode for the MBean to be loaded. Once the URL of the JAR file containing the MBean(s) to be loaded has been added to the M-Let service’s search list of URLs, either instantiate( ) or createMBean( ) can be called to load the MBean. We will see how to do this later in this chapter.

If the MBean to be loaded exists in the same code base (i.e., one or more JAR files, specified by a URL) as any other MBean that has been loaded using an M-Let file, you do not need to specify the URL. In other words, the M-Let service remembers any URL from which it has previously loaded a class. This functionality is typical of all class loaders. We will look at an example of this later in this chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset