One feature I use very often in JConsole is the "MBeans" tab for displaying manageable and monitorable attributes, operations, and notifications related to my custom MBeans. While this tab does not exist in VisualVM when it is first run from the command-line in Java SE 6, it is trivial to add the MBeans plugin to get behavior very similar to that provided in JConsole.

To run VisualVM provided with the JDK distribution, use the command jvisualvm from the command prompt. This is demonstrated in the following screen snapshot:

When first started up, VisualVM does not have an MBeans tab like that used in JConsole. However, one can easily add the MBeans plugin by selecting Tools->Plugins from VisualVM. The following screen snapshots show how to do this.

This first screen snapshot shows selection of Tools->Plugins.

The next screen snapshot shows the MBean tab selection from among the available VisualVM plugins.

The next screen snapshot demonstrates what the MBeans tab looks like in VisualVM.

The MBeans tab in VisualVM is very familiar to anyone who has used the MBeans tab in JConsole.

Another useful JConsole feature is the ability to add custom tabs to JConsole. While the VisualVM JConsole Plug-in Wrapper Tab document recommends using VisualVM's own customizability features when developing new support for VisualVM, it can be handy to use existing JConsole plug-ins with VisualVM. The just-referenced document VisualVM JConsole Plug-in Wrapper Tab does a nice job of covering how to use a custom JConsole plug-in tab in VisualVM. That example uses the JDK-provided JTop custom plugin for the example.

The three screen snapshots that follow show how easy it is to install the JConsole plugins tab wrapper in VisualVM and to select a JConsole plugin for use in VisualVM. The final image shows how one JConsole plugin, the JTop plugin provided with the SDK, appears in VisualVM.

This first image shows the details related to the JConsole plugin tab wrapper.

The next image shows selection of a particular JConsole tab plugin once the wrapper plug-in for VisualVM has been installed.

This final image demonstrates what the JTop JConsole tab looks like in VisualVM via VisualVM's JConsole plug-in tab wrapper.

For individuals and organizations with large investments in JConsole custom tabs, the VisualVM wrapper plug-in allows those plug-ins to be leveraged in VirtualVM without massive re-writes. For those who appreciate JConsole as an easy-to-use client of custom JMX applications, VisualVM can provide similar capabilities via its MBeans plugin. Besides providing many of the advantages of JConsole via plug-ins and out-of-the-box support, VisualVM provides graphical representation of the monitoring data provided by many tools other than JConsole. With the JConsole-friendly plug-ins mentioned in this blog entry in use, VisualVM is able to combine the strengths of JConsole with the value found in other Sun JDK-provided management and monitoring tools.

Because the Eastwood Chart Servlet implements the most of the APIs of Google Charts, my example will be able, in most cases, to call either charting provider based on user selection. There are some extensions in Eastwood beyond the Google Chart API and the Google Chart API has some features still not implemented in Eastwood, but most of the common functionality is commonly implemented in both charting providers.

While URLs constructed to request chart generation from Google Charts and Eastwood Charts are almost always the same (because Eastwood is implemented to the Google Charts API), there are differences between the two implementations of these APIs. Using Google Charts is really easy because no work needs to be done on the server-side. All the developer needs to do is construct the appropriate URL conforming to the Google Charts API and invoke that to get the returned image. With Eastwood Charts, the developer needs to install the Eastwood-provided WAR file on his or her favorite Java EE container. It is important to note that this is all that must be done. The WAR files does not need to be tweaked or manually unzipped, but simply needs to be deployed by dropping it in the appropriate container directory or else through the server's administration tool.

The Eastwood Developer Manual that is included with the Eastwood download contains a list of several bullets outlining some advantages of the Eastwood Charts implementation of the Google Charts API. Most of these advantages stem ability to run the charting server on one's own network. Advantages of running the charting provider on one's own machine is include the ability to keep potentially sensitive data within one's own environment and the ability to run the chart generation in environments in which Internet connectivity is not available.

The following MXML code is a simple but complete example that accesses both Google Charts and Eastwood Charts via the same URL. I intentionally included 3D bar chart examples to demonstrate an extension provided by Eastwood Charts, but not by the Google Charts. While I don't show it here, Google Charts similarly provide some features not currently supported in Eastwood Charts (such as Maps).

