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



Friday May 23, 2008

Use VBScript to cheat at poker with JMX!

This year at JavaOne Eamonn and I presented during our technocal Session, where we stand with respect to JMX. Eamonn covered JMX in general and JMX 2.0, while I covered the Web Services Connector for JMX. At the end of the talk, we performed a demo named “CSPoker, JMX Technology, Java VisualVM and WinRM at the JavaOne Tournament's Final Table”. We linked together a set of JMX related technologies to offer, in an original Online Poker Web Site use case, an interesting setup highlighting the power of JMX (here's a PDF file of the demo architecture) .

At the end of the talk, some people asked me some questions about the WS-Management access to JMX we had just demonstrated. More details on the WS-Management to JMX interoperability can be found in this article.

Here, I am providing some details on the actual script used during the demo. This script automates the Poker Engine monitoring and management tasks. It first registers to listen for JMX Notifications exposed as WS-Eventing notifications. Each time a “Poker table joined” notification is received, it checks that the IP address from which the player joined is not already known to the system. If an IP address is already known, it means that another user already joined from the same host.... which is very bad if you want to avoid the same player using multiple identities....

When such a “bad user” is detected, the script ejects all the players that joined from that machine.

Intialisation of the WS-Management access

dim wsmanObj
set wsmanObj = CreateObject("WSMAN.Automation")
dim objConnectionOptions
set objConnectionOptions = wsmanObj.CreateConnectionOptions
dim iFlags
iFlags = wsmanObj.SessionFlagUseNoAuthentication
dim session
set session = wsmanObj.CreateSession("http://localhost:8080/admin", iFlags)

At this point, you have a WS-Management proxy (the session object), that allows you to interact with a JMX Agent attached to the Web Services Connector.


Subscription to the MBean notifications

The MBean we want to subscribe to is named : cspoker:type=CSPokerControl

Because the WS-Management session doesn't offer a nice API for subscriptions, we need to construct the subscription invocation request using the “all purpose” invoke method :


Dim reply
reply = session.invoke("http://schemas.xmlsoap.org/ws/2004/08/eventing/Subscribe", _
"http://jsr262.dev.java.net/DynamicMBeanResource?ObjectName=cspoker:type=CSPokerControl", _
"<wse:Subscribe xmlns:wse='http://schemas.xmlsoap.org/ws/2004/08/eventing'>"_
& "<wse:Delivery Mode='http://schemas.dmtf.org/wbem/wsman/1/wsman/Pull'/></wse:Subscribe>")

At this point we have sent a WS-Eventing subscription request (in PULL mode, meaning that the client will send a request to pull notifications from the server) and received a response. The response contains the WS-Eventing context to be used to retrieve notifications.

Retrieving the Eventing context

To get the eventing context from the response, we need to make use of the VBScript DOM library : Microsoft.XMLDOM

Warning : Because namespaces are not handled well in this DOM library, we are trying to discover the Namespace prefix based on our knowledge of the way they are declared (ns<i>). I am not a VBScript expert and would be very interested to know if there is an equivalent to getElementsByTagNameNS using VBScript???

Function findElement(elem, tagElem)
' wscript.echo "Finding Element " & tagElem
 for i = 0 to 15
  set findElement = elem.getElementsByTagName("ns"& i &":" & tagElem)
  If findElement.Length > 0 Then Exit For
 next
End Function

Dim objXMLDoc
set objXMLDoc = CreateObject("Microsoft.XMLDOM")
objXMLDoc.async = False
objXMLDoc.loadXML(reply)

' Get the Eventing context to use in the next WS-Eventing Pull request
Dim nodeList
set nodeList = findElement(objXMLDoc.documentElement, "EnumerationContext")
dim context 
context = nodeList(0).text
wscript.echo "Subscription Enumeration Context " & context

At this point, the context variable contains the WS-Eventing context that identifies our subscription. This context is to be used to retrieve notifications.

Retrieving the Notifications

