Monday, April 12, 2010

WSO2 ESB Tips & Tricks 04: Troubleshooting JMS

WSO2 ESB works really well with JMS. The JMS transport adapter used by WSO2 ESB comes from the Apache Axis2 project and it makes use of JNDI to connect to various JMS brokers. Therefore WSO2 ESB can work with pretty much any JMS broker that offers JNDI support. The product ships with sample configurations for Apache ActiveMQ integration, but it can be easily modified for integration with a JMS broker like IBM MQ or SwiftMQ.
Enabling JMS in WSO2 ESB is a simple 2-step process.
  1. Deploy the JMS client libraries to the repository/components/lib directory (these libraries will be used by the ESB to connect to the JMS broker)
  2. Enable JMS transport receiver and the sender by modifying the axis2.xml file or using the management console
Having followed the above mentioned process you can start creating JMS endpoints to forward messages and JMS proxy services to receive messages. However while implementing certain JMS related scenarios you might run into some error conditions. The rest of this blog post focuses on a couple of such commonly encountered problems and how to get rid of them, once and for all.
CNF? NCDF?
If you ever run into any ClassNotFoundExceptions or NoClassDefFoundExceptions while using JMS support in WSO2 ESB, chances are you haven’t deployed all the required client libraries. Please inspect what you have copied into repository/components/lib directory and make sure the required class is available in one of the deployed jars.
Also note that WSO2 ESB ships with geronimo-jms library which contains the javax.jms packages. Therefore you do not have to deploy them again.
HTTP Header Conversion Problem
When forwarding HTTP traffic to a JMS queue using WSO2 ESB, you might at times run into an error similar to the one given below.
ERROR JMSSender Error creating a JMS message from the axis message context
javax.jms.MessageFormatException: MQJMS1058: Invalid message property name: Content-Type
This exception is thrown by the JMS client libraries used to connect with your JMS broker and the problem is specific to the JMS broker being used. I have encountered this issue mostly with IBM Websphere MQ, but I guess there might be other broker implementations that may display the same issue. So here’s what happens….
The incoming HTTP message contains a bunch of HTTP headers that contain the ‘-‘ character. Some notable examples are ‘Content-length’ header and the ‘Transfer-encoding’ header. When ESB attempts to forward the message over JMS it sets the headers of the incoming message to the outgoing JMS message as JMS properties. According to the JMS spec the ‘-‘ character is prohibited in JMS property names. Some JMS brokers like ActiveMQ do not strictly check for this and hence they won’t complain. But certain other brokers will throw exceptions similar to the one shown above.
Even though the problem sounds very complex and tricky the solution is almost trivial. We just need to get rid of the troublemaking HTTP headers from the message before it is delivered over JMS. You can make use of the property mediator as follows to achieve this:
<property action="remove" name="Content-Length" scope="transport">
<property action="remove" name="Accept-Encoding" scope="transport">
<property action="remove" name="User-Agent" scope="transport">
<property action="remove" name="Content-Type" scope="transport">
JMS Property Data Type Mismatch
Sometimes when the ESB attempts to forwards a message over JMS, the client libraries may complain, saying that the data type of a particular message property is invalid. You may often run into this problem if you are using the property mediator to manipulate property values set on the message. This is because certain implementations of JMS, have restrictions on data types of properties. The property mediator always sets property values as strings.
To overcome this problem you will have to revise your mediation sequences and avoid manipulating property values which should contain non-string values. If you must set a non-string property value you will have to write a simple custom mediator to get the job done. Starting from WSO2 ESB 3.0 (scheduled to go out this month), the property mediator is type aware. Therefore to get rid of this problem you can set properties with specific data types. For an example if you want to set a property named foo with the integer value 12345 use the property mediator as follows:
<property name="foo" value="12345" type="INTEGER" scope="transport/">
If you leave the type attribute out the property value will be set as a string.
Too Many Threads? Out of Memory?
With certain JMS brokers WSO2 ESB tends to spawn new worker threads indefinitely until it runs out of memory and crashes. I have observed this behavior with SwiftMQ. This problem is caused by a bug in the underlying Axis2 engine and there is a simple workaround to the problem. In your mediation sequence engage the property mediator as follows:
<property action="remove" name="transportNonBlocking" scope="axis2">
This will prevent the ESB from creating new worker threads unlimitedly and everything will be back to normal. Note that you can always use a JMX client like jconsole to monitor the active threads and memory consumption of the ESB.

No comments: