Monday, March 30, 2015

Exposing JMS queues and topics with a JAX-WS webservice

Everyone can do HTTP calls and thus call most webservices. Interfacing with JMS queues or topics though is a bit more difficult (when not using Oracle SOA Suite). An alternative is using custom code. This usually requires libraries, JNDI lookups, opening connections and such. Because I wanted to make it easy for myself to put stuff on queues and topics, I created a simple JAX-WS wrapper service. By using this service, JMS suddenly becomes a whole lot easier.


Implementation

If you just want to download and use the code, go to the usage section. I wrote the code in a short time-span. It can use some improvements to make the request message better and to allow dequeueing. Also I have not tested it under load and I might not do a nice cleanup of the connection.

Getting started

The implementation is relatively straightforward if you're a bit familiar with JMS programming. There are some things to mind though. The first thing I encountered were some difficulties after I selected the JAX-WS Sun reference implementation in JDeveloper when creating my JAX-WS webservice. I should of course have selected the Weblogic implementation to avoid issues (such as missing metro-default.xml and missing classes after having added that file). Deleted the application and started over again. No issues the second time.


This next part is also shown in the title image. I first obtain the Context which is easy since the webservice is running in the application server. Using this context you can obtain a Destination by doing a JNDI lookup. This Destination can be used to obtain a ConnectionFactory. Using this ConnectionFactory you can obtain... yes... a Connection! This Connection can be used to obtain a Session. This Session in turn can be used to create a TextMessage and a MessageProducer. You can imagine what those two can do together.

Avoid separate code for queues and topics

It is important to realize that for this implementation it is not relevant if you are posting to a queue or a topic. Specific destinations exist for topics and queues but you can just as well use the Destination class itself. The same goes for the ConnectionFactory. Using these common classes avoids duplication in the code.

JMSProperties and JMSHeaders

JMSProperties
I didn't like this part. The JMSProperties are custom properties which can have a specific type such as integer, string, float, double, boolean. There are separate methods on TextMessage instances to set these different types. In an XSD this would have been a choice. I didn't do contract first development though and a Java implementation of an XSD choice isn't something which can be called pretty (http://blog.bdoughan.com/2011/04/xml-schema-to-java-xsd-choice.html). Thus I supplied a string and an enum indicating the type in order to map it to the correct method and set the property.

JMSHeaders
The JMSHeaders also weren't fun. The TextMessage class had several methods specific to individual headers! What I wanted though was just to specify name/value pairs and let it set the value based on that. I was required to make a mapping to the header specific methods of the TextMessage class and do a type conversion from string to the input of the specific method. This would have been easier with Oracle BPEL and invoke activity properties.

Base64

I choose to supply the message as Base64. Why? Well, because escaping XML doesn't look good and we're not even sure every message is going to be XML. We might want to send JSON. JSON escapes differently. In order to avoid escape issues, base64 always works. I used Apache Commons Codec to do the Base64 part. For quick online encoding/decoding you can use something like: https://www.base64encode.org/. Beware though not to feed the site with business sensitive information.

Usage

You can download the code here. The project is specifically written to run on Weblogic server (developed on the 12.1.3 SOA Suite quickstart). A WAR is included. It might also run on older SOA Suite versions with some minor changes.

First you have to create a queue or topic. A queue is easiest for testing. You can look at for example http://middlewaremagic.com/weblogic/?p=1987 on how to create a queue. I've created a queue called MyQueue which I supply as JNDI name.

After you deploy the service, you can call it using the Enterprise Manager test console or SOAP UI or anything which can do HTTP. After a call you can verify in the Weblogic console the message has arrived.



Warning

Beware though that you are providing a hole in the Weblogic security layer by exposing JMS queues and topics to 'the outside'. This webservice needs some pretty good security. I therefore recommend to only use it for development and testing purposes and avoid using it in a production environment.