This is done by sending a Pull request to the server and providing it the context. The pull request blocks until some Notifications are emitted or the timeout (1 minute by default) is reached. As for subscribe requests, no Pull API is offered. We need to use the general purpose invoke operation. We have written a pull function that handles pull request timeouts properly. When the timeout occurs, instead of exiting the script, the error is trapped and the script continues. Because we expect multiple notifications, the Notification pulling is done in a loop.

Function pull(session, context)
 On Error Resume Next
Dim pullXml
pullXml = "<wsen:Pull xmlns:wsen='http://schemas.xmlsoap.org/ws/2004/09/enumeration'><wsen:EnumerationContext>" & context & "</wsen:EnumerationContext><wsen:MaxTime>PT1M0.000S</wsen:MaxTime><wsen:MaxElements>1000</wsen:MaxElements></wsen:Pull>"
 pull = session.invoke("http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull", "http://jsr262.dev.java.net/MBeanNotificationSubscriptionManager", pullXml)
  On Error Goto 0
End Function

' This piece of script is called in an infinite loop

Dim notifs

 notifs = pull(session, context)

At this point, the notifs variable contains (or does not contain, if the timeout occurred) the JMX notifications in an XML format.

Extracting the Notification content and tracking the cheat

We only do this extraction if the list of notifications is not null. The VBScript DOM library is again used to parse the notifications. Because a pull request can return multiple notifications, we must iterate on all TargetedNotification elements contained in the notification list. A TargetedNotification is an XML representation of a JMX Notification defined by the JSR 262 (JSR in which the Web Services Connector is defined).

In our case, the TargetedNotification/Message XML Element contains the Player name. The TargetedNotification/UserData XML Element contains the IP Address as a string (eg:<jmx:String>192.168.0.1</jmx:String>)

To keep the IP <==> Player relationship, we use a Map data structure and array. In VBScript, we use a dictionnary (scripting.dictionary Libray)

' Create a Map
dim dict
set dict = CreateObject("scripting.dictionary")
Dim ipArray(10)
Dim arrayIndex
arrayIndex = 0

if Not(isNull(notifs)) then

  set objXMLNotif = CreateObject("Microsoft.XMLDOM")
  objXMLNotif.async = False
  objXMLNotif.loadXML(notifs)
  set NodeListNotifs = findElement(objXMLNotif.documentElement, "TargetedNotification")
  WScript.echo "Pull returned " & NodeListNotifs.length & " notifications"

  ' Now that we get the list of notifications, extract the content.
  Dim i
  Dim EventType
  Dim msgObj
  ' Loop over the received Notifications
  For i = 0 To NodeListNotifs.length - 1
      Dim listMsg
      set listMsg = findElement(NodeListNotifs(i), "Message")
      Dim eventMessage 
      eventMessage = listMsg(0).text

      Dim listUserData
      set listUserData = findElement(NodeListNotifs(i2), "String")
      ' We have an IP address
      if(listUserData.length > 0) then
           Dim ipAddress
           ipAddress = listUserData(0).text
           wscript.echo eventMessage & " Joined From " & ipAddress
           if dict.exists(ipAddress) then
              Dim prev
              prev = dict.item(ipAddress)
              if Not StrComp(prev,eventMessage) Eqv 0 Then 
                 dim users
                  users = Array(eventMessage, prev)
                  For Each user In users
                    wscript.echo user & " already connected from same host [" & ipAddress &"], will eject him." '"Type return."
                    wscript.echo "Ejecting player " & user
                    ejectPlayer session, user
                    wscript.echo "Player " & user & " ejected"
                  Next
              end if
           else
             dict.add ipAddress, eventMessage
           end if
      else
         wscript.echo eventMessage
      end if
  Next

Ejecting the player

The function ejectPlayer calls the ejectPlayer MBean operation by making use of the general purpose invoke operation.

