Riding the Snake

“Ride the snake” is a line in one of my favourite songs by The Doors, “The End”. The song also plays during the culminating of one of my favourite movies, Francis Ford Coppola’s masterpiece “Apocalypse Now”.
I associate “riding the snake” with tinkering around in Python, although according to the Urban Dictionary it does have a quite different meaning. Whatever.

How does that relate to work?

Recently, I was working with one of my customer’s employees on a scenario where we wanted to replace one component in their messaging infrastructure by another - hopefully more reliable - solution. For testing purposes, we used an open source tool that I find quite indispensable when working with messaging technologies as JMS, or even WebSphere MQ (yes, you can also work with IBM’s WebSphere MQ using its JMS bindings, see my blog posting).

The problem at hand was that we had to demonstrate that our proposed solution was able to replace the existing implementation - which was being crippled by hangups several times a day, requiring a restart - by demonstrating that the outcome of our implementation would perform correct in terms of message relocation, without the need for operator intervention. If only they had required the same amount of validation for their initial solution...

As the messages were of multiple JMS types and coming in over an interval of ten days as part of our duration testing, we decided we would like to see a count of messages per type per date, apart from some initial validation testing to verify that individual messages were being delivered without modification to their payload. So, the possibility of using the "Browser with Selector" functionality was out of the question.

The problem with HermesJMS

There is one small problem with HermesJMS, as good as it is: it’s not being actively supported anymore. The code is still available on SourceForge, where it points to its website (http://www.hermesjms.com) for more documentation and examples, but unfortunately these pages do not exist anymore in the here and now.

Time Machine to the rescue?

Although I have been able to recover some of the documentation on the HermesJMS home page, using the “Internet Archive Wayback Machine”, the content is far from complete. It does offer some nice and informative examples and descriptions, but the documentation of the Java classes quite fragmented.

So, if you really need to dive into the implementation details quickly, this is not going to help. Checking out the source code from SourceForge:

Source code is still available
Checking out HermesJMS sources from SourceForge

Now, the source code comes complete with a build file allowing to generate the JavaDocs:

ant generating JavaDoc
Generating documentation using Ant

Python? Why?

So, as said, we had a requirement to browse some queues and perform aggregations on its contents, in order to demonstrate beyond reasonable doubt that the alternative we had proposed would accomplish the same result as the existing solution did, but in a more reliable way, requiring less attention of the operators to periodically restart the component. As we did not fancy writing a solution in Java, pulling in all kinds of dependencies and we were already using HermesJMS for browsing the queues and loading message data into this messaging infrastructure, we decided to give HermesJMS’s  Python integration a go … How can a programming language that derives its name from one of the greatest groups op British comedians not be the proper choice of weapon?

Ministry of Silly Walks
John Clees in Monty Python's Flying Circus'
sketch "Ministry of Silly Walks"

Hermes riding the Snake

In the more recent release of HermesJMS, it contains a Jython interpreter, which is actually a Python interpreter running in the JavaVM. This interpreter only manifests itself in HermesJMS through a small icon in the bottom left-hand corner:

Jython Interpreter in HermesJMS
A well kept secret? HermesJMS' Jython interpreter

You can expand this by clicking on the icon and pin it to prevent it from hiding again:

Pinning and exploring
Pinning the Jython interpreter and exploring the invokeable methods on the Java objects

The screenshot above shows how you can explore the capabilities (attributes/methods) of an existing Java class inside the Jython environment.

As we already had the setup in place to connect to the desired message destinations, building on the examples retrieved through time-travelling to the HermesJMS.com website, resulted quickly in a prototype of the script that allowed us to aggregate message counters per type per date. This script, listed below, was saved in a Python script file that can be run by invoking the context menu on the Jython interpreter (just right-click inside the Jython area to show the menu item to “Load a script”):

Running a Jython Script
Running a Jython script in HermesJMS

 

Implementation for WebLogic 12.1.3

The script below shows how to interact with a WebLogic 12c environment from HermesJMS, using Python as the scripting language while reusing the connection configuration from within HermesJMS and, more importantly, its access to the WebLogic Java libraries:

import time
from hermes.browser import HermesBrowser
from hermes import Domain
print "Starting"

hermes = HermesBrowser.getBrowser().getContext().lookup("ACC-WebLogic")
ctx = hermes.createContext()

# replace <<<JNDI-FOR-YOUR-DESTINATION-HERE>>> with your JNDI
queue = ctx.lookup("<<<JNDI-FOR-YOUR-DESTINATION-HERE>>>")
session=hermes.getSession()
qb = session.createBrowser(queue)
# here the way of addressing the queue is different
d = qb.getEnumeration()
agg={}
i = 0

while ( d.hasMoreElements()):
    i+=1
    m = d.nextElement()
    jmsDate = time.localtime(m.JMSTimestamp/1000)
    sJMSDate = "%04d-%02d-%02d"%(jmsDate[0],jmsDate[1],jmsDate[2],)
    if not(sJMSDate in agg):
      agg[sJMSDate] = agg[sJMSDate]= {}
    a = agg[sJMSDate]
    jmsType = m.JMSType
    if jmsType in a:
        a[jmsType]+=1
    else:
        a[jmsType]=1
    if (i%5000==0):
        print "Messages: %08d" % (i)

# Print all results per date
sortedDates = agg.keys()
sortedDates.sort() # in-place sorting
gt = 0

print "%10s - %-10s - %08s" % ("yyyy-mm-dd", "MsgType", "Count")
for key in sortedDates:
    sortedTypes = agg[key].keys()
    sortedTypes.sort() # in-place sorting
    for t in sortedTypes:
        gt += agg[key][t]
        print "%10s - %-10s - %08d" % (key,t,agg[key][t],)
print "Done, grand total =" + str(gt)

Conclusion

Although it required some effort to uncover the information using the Wayback machine, accomplishing this task with HermesJMS and some Python scripting provided the relief by quickly obtaining an answer to demonstrate the viability of our proposed alternative solution.

Epilogue – Implementation for JBoss5

We have also created this script for performing the aggregation on queues hosted by JBoss EAP5.x; the code for this solution is slightly different (apart from the obvious differences like session and queue names), by requiring a delegate to be obtained instead of an Enumeration that needed to be browsed with hasNextMessage()/nextMessage() as opposed to hasMoreElements()/nextElement(). Apart from this minor implementation differences, the code was identical and easily adjusted!

qb = session.createBrowser(queue)
d = qb.getDelegate()
agg={}
i = 0
while ( d.hasNextMessage()):
    i+=1
    m = d.nextMessage()

 

Over de auteur