Here is the source code for the Flex application taking advantage of both Google Charts and Eastwood Charts:

The above example provides a radio button group for the user to select which chart provider (Google Charts or Eastwood Charts) should be used. Another radio button group allows the user to select which chart type should be generated. The text fields allow for dynamic data values to be supplied that are used in the chart generation. The sample code takes these input values, the user's selection for chart type, and the user's selection for chart provider and builds a URL from these data points that meets the Google Charts API.

The following screen snapshots show charts generated from both Google Charts and Eastwood Charts (click on the images to see larger versions).

Eastwood Charts-Generated 3D Pie Chart

Google Charts-Generated 3D Pie Chart

Eastwood Charts-Generated Vertical Bar Chart

Google Charts-Generated Vertical Bar Chart

As you can see in the screen snapshots, there are some slight differences in the implementations of Eastwood Charts and Google Charts. However, they are remarkably similar and it is pretty convenient to be able to have the same code call either implementation to generate these charts. There are many more types of charts available than those shown in this example. Examples of these types of charts can be found in the Google Charts API page and in the Eastwood Chart Servlet samples page.

Saturday, August 23, 2008

One of the things that was most difficult for me to learn when first learning about Remote JMX was the difference between a JMX Connector and a JMX Adapter (also spelled Adaptor in many cases). Part of this confusion was a result from trying to understand the difference based on books written before the Remote JMX specification was written or finalized. Another part of the confusion is in the actual names. In this blog entry, I'll point to a few references and resources that I think best explain the JMX Connector and the JMX Adapter and then I'll go through some source code examples because I believe that using these in practice makes them easier to understand than simply reading the words.

The JMX 1.4 specification includes both "regular" JMX and remote JMX in a single, consolidated specification. Part III of this consolidated JMX specification is focused on Remote JMX and is called "JMX Remote API Specification." The first chapter in this Part III, Chapter 13, covers JMX Connectors in general and is followed by Chapter 14 focusing on the RMI-based JMX Connector and Chapter 15 focusing on the Generic Connector.

I think two sentences in Chapter 13 of the JMX 1.4 specification are particularly important to understanding JMX connectors:

1. "The client end of a connector exports essentially the same interface as theMBean server."

2. "A connector consists of a connector client and a connector server."

Section 5.3 of the JMX 1.4 specification is called "Protocol Adaptors and Connectors" and covers basics of both adapters and connectors. Related to JMX connectors, this section makes the important observation that "A connector is specific to a given protocol, but the management application can use any connector indifferently because they have the same remote interface."

1. "Protocol adaptors provide a management view of the JMX agent through a given protocol. They adapt the operations of MBeans and the MBean server into a representation in the given protocol, and possibly into a different informationmodel."

2. "Management applications that connect to a protocol adaptor are usually specific to the given protocol."

With the key characteristics of JMX connectors and protocol adaptors highlighted above, there are some quickly identifiable differences between the two. These differences may be most succinctly summarized in Daniel Fuchs's blog entry What is JMX?, where he states that JMX Protocol Connectors represent the MBeans to the remote client the same way they would be represented to a local client and that a JMX Protocol Adaptor adapts the server-side model to what the client expects.

JMX Protocol Connectors and JMX Protocol Adaptors both typically work with a single protocol. The difference between the two is that Adaptors massage the management interface for the client's benefit while the Connectors provide a protocol-independent API that is essentially the same as the local API.

The JMX Reference Implementation (the implementation of JMX included in Sun's Java SE 6 distribution) provides the one Connector required of the specification: the Remote Method Invocation (RMI) Connector. The JMX 1.4 specification only requires a JMX implementation to provide an RMI-based Connector, but the specification outlines an optional JMXMP-based Connector. For this example, I use the JMXMP (JMX Message Protocol) Connector provided by OpenDMK. The third JMX Connector used in this example is the JSR-262JMX Web Services Connector.

I now delve into some code samples to illustrate JMX Connectors versus JMX Adaptors. For simplicity, I have a single class that runs three types of JMX Connector Servers and also runs an Adapter Agent. This class is called JmxServerMain and its main() method is listed here first.

I will show the implementations of the methods called above later in this entry, but even this high-level look reveals clear and easily identifiable differences between Connectors and Adapters. Note that all three JMX Connectors can be treated the same and can take advantage of the same method. In other words, all three Connectors can be set up using the useJmxServiceUrlBasedConnector method. The Adapter, on the other hand, can not take advantage of the same method as the Connectors and must be set up with its own useHtmlAdaptor method. Note that this method name, useHtmlAdaptor, is specific to the adaptor involved.

The definition of the useJmxServiceUrlBasedConnector method is shown next.

The useJmxServiceUrlBasedConnector method shown above is generic and supports all types of specification-compliant JMX connectors provided to it. In fact, the only thing that differentiates one type of connector from another is the protocol embedded within the string that forms the JMXServiceURL. For connector management purposes, it is a recommended practice to register connectors themselves as MBeans and that is also done in this code.

We have now seen that the same generic code can be used to set up all the Connectors for Remote JMX access. In the example above, the RMI, JMXMP, and JMX Web Services Connector are all used this way. The next code listing shows the code for the useHtmlAdaptor method, which is also part of the JmxServerMain class.

JmxServerMain.java useHtmlAdaptor Method

/** * Provide server-side functionality for HTML Adaptor to be used by client * web page. * * @param htmlAdaptorPort Port on which web browser will see this. * @param adaptorMBeanName Name of MBean by which adaptor will be registered. * @return Handle to the HTML Adaptor that can be stopped when finished. */public static HtmlAdaptorServer useHtmlAdaptor( final int htmlAdaptorPort, final String adaptorMBeanName){ final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); final HtmlAdaptorServer htmlAdaptor = new HtmlAdaptorServer(htmlAdaptorPort);

All three JMX Connectors (RMI, JMXMP, and WS-JMX) can be connected to by JConsole or by any other standard JMX client. I'll first show the code for accessing these three connectors from a simple client.

The simple client whose code is shown above allows the user to specify which protocol connector to use (RMI, JMXMP, JMXWS) as a command-line argument and RMI is used if none is specified. What this simple client demonstrates is that the JMX Connector Servers are accessed in the identical manner regardless of the underlying protocol. Only the JMXServiceURL needs to be different.

The three JMX Connector Servers can also be accessed from JConsole. As with the simple client, the only thing that needs to be different is the JMXServiceURL provided to JConsole in the remote field.

The HTML Adaptor is not accessed via the simple client shown above or via JConsole. Rather, as an HTML adapter, it has adapted the model for HTML presentation and one accesses its exposed management interfaces via web browser with URL of http://localhost:1096 (1096 in this example because we established this as the port for the HtmlAdaptorServer).

I am not going to show the simple client output, the JConsole output, or the HTML web page output here, because they are nothing different from what one would see using these tools for other JMX uses. For convenience, I am including the entire JmxServerMain class next. I included significant portions of it above, but this listing includes the entire class with all of its convenience methods.

/** * Register an example MBean with the Platform MBean server to be looked up * by clients connected via a connector or adapter. Note that this is not * absolutely necessary in Java SE 6, but it is interesting. * * @param nameForMBean Name for MBean to be registered with MBeanServer. */ public static void registerExampleMBean( final String nameForMBean ) { registerProvidedMBean(new ApplicationState(), nameForMBean); }

/** * Provide server-side functionality for HTML Adaptor to be used by client * web page. * * @param htmlAdaptorPort Port on which web browser will see this. * @param adaptorMBeanName Name of MBean by which adaptor will be registered. * @return Handle to the HTML Adaptor that can be stopped when finished. */ public static HtmlAdaptorServer useHtmlAdaptor( final int htmlAdaptorPort, final String adaptorMBeanName) { final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); final HtmlAdaptorServer htmlAdaptor = new HtmlAdaptorServer(htmlAdaptorPort);

Because the RMI connector is included with the Reference Implementation of JMX that is included with Java SE 6, I did not need to explicitly include anything on the classpath to use it. However, to use the JSR-262 WS-JMX and to use OpenDMK for both the HTMLAdaptor and for the JMXMP Connector, I did need to add relevant JARs to the classpaths.

I ran JmxServerMain as follows (thankfully, Java SE 6 supports wildcards for including JAR files in the classpath or else the WS-JMX entries would be numerous):

If you don't include the appropriate JAR files for WS-JMX or for OpenDMK's JMXMP Connector, you will see errors like those shown in the following two images ("Unsupported protocol: jmxmp" and "Unsupported protocol: ws"):

Failure to Include OpenDMK JARs on ClassPath

Failure to Include JSR-262 JARs on ClassPath

Failure to include the OpenDMK JARs for HTMLAdaptor will be revealed at compile time instead of runtime because of the direct instantiation of the HtmlAdaptorServer class described above. Of course, the runtime classpath will need them as well, but failure to do that is marked by the well-known NoClassDefFoundError.

In this blog entry, I've attempted to demonstrate key differences between JMX Protocol Adaptors and JMX Protocol Connectors. In general, I prefer Connectors because of the standardized approach that can be used to work with them both on the Connector Client and Connector Server side. I also generally like having the same interface both locally and remotely. However, there are times when adapters have their advantages. For example, it is nice not to have to include OpenDMK or WS-JMX libraries on the client machine when using a web browser with the HTML Adaptor. Perhaps at least partially for this reason (simplicity on the client side), early JMX books often favored the HTML Adaptor as the view into managed applications. The fact that JConsole was not yet available probably had something to do with the prevalent use of HTML Adaptor as well. With JConsole, VisualVM, and the ability to easily write JMX Connector Clients, I find myself generally favoring Connectors over Adaptors unless there is something specific about the client format (such as HTML or SNMP) that is required.

However, as discussed in my blog entry The JMX Model MBean, there are some disadvantages of Standard MBeans (and MXBeans) that Model MBeans can address. The most significant reason for using the Model MBean (to wrap existing non-JMX resources such as employed in the Spring Framework) is not possible with Standard or MXBeans due to their static nature. However, the advantage of being able to provide information on operations, parameters, constructors, attributes, and notifications is not a sole advantage of Model MBeans or even of the class of dynamic MBeans. I will demonstrate in this blog entry one approach to specifying operation metadata for Standard MBeans and MXBeans that can be displayed in JConsole and other clients that know how to handle MBeanInfo.

The key to providing additional metadata above and beyond what is normally associated with a Standard MBean is use of the class javax.management.StandardMBean. The description portion of this class's Javadoc documentation shows two ways to use this class. They are using StandardMBean's public constructors or by having the MBean implementation class extend the StandardMBean class (but still implement the same interface). Using the StandardMBean class allows the naming conventions normally associated with Standard MBeans to be relaxed because arbitrary implementation classes and interfaces can be associated with this class. However, in this blog entry, I will keep the normal implementation/interface naming conventions and use the class StandardMBean to provide metadata to the Standard MBean and MXBean.

My first code listing shows a class called DustinMBean that extends StandardMBean so that I can override the StandardMBean.cacheMBeanInfo method.

/** * Provides the type of operation last executed against this calculator class. * * @return Type of operation last executed against this calculator. */ public OperationType whatWasTheLastOperation();}

