Tuesday Jun 03, 2008

RESTful Access to JMX Instrumentation, second part

This post is an answer to William Vambenepe who recently wrote an interesting post related to JSR 262 and the REST access to JMX I discussed a few months ago. William shows some interest in the REST adaptor for JMX and asks for the next steps. Here they are...


A bit of context

The REST approach is a possible solution for interaction with JMX agents mostly due to the fact that monitoring and management is increasingly present in our systems at a much higher level than it used to be.

The data exposed tends to be directly understandable. There is no need for complex processing on the client side to understand what is going on. Why is this possible? I think that it comes from the fact that the new trend in Monitoring and Management consoles (consoles such as JConsole or Visual VM), is to display "raw" data.

This raw data is interpreted by only viewing or displaying it graphically. It makes MBean designers think more and more about their MBean interfaces as human-readable APIs. My colleague Daniel Fuchs shows the limits of this approach in a recent blog entry. But I also remember Daniel saying a few years ago that people will soon start to design MBeans to comply with JConsole's capabilities. I think that he was absolutely right. This is what is emerging now.


So it seems an appropriate time to build an HTTP based access, along standardized lines, to allow web designers to benefit from this valuable management information by making it possible to embed it directly in Web pages.


My previous post put in place the foundations of the REST adaptor for JMX agents. This post covers the next features that should be added in the near future. I write “should be added” because I would like to hear your reactions to them before I add them to the current implementation. Please let me know whether or not they will meet any of your requirements, so that we can discuss how to improve them. The adaptor will be much more valid if it answers the needs of the community.


Security

HTTPS and Basic AUTH seem natural choices. Nothing special, simple and safe. They should cover most cases. Is Basic AUTH enough or do we also want to offer “mutual authentication”, to allow the server to authenticate clients based on client certificates? What about access control? We could easily add access control based on JMX permissions as is done today when you provide an access and password file when starting the JVM.


Snapshot of values

Currently we can't retrieve a complex MBean attribute atomically. Say that we want to retrieve all the values contained in the HeapMemoryUsage attribute of the Memory MBean. This attribute is of type CompositeData. The well-known URLs (that point to plain text data) associated to this attribute are the following:


http://curcuma:9999/rest/jmx/java.lang:type=Memory/HeapMemoryUsage/committed

http://curcuma:9999/rest/jmx/java.lang:type=Memory/HeapMemoryUsage/init

http://curcuma:9999/rest/jmx/java.lang:type=Memory/HeapMemoryUsage/max

http://curcuma:9999/rest/jmx/java.lang:type=Memory/HeapMemoryUsage/used


Currently, we can only retrieve committed, init, max and used individually.

If we introduce a new query parameter named capture, we could ask the adaptor to construct a frozen view of an attribute value (or more generally of a sub-tree). We could then retrieve the values located in the snapshot.


In practice:

GET http://curcuma:9999/rest/jmx/java.lang:type=Memory/HeapMemoryUsage?capture=mysnapshot1


Returned resource :

<ul>
<li>http://curcuma:9999/rest/snapshots/mysnapshot1/jmx/java.lang:type=Memory/NonHeapMemoryUsage/commited</li>
<li>http://curcuma:9999/rest/snapshots/mysnapshot1/jmx/java.lang:type=Memory/NonHeapMemoryUsage/init</li>
<li>http://curcuma:9999/rest/snapshots/mysnapshot1/jmx/java.lang:type=Memory/NonHeapMemoryUsage/max</li>
<li>http://curcuma:9999/rest/snapshots/mysnapshot1/jmx/java.lang:type=Memory/NonHeapMemoryUsage/used</li>
</ul>



The returned URLs reference the captured data. We now have the freedom to analyze the values outside the ever-changing real world. This pattern could also be applied higher up in the tree (at the MBean level, for example) to create a snapshot of multiple attributes.


Notifications

We could map from JMX Notifications to atom feeds. This could be a good approach. However, here I would like to keep it simple and carry on with the resource-centric approach and try not to break the model. I would like to make the number of required technologies as minimal as possible. Relying on HTTP(S) with a bit of HTML/XML should be the maximum we allow ourselves... ;-)


So, how can we proceed? JMX MBeans are the event sources. Clients generally subscribe to MBean notifications then pull notifications from the MBean server. Pulling seems very appropriate in our web context. Pushing has never really worked.

If you want reliable, zero-loss notifications then you should stop reading this post. You are going to be frightened by what I am about to say. In JMX we generally see notifications as an unreliable way to receive information. You can't count on a high level of reliability. Lost notifications are not common but they can occur. Once you know the context in which notifications are handfed, you can design an event system that copes with it. Making your MBean re-emit notifications until an acknowledgement comes back can be a decent solution.


If we agree with what has been said previously, we can attach a rolling buffer to each MBean resource that contains the last n emitted notifications (10 is a possible default value). This buffer can be pointed to using the URL scheme we have already put in place.

Here is an example URL for retrieving notifications:

http://curcuma:9999/rest/notifications/jmx/java.lang:type=Memory/



If events occur, the list of emitted notifications is returned in the GET response.

<ul>
    <li>
       Notification 1 
    </li>
    <li>
       Notification 2
    </li>
    ...
    <li>
       Notification N
    </li>
</ul>

Representation of notifications

A Notification is a complex type for which we can define a set of well known URLs. By nature, a notification is a snapshot of data, and its URL contains the information that makes it unique. The JMX API doesn't guarantee a unique sequence number. The emission time seems a better identifier.


<ul>
  <li>http://curcuma:9999/rest/notifications/jmx/java.lang:type=Memory/25_12_1970_12_00_00/message</li>
  <li>http://curcuma:9999/rest/notifications/jmx/java.lang:type=Memory/25_12_1970_12_00_00/number</li>
  <li>http://curcuma:9999/rest/notifications/jmx/java.lang:type=Memory/25_12_1970_12_00_00/type</li>
  <li>http://curcuma:9999/rest/notifications/jmx/java.lang:type=Memory/25_12_1970_12_00_00/userdata/<...possible path if complex type></li>
   ... user data URL continue if complex content.
</ul>

Custom notifications

If the emitted notification is custom-built, and some getters are exposed, then the added field is discovered and exposed. For example, the following notification defines a getPriority field:


public class PriorityNotification extends Notification {
  ...
  public int getPriority() {
    ...
  }
}

This will be returned as follows:

<ul>
 <li>http://curcuma:9999/rest/jmx/notifications/java.lang:type=Memory/25_12_1970_12_00_00/priority</li>
 <li>http://curcuma:9999/rest/jmx/notifications/java.lang:type=Memory/25_12_1970_12_00_00/message</li>
 <li>http://curcuma:9999/rest/jmx/notifications/java.lang:type=Memory/25_12_1970_12_00_00/number</li>
 <li>http://curcuma:9999/rest/jmx/notifications/java.lang:type=Memory/25_12_1970_12_00_00/type</li>
 <li>http://curcuma:9999/rest/jmx/notifications/java.lang:type=Memory/25_12_1970_12_00_00/userdata/<...possible path if complex type></li>
</ul>



Filtering based on emission time

You could argue that only keeping 10 notifications is insufficient and that all notifications should be stored. OK, but in this case, we would like to be able to filter out the old ones. That can be done by adding a since query parameter when getting notifications. For example:

http://curcuma:9999/rest/notifications/jmx/java.lang:type=Memory/?since=20_12_1970_00_00

We just need to agree on a date format.

Notification retrieval scope

This approach allows us to express a homogenous "retrieval scope”. By choosing a location in the tree (a URL where we can get notifications), we can retrieve notifications emitted by :

  • MBean servers (all MBeans, and potentially all attributes too, could add a JMX pattern to narrow the scope)

  • MBeans

  • MBean attributes (equivalent to AttributeChange).

  • Information inside an attribute value (namely, is it a real scope, and do we want it?)



Conclusion

It seems that things are still being kept simple here without compromising the JMX technology's philosophy. Or perhaps not, and you think it is already too complicated and I should stop mining this seam... just let me know and I will down tools! ;-)

What do we have on the plate for the next post? Setting attributes and invoking MBean operations. If you have some ideas, please let me know. They are tough ones!

Thanks.

Jean-François Denise

jean-francois.denise@sun.com



Thursday Mar 13, 2008

RESTful Access to JMX Instrumentation, Via URI-fication of MBean Attributes

As you perhaps know from reading my posts, I am involved in the definition of JSR 262, Web Services Connector for JMX Agents. JSR 262 offers an access to Web Services that is very far removed from Representational State Transfer (RESTful) Web Services. So, this blog is not about JSR 262, but instead it describes some of the investigations and development I have performed related to the Java API for RESTful Web Services (JAX-RS API) and the JMX API.

Having simple HTTP-based access to a Java Management Extensions (JMXTM) MBean is an idea that I like a lot and one for which I think that there are thousands of real use cases. For example, when developping a Web application, integrating a piece of information obtained from JMX instrumentation, such as the status of a service, should be as simple as loading an HTML page.

My first attempt was to define and implement a merge of JSR 262 and a RESTful approach... All in vain! The two technologies cannot co-habit, so you are forced to choose between them. You either have to go down the WS-\* path or you have to go down the RESTful path. There's no way to make one leverage the other to offer a tidy solution. In this case, keeping the two parts separate is much better than trying to bundle them together. In this investigation, I have limited the scope just to retrieving information from JMX instrumentation. Setting MBean attributes or invoking operations has not been addressed (yet).

June 2008. UPDATE TO THE ORIGINAL ENTRY. I added description for support of notifications and snapshot of values in this new entry.

If you want to play with this prototype for RESTful access to JMX instrumentation (based on Jersey, which you will need to download) before reading the blog entry, you can jump straight to Running the Adaptor. This RestFul JMX Adaptor is hosted by the OpenDMK java.net project.

But first, let's start with a bit of background. The next sections describe how the information from JMX instrumentation is accessed, and how this information can then be mapped into a format that is acceptable to the RESTful approach.

JMX Instrumentation Information Tree

So, how does JMX instrumentation present its information? First, we have an MBean server in which MBeans are registered. Each MBean contains a set of attributes that represent an actual piece of information. MBean attributes are not always exactly actual pieces of data, though, as this is dependent upon the Java class of the attribute. If the attribute is a primitive type, then yes, the attribute is indeed an actual piece of data. If it is a complex type (or a collection), then it is not. Complex types need to be traversed to discover the actual data.

So, we can represent the whole set of information exposed by the JMX instrumentation as a tree. The root of the tree is the MBean server, the MBeans are the root's child nodes and the attributes are the MBeans' child nodes. Some attributes are terminal nodes (primitive nodes), some other attributes (complex types) are intermediary nodes.

The following figure presents the JMX instrumentation information tree:


In this tree, we can see the data path as leaves.


Here, we can identify three elements:

  1. The leaf node, which is a data container.

  2. The intermediary node, which is a child container.

  3. The data path, which is composed of the set of parent/child relationships from the root to the leaf.

Traversing Complex Types

We just saw that you need to traverse complex types to access the actual data. However, how to deal with every sort of complex type that can be defined is outside the scope of these investigations. So, we have limited ourselves to Array, List, Set and the generic JMX types CompositeData (which is very similar to Map) and TabularData (which is a table of CompositeData).

The above list of types complies with MXBean usage, so we are able to go quite far, even with this limited set. These types are traversed in different ways, as follows:

  • To traverse a List or an Array, you need to iterate the structure.

  • To traverse a CompositeData, you need to find out each key and retrieve the associated value.

  • To traverse a TabularData, you need to iterate the structure and then traverse each CompositeData (as described above).

Mapping the Information Tree to RESTful Web Services

I am not making a revolutionary statement by saying that nodes are resources and data paths are URIs. In our information tree, we have two kinds of resources, container resources that are referenced by other resources, and the content resources. These resources can be identified by URIs, as explained in the next sections.

Resource URIs

The different resources in our information tree are identified by the following URIs:

  • MBean server: http://<host>:<port>/<root context>

  • MBean: http://<host>:<port>/<root context>/<MBean ObjectName>

  • MBean attribute: http://<host>:<port>/<root context>/<MBean ObjectName>/<attributeName>

  • Collection (list or array) element: http://<host>:<port>/<path to complex type>/<index>

  • Map element: http://<host>:<port>/<path to complex type>/<URL encoded(key.toString)>

  • CompositeData entry: http://<host>:<port>/<path to complex type>/<key>

  • TabularData element: http://<host>:<port>/<path to complex type>/<index>

Container Resources

MBean servers, MBeans, arrays, lists, sets, CompositeData entries and TabularData elements are all container resources. A simple XML definition is enough to represent these resource types. To avoid defining a new XML element, we can reuse the XHTML list element (<ul><li></li></ul>).

References to a child can either be relative to the current resource or absolute. I chose to make them absolute. Below are some examples of representations of different container resources.

  • MBean server containing two MBeans:

    <ul>
    <li>http://<host>:<port>/<root context>/java.lang:type=Memory</li>
    <li>http://<host>:<port>/<root context>/java.lang:type=Thread</li>
    </ul>
  • MBean with two attributes, NonHeapMemoryUsage and HeapMemoryUsage:

    <ul>
    <li>http://<host>:<port>/<root context>/java.lang:type=Memory/NonHeapMemoryUsage</li>
    <li>http://<host>:<port>/<root context>/java.lang:type=Memory/HeapMemoryUsage</li>
    </ul>
  • CompositeData, composed of commited and init keys:

    <ul>
    <li>http://<host>:<port>/<root context>/java.lang:type=Memory/NonHeapMemoryUsage/commited</li>
    <li>http://<host>:<port>/<root context>/java.lang:type=Memory/NonHeapMemoryUsage/init</li>
    </ul
Note: You will notice that I am not using the HTML link tag (<a href="..."></a>). This is because I am not defining HTML access (such as that provided by the JMX technology's HTML adaptor), but rather XML access.

Container resources like those above are not of particularly great interest to us. They help with navigation when you are having difficulties finding your way through the information tree, but when you know where you want to go, they are almost useless. When you know where you want to go you don't need to navigate at all, you just jump at light speed to the end of the path by providing the full URI.

However, in some cases where the information is dynamic, container resources can be really helpful.

Content Resources

In this prototype, actual data is represented by straightforward plain text. For example, Hello world, is plain text...

A Restful Adaptor for JMX Instrumentation

I have developed a prototypal implementation of the above mapping using the JAX-RS Reference Implementation (a.k.a the Jersey project). The adaptor attaches to the platform MBean server that is located inside any Java Virtual Machine (JVMTM) from Java Development Kit (JDK) version 5.0 or above. The adaptor offers URI-based navigation, and the returned pages are in either HTML or XML format, according to the receiving client's "Accept Headers" setting.

The current prototype covers all the types exposed by the JVM software's MXBean interfaces (used for monitoring memory, threads, classes, etc.). If your MBeans are also MXBeans, they you should be able to navigate to them without problems. I re-used the HTML <ul><li> tags to handle lists in XML. In HTML, the <a href="..."> tag is used in conjonction with the <li> tag in order to make clickable URLs.

The adaptor provides an API (JMXWSMBeanRestResource#setListXMLTags) that allows you to change these list tags and provide your own.

If your MBeans expose unsupported types, you can provide your own resources by calling JMXWSMBeanRestResource#registerResourceHandler. Look at the source code for JMXWSMBeanRestResource.CollectionResource to understand how the adaptor's JAX-RS resources are defined.

JAX-RS Resources

JAX-RS allows you to define “top level” resources that return sub-resources. I defined a top level resource named JMXWSMBeanRestResource, which serves as the JMX adaptor's entry point and handles the MBean server and the MBean resource types. It also delegates the navigation of attribute values to sub-resources. The current sub-resources are the following:

  • PlainResource

  • ArrayResource

  • CollectionResource

  • MapResource

  • CompositeResource

  • TabularResource

Each resource handles a data type and, in turn, delegates it to other sub-resources to reach the leaf (the plain text resource).

The JAX-RS resource / sub-resource pattern allows for very simple tree navigation. Each resource is annotated using JAX-RS annotations. The following ArrayResource shows what a sub-resource actually does:

public class ArrayResource { 

/\*\* Returns the list of URI that point to array items. \*\*/

@GET

@ProduceMime("text/xml")

public Response getXMLItemURIs() throws Exception {

return getURIs();

}

/\*\* Returns the Sub resource pointed by the array index. ResourceFinder is a reference to the JMXWSMBeanRestResource that manages Sub Resources. \*\*/

@Path("collection/{index}")

public Object getItem(@UriParam("index") String index) throws Exception {

int idx = Integer.valueOf(index).intValue();

return resourceFinder.findResource(Array.get(array, idx));

}

...

}

That's about it for the introduction. Now you can see the adaptor in action.

Running the adaptor

  1. You need first to do a CVS checkout of the Restful Adaptor sources from OpenDMK java.net project

    1. export CVSROOT=:pserver:guest@cvs.dev.java.net:/cvs

    2. cvs co opendmk/contributions/rest-adaptor

    3. Open the NetBeans project rest-adaptor/RestAdaptor.

  2. Follow the steps documented in Restful Adaptor readme file.

  3. Run the adaptor (this requires a minimum of JDK version 5.0, although JDK 6 is recommended).

  4. The adaptor will display the URL on which it is bound, as well as some other information, such as the composition of the URIs and the names of the MBeans.

  5. In your browser type the following URL : http://localhost:9999/rest/jmx.

  6. If your browser is set to accept XML headers by default over HTML headers (as is the case for Firefox), you will receive the resources in XML form, which is not really the best form for a browser. However, you can still navigate by copying and pasting the URIs until you reach a leaf. The best thing to do is to change your Firefox settings to accept HTML headers by default over XML headers, as follows:

    1. In your browser, type about:config

    2. Go to network.http.accept.default

    3. Prefix the value with text/html.

    You can now navigate from the root to the leaves.

But, as I said previously, navigation is really not the best way. What you really want to do is to jump to a value using a well-known URL. But where are these well known URLs? They are there already, waiting for you. If you want to see them all, go to the following URI:

http://localhost:9999/rest/jmx/all

This URI references a special resource that lists ALL the leaves of a JMX information tree for a given MBean server. All listed URLs identify an actual piece of data.


This list of URLs (that can be very long) can be filtered by using a URI parameter that contains the following JMX specification ObjectName pattern: http://localhost:9999/rest/jmx/all?pattern={your jmx ObjectName pattern}

Well Known URLs

In a system being managed by JMX instrumentation, the set of exposed MBeans is generally well defined. The set of MBean ObjectName instances is well known and documented so that clients can access the exposed information. We can take advantage of this and select a set of URLs that will never change for a given system. For example, the URIs that identify the commited heap memory of the JVM software from JDK version 5.0 or version 6 will never change, except for the host and port deployment information, as shown below :

http://<host>:<port>/rest/jmx/java.lang:type=Memory/NonHeapMemoryUsage/commited

This file contains the URIs you expect to find in a JVM implementation from JDK version 6, regardless of your context. For monitoring and management of the JDK software, the URLs that change are related to Array and TabularData (i.e. thread IDs, system properties, logger names, etc.) and to memory managers that are not identical as far as the hardware architecture is concerned.

You can easily discover these URLs without navigating through the tree, by starting at index 0 and incrementing by 1 until you reach a 404 error. For example, to retrieve all the thread IDs, you just have to increment the {index} :

http://<host>:<port>/rest/jmx/java.lang:type=Threading/AllThreadIds/{index 0-N}

The example of thread IDs shows up a major limitation of this approach when the information is very dynamic (as threads are). The array size and elements can change in such a way as makes the returned values invalid. In this case we would need a snapshot of the array.

June 2008. UPDATE TO THE ORIGINAL ENTRY. I added description for support of notifications and snapshot of values in this new entry.

Conclusion

This RESTful adaptor provides a possible way of implementing a RESTful access to JMX instrumentation. I have a strong feeling that it could be very helpful when aggregating loosely coupled pieces of information. The current adaptor does not address all data structures (although MXBeans are fully handled), but it is provided in Java source code and offers an API for you to add your resource handlers.

Possible usages:

  • Develop AJAX based dashboads to monitor Java VM and/or your applications.

  • Quickly construct HTML pages to offer human readable access to the internals of your systems.

What are the next steps:

  • Add a support for Notifications.

  • Add a support for POST/PUT.

  • Add a support for snapshot of values.

I would like to thank Paul Sandoz for is great help. REST philisophy is Paul's second nature. Expose him your problem and he will Restify it. Really smart!

I would be very happy to receive any feedback about this approach. Feel free to contact me and thank you for reading.

Regards.

Jean-François Denise

Saturday May 05, 2007

JMX Web Services Connector is out, in WS-Man dress.


JMX Web Services Connector (JSR 262) RI is out! You can download it here.

The novelety in comparaison with the previous Early Access is that the Connector protocol is now based on WS-Management (WS-Man). Connector WS-Man implementation is based on the WiseMan project.

Native WS-Man clients can now interact with MBeans. MBeans are no more the exclusivity of JMX clients. Clients such as Windows Remote Manager (WinRM) and openwsman, can retrieve MBean attributes, call MBean operations and subscribe to MBean notifications.

JSR 262 specification defines a mapping between JMX MBeans and WS-Man Managed Resources. More details can be found in the Early Draft 2 specification. Have a look to the spec and send us your feedbacks.

Next Thursday, at JavaOne, during Eamonn and myself Technical Session, we are presenting an interoperability demo that highlights these new JMX interoperation capabilities. Demo is composed of three scenario:
  • HP Open View Operations / JSR 262 (done by Denis Rachal from HP)
  • Microsoft WinRM Scripting for JSR 262
  • Microsoft Vista Event Viewer to subscribe to MBeans
See you there!

Jean-Fran├žois
About

jeanfrancoisdenise

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today