Function ejectPlayer(session, playerName)
 dim pokerURI
 pokerURI = "http://jsr262.dev.java.net/DynamicMBeanResource?ObjectName=cspoker:type=CSPokerControl"
 dim xmlInvoke
 xmlInvoke = "<jmx:ManagedResourceOperation name=" & Chr(34) & "ejectPlayer" & Chr(34) & " xmlns:jmx=" & Chr(34) & "http://jsr262.dev.java.net/jmxconnector" & Chr(34) & "><jmx:Input><jmx:Param><jmx:String>" & playerName & "</jmx:String></jmx:Param></jmx:Input></jmx:ManagedResourceOperation>"
 session.invoke "http://jsr262.dev.java.net/DynamicMBeanResource/Invoke", pokerURI, xmlInvoke
End Function


Hope that these VBScript extracts helped you understand better how you can use this path to interoperate with JMX.

Thanks.

Jean-François Denise

jfd@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

Tuesday Jun 05, 2007

J2EE Deployment of JMX WS Connector


If you are already evaluating the Early Access 2 of JSR 262, you have perhaps a need to deploy the Connector in your servlet container.
A sample, located in samples/servletdeployment directory, shows you how to achieve such deployment. The provided example shows how to deploy the JSR262 JAX-WS Endpoint com.sun.jmx.remote.ws.wsman.JMXWSManServiceEndpoint inside a JAX-WS compliant servlet container. When created, the endpoint gets a reference to the platform MBeanServer (thanks to java.lang.management.ManagementFactory.getPlatformMBeanServer())
If the MBeans you want to manage are registered inside the platform MBeanServer, you can reuse this sample code. Registering MBeans in the platform MBeanServer is something that we encourage.
If you want to attach the connector to another MBeanServer, then you need to subclass JMXWSManServiceEndpoint and provide your own MBeanServer.

Extending JMXWSManServiceEndpoint JAX-WS endpoint

When extending an annotated class (JMXWSManServiceEndpoint JAX-WS endpoint is annotated), the extended class doesn't inherite from the mother class annotations, you need to re-annotate the extended class.
When deploying in J2EE, no JMXServiceURL is provided to the connector (as opposite to the JMX J2SE way of deploying a Connector). You need to provide to the Connector the URL on which it has been deployed. This is done by calling setURL on JMXWSManServiceEndpoint class. This URL is used when translating from MBean ObjectName to WS-Addressing EPR.

Extended class

The following sample code is a ready to deploy extended class that gets a reference to the first MBeanServer found thanks to the javax.management.MBeanServerFactory class. The URL on which the endpoint has been deployed is hard coded. You can easily externalize it, for example read it from a property file.

import com.sun.jmx.remote.ws.api.JMXWSManDispatcher;
import com.sun.jmx.remote.ws.api.JMXWSManServiceEndpoint;
import javax.xml.ws.WebServiceContext;
import javax.annotation.Resource;
import javax.management.\*;

@javax.xml.ws.WebServiceProvider
@javax.xml.ws.ServiceMode(value=javax.xml.ws.Service.Mode.MESSAGE)
public class ExtendedEndpoint extends JMXWSManServiceEndpoint {
   @Resource
   private WebServiceContext context;

   public ExtendedEndpoint() throws Exception {
       super(new JMXWSManDispatcher(null, 
               (MBeanServer)MBeanServerFactory.findMBeanServer(null).get(0)));
   }

   protected WebServiceContext getWebServiceContext() {
        return context;
   }
}


Packaging the connector

You simply need to update the endpoint implementation in the sun-jaxws.xml file and repackage the extended class in a war file similar to the sample.

sun-jaxws.xml file

<?xml version="1.0" encoding="UTF-8"?>
< endpoints
        xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
        version="2.0">
        < endpoint
                name="JMXWSManEndpoint"
                implementation="ExtendedEndpoint"
                service="{http://jsr262.dev.java.net/jmxconnector/wsdl}JMXConnectorService"
                port="{http://jsr262.dev.java.net/jmxconnector/wsdl}JMXConnectorPort"
                url-pattern="/jmxws"
                binding="http://www.w3.org/2003/05/soap/bindings/HTTP/">
        </endpoint>
</endpoints>

Conclusion

The simpler way to deploy the Connector is by using the JMXConnectorServerFactory class. This will answer your needs when you want to take benefit of the JAX-WS http server. Direct JAX-WS endpoint deployment is the other way when reusing an existing infrastructure.

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