SimpleCalculator.java (Standard MBean Implementation)

package dustin.jmx;

/** * Simple calculator class intended to demonstrate how a class with no knowledge * of JMX or management can be used as a Standard MBean. * * @author Dustin */public class SimpleCalculator implements SimpleCalculatorMBean{ private OperationType lastOperation = OperationType.NO_OPERATIONS_INVOKED;

/** * Provides the type of operation last executed against this calculator class. * * @return Type of operation last executed against this calculator. */ public OperationType whatWasTheLastOperation() { return this.lastOperation; }}

The two code listings immediately above are the interface and implementation for the Standard MBean. The next two listings are for the interface and implementation for a very similar MXBean. The MXBean is not really any more complicated than the Standard MBean, but I needed to name it something different.

LessSimpleCalculatorMXBean.java (MXBean Interface)

package dustin.jmx;

/** * Interface for a standard MXBean example using the Simple Calculator. * * @author Dustin */public interface LessSimpleCalculatorMXBean{ /** * Calculate the sum of the augend and the addend. * * @param augend First integer to be added. * @param addend Second integer to be added. * @return Sum of augend and addend. */ public int add(final int augend, final int addend);

/** * Provides the type of operation last executed against this calculator class. * * @return Type of operation last executed against this calculator. */ public OperationType whatWasTheLastOperation();}

LessSimpleCalculator.java (MXBean Implementation)

package dustin.jmx;

/** * Simple calculator class intended to demonstrate how a class with no knowledge * of JMX or management can be used as an MXBean. * * @author Dustin */public class LessSimpleCalculator implements LessSimpleCalculatorMXBean{ private OperationType lastOperation = OperationType.NO_OPERATIONS_INVOKED;

With the Standard MBean, MXBean, enum, and DustinMBean classes all shown above, it is time to look at the class that calls DustinMBean to turn the Standard and MXBeans into dynamic MBeans with metadata descriptions.

/** * Construct the meta information for the SimpleCalculator * Standard-turned-Dynamic MBeans operations and the operations' parameters. * * Note that this method was adapted from a very similar method for * constructor Model MBean operation info data that was discussed in the * method buildModelMBeanOperationInfo() in the class * ModelMBeanDemonstrator in the blog entry "The JMX Model MBean" * (http://marxsoftware.blogspot.com/2008/07/jmx-model-mbean.html). * * @return Metadata about MBean's operations. */ private static MBeanOperationInfo[] buildMBeanOperationInfo() { // // Build the PARAMETERS and OPERATIONS meta information for "add". //

final MBeanParameterInfo augendParameter = new MBeanParameterInfo( "augend", Integer.TYPE.toString(), "The first parameter in the addition (augend)." ); final MBeanParameterInfo addendParameter = new MBeanParameterInfo( "addend", Integer.TYPE.toString(), "The second parameter in the addition (addend)." );

/** * Create and register an MBean given the provided MBean's implementation * class name, the desired Object Name for the MBean, and the MBeanServer * on which to register the MBean. * * @param mBeanClass MBean implementation class. * @param objectNameStr ObjectName to be used for the MBean instance. * @param mbs MBean Server that will be hosting the MBean. */ private static void createAndRegisterStandardMBean( final Class mBeanClass, final String objectNameStr, final MBeanServer mbs) {

In the class above, the method that sets up the metadata [buildMBeanOperationInfo()] is extremely similar to the same method used in an earlier blog entry to set up metadata on operations for the Model MBean class.

It is inside the try block in the registerStandardMBean method that most of the action occurs in terms of using the StandardMBean-derived DustinMBean. This method is a little more complicated than it would need to be if was less generic and reflection was not used. The example usage code shown in the Javadoc for StandardMBean shows how easy it can be.

In the main() of the StandardMBeanDemonstrator class, the code demonstrates that the Standard MBean and the MXBean are each used twice, once in the standard way and once via the StandardMBean class. The standard approach depends entirely on naming conventions between implementation and interface while the StandardMBean approach allows the implementation and interface to be explicitly associated in code. The latter approach also allows extra metadata to be specified.

I won't show it here, but the whatWasTheLastOperation() operation only works in JConsole for the two uses of MXBean and not for the two uses of Standard MBean for reasons displayed in a previous blog entry.

I'll end this entry with two screen snapshots. One shows the MXBean that was created and registered with the MBeanServer in the standard way. It works perfectly well, but lacks descriptive information in JConsole. The second shows the same MXBean registered with the StandardMBean approach. It works as well, but also shows dynamic MBean level of description.

MXBean Registered on MBean Server in Standard Way

MXBean Registered on MBean Server via StandardMBean Class

In conclusion, use of the Java SE-provided StandardMBean class allows JMX developers to treat Standard and MXBeans more like dynamic MBeans. Because all MBean types support Descriptors as of Java SE 6, the differences between the types of MBeans continue to blur.

2. Execute the downloaded JAR with a command like this: java -jar jdk-7-ea-src-b32-jrl-04_aug_2008.jar and follow the wizard (including accepting the JRL license terms). Make note of where you have the source code placed. For my examples, I had the contents placed in C:\java7.

3. Change directory to the "jdk" directory under the expanded Java SE 7 source code and run Ant like this: ant -f make/netbeans/jmx/build.xml

(The -foption in Ant specifies the location of an alternative build file instead of Ant looking for a build.xml file in the same directory. Alternatively, one could change directories all the way to the make/netbeans/jmx directory and simply run "ant" there.)

4. If all has gone well, there will be a generated jmx.jar file in the dist/lib directory. The next screen snapshot shows how this appears on my machine.

I copied this generated jmx.jar file into my C:\jmx2 directory for easy reference.

With jmx.jar built, it can be placed on the classpath to build and run examples based on JMX 2.0. In my case, I added it to NetBeans 6.1. In a later step, I'll show how I ran the sample using it in the runtime classpath. For now, though, I will show the two code listings for my example. The first is a class called SimpleCalculator adapted from my blog entries on Model MBeans (direct, with Spring, with Apache Commons Modeler, and with EasyMBean).

This version of SimpleCalculator differs from the various versions used in my previous Model MBeans examples because this version uses JMX 2.0 annotations. This example is different as well in the sense that these JMX 2.0 annotations allow this class to be used as a Standard MBean rather than as a Model MBean (the Spring and EasyMBean annotations exposed their decorated SimpleCalculator class as ModelMBeans).

The four import statements in SimpleCalculator correspond to the four JMX 2.0 annotations used in the creation of the Standard MBean. The @MBean annotation on the class itself states that it will be a Standard MBean (and @MXBean does the same for MXBeans). The @ManagedOperation annotation specifies which operations are exposed by the class-turned-Standard MBean. Because I cannot specify information on the parameters to the operations like I can do with Model MBeans, I have included parameter information via the @DescriptorFields annotation. Finally, I used @Description annotations to describe the class and each of the operations. Information on each of these annotations is available in the Javadoc documentation for the javax.management package.

The next class, Main, registers the annotated SpringCalculator Standard MBean with the platform MBean server.

With the above two classes implemented, they can be built and the resulting .class or .jar files can be executed. In my case, I built the classes with NetBeans 6.1 and it generated a JAR file called JMX2.jar containing the compiled Main.class and SimpleCalculator.class files.

To run the example and use the Java SE 7 jmx.jar in my Java SE 6 environment, I took advantage of Eamonn's recommendation regarding the use of the non-standard option bootclasspath to prepend (the p in the command) the JMX 2.0/Java SE 7 jmx.jar to the front of my boot class path. Running this application with this JMX 2.0/Java SE 7 jmx.jar in the boot class path looks like this:

java -Xbootclasspath/p:C:\jmx2\jmx.jar -cp JMX2.jar dustin.jmx2.Main

I can then run JConsole and view the exposed Standard MBean. The next two screen snapshots show this. The first screen snapshot shows some general MBean information and the second screen snapshot shows a particular operation being invoked via JConsole. Of special interest are the descriptor and description sections. I took advantage of both of these (the descriptors and the descriptions) to specify information about the operations' parameters that would be labeled simply as "p1" and "p2" otherwise.

I have attempted to demonstrate in this blog entry how easy it is to turn an otherwise normal Java class into a JMX Standard MBean using the proposed JMX 2.0/JSR-255 annotations. MXBeans are similarly annotated (the primary difference being the use of @MXBean rather than @MBean). The obvious advantage of these JMX 2.0 annotations is convenience and ease of use. However, Eammon points out in the "Pros and Cons of @MBeans" section of Defining MBeans with Annotations (and the Javadoc documentation points out in Defining Standard MBeans with annotations section of javax.management documentation) that there are disadvantages to using these annotations to define standard and MXBeans. The primary disadvantages result from the mixing of potentially JMX-exposed methods in a class with non-JMX-exposed methods in the same class (and hence confusing Javadoc documentation) and from the lack of an interface to use with JMX client proxies.