Spring JMS and WebSphere

Kris Geusebroek

Using Spring JMS in our application which needs to be running on WebSphere proved to be somewhat of a challenge. And since googling provided a lot of information but just a small ‘easy to miss’ piece of text to put the pieces together, i decided to write up this blog.


Part I

The need for using Spring JMS opposed to ‘normal’ MessageDrivenBeans came out of the following requirement:

On receiving messages from the Queue we need to send these messages to another system through a Socket connection.

This means that we cannot start processing the messages from the queue until the socket connection is available. This socket connection is created on application startup in  a spring bean so it isn’t possible to guarantee that the connection is available. And also the application will be deployed inside a WebSphere cluster so one of the two servers in the cluster will never get a connection to the socket.

So we need some kind of programmatic control over the starting of the message listener.

Luckily this is possible in Spring with the start (and stop) methods of the AbstractJmsListeningContainer or the GenericMessageEndpointManager. Since we already had an implementation with MessageDrivenbeans and ActivationSpecifications to distribute the messages we decided to go with the JmsMessageEndpointManager because we could reuse our ActivationSpecifications configured in WebSphere (well we thought we could do that…..)

Reusing the configured ActivationSpecification was not possible see this topic on the springsource forum so we configured the ActivationSpecification in the spring config files together with the message endpoint handler the resource adapter and the workmanager as described in the using Spring JMS on WebSphere article.

No messages were picked up and no error messages were found to guide us in the right direction. So without more information it became some kind of trial and error exercise (which i hate, and become to hate even more because of the long /try to fix/deploy/test cycle).

So after a few tries i decided to take a closer look at the sources i had used to develop the configuration and after reading over it more than once my eyes stopped at the following piece of text hidden in the using Spring JMS on WebSphere article:

…Be aware that no other Spring JMS MessageListenerContainer types are supported…

Did this mean…..? Yes it did. By making the decision to use the message endpoint handler i had used the wrong type. So after a few minutes of rewriting the configuration to use the DefaultMessageListenerContainer (together with a messageselector to replace the activationspecification), setting the autoStartup property to false and injecting it into my connection manager bean to programmatically start the listener after the connection is created, one more long /try to fix/deploy/test cycle………..

Part II

and then it almost worked. A ClassCastException in the onMessage method stating that class A could not be cast to class A. Why isn’t it possible to cast something to itself. Ok i admit it seems a bit strange to want to do this and i didn't do it on purpose really. The onMessage method was supposed to receive a Serialized message as input parameter so i thought i needed to cast it. But it turned out to be a class A already. So i changed the method signature to take a class A as input parameter.

So we got rid of the ClassCastException this way but now we got an NoSuchMethodError (i’m not exactly sure what i prefer). This is going to look like a ClassLoader issue and if it looks like a ClassLoader issue and behaves like a ClassLoader issue it is a ClassLoader issue!

But how can that be? I have an ear file with a war file which loads all the spring bean with the contextLoaderListener and nothing else. Well almost nothing else. On the same server a different ear is deployed which also makes use of class A. therefore class A is in the core module (its called core module for a reason!). Could it be that?

Yes it can be that! The Websphere server can decide to use a ApplicationClassloader for multiple applications so on server level we need to set the classloading policy to single to prevent the ClassCastException or the NoSuchMethodError.

Hope this helps anyone out there to avoid these pitfalls.

Comments (9)

  1. Francesco - Reply

    October 15, 2009 at 3:21 pm

    Hi

    I had stumbled on pretty much the same problem almost an year ago. Now, did you manage to reference an activationSpec using the DefaultMessageListenerContainer? I'm referring to your line

    "together with a messageselector to replace the activationspecification"

    Thanks for recompiling this information, I admit having been lazy to do it myself...

  2. Kris - Reply

    October 16, 2009 at 12:02 pm

    Hi Francesco,

    This is what it looked like when using the activationspec (which didn't work) in the spring config:

    	<bean id="jmsListenerPL0100"
    		class="org.springframework.jms.listener.endpoint.JmsMessageEndpointManager">
    		<property name="resourceAdapter" ref="wasResourceAdapter" />
    		<property name="activationSpec"
    			ref="receiveQueueActivationSpecPL0100" />
    		<property name="messageListener"
    			ref="messageReceiverListener" />
    		<property name="transactionManager" ref="transactionManager" />
    	</bean>
    
    	<bean id="receiveQueueActivationSpecPL0100"
    		class="com.ibm.ws.sib.api.jmsra.impl.JmsJcaActivationSpecImpl">
    		<property name="destination" ref="receiveQueue" />
    		<property name="destinationType" value="javax.jms.Queue" />
    		<property name="busName" value="server1_bus" />
    		<property name="maxConcurrency" value="5" />
    		<property name="messageSelector" value="regioCode='PL0100'" />
    	</bean>
    

    and now it looks like this:

        
        <bean id="jmsListenerPL0100" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="connectionFactory" />
            <property name="destination" ref="receiveQueue" />
            <property name="messageListener" ref="messageReceiverListener"/>
            <property name="transactionManager" ref="transactionManager" />
            <property name="taskExecutor" ref="wasDefaultWorkManager" />
            <property name="messageSelector" value="regioCode='PL0100'" />
        </bean>
    

    Cheers Kris

  3. rd - Reply

    February 23, 2011 at 7:17 pm

    This is very helpful. Thank you for sharing.

  4. Sujeeth - Reply

    August 22, 2011 at 10:59 am

    Hello,

    I just wanted to have a simple MDB listening on Websphere, which listens on a queue onto which external system posts messages.

    For this, I created the Messaging listener service on Websphere, and my MDB listens and recieves the messages sucessfully. Now, my goal is to delegae the message processing to a Service / Session Facade class (POJO).

    How to inject service class into my MDB using Spring framework ? I have a clue that, my MDB should configure as spring JMS bean as explained nicely by Kris. But, who will load Spring container, in case of consuming messages ?

    Thanks in advance.
    Sujeet

  5. Paul - Reply

    March 21, 2012 at 9:51 pm

    An old thread, but for future reference one solution to Sujeeth's question is Kris' statement of having an "ear file with a war file which loads all the spring bean with the contextLoaderListener". Another approach is for the web app to load spring beans via "new ClassPathXmlApplicationContext("classpath:spring-config.xml");". This will effectively boostrap the spring message listener(s).

  6. Paul - Reply

    March 21, 2012 at 9:53 pm

    Also, to clarify the web app will load spring beans via a new ClassPathXmlApplicationContext in the contextInitialized() method of a ServletContextListener implementor contained in the war file.

  7. Veeras - Reply

    August 30, 2012 at 6:39 am

    09:54:51,683 WARN [org.springframework.jms.listener.DefaultMessageListenerContainer] (jmsContainer-1) Could not refresh JMS Connection for destination 'ORANGE.QUEUE' - retrying in 5000 ms. Cause: JMSWMQ2013: The security authentication was not valid that was supplied for QueueManager 'tree.queue.manager' with connection mode 'Client' and host name '192.168.2.29(1414)'.; nested exception is com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2035' ('MQRC_NOT_AUTHORIZED').

  8. Veeras - Reply

    August 30, 2012 at 6:42 am

    Hi i am trying to integrate Spring JMS with Websphre MQ i got above warning when
    i deploy i application to server.I don't know how to solve this problem, Can you please help me on this.

  9. Veeras - Reply

    August 30, 2012 at 6:47 am

    It i showing like Authentication problem, I don't know where to configrue the username & password , it is not allowing to put under MQQueueConnectionFactory below.I am using WQ 7.5.0 & Spring 2.5
    My Configuration in spring like below:

    1
    tree.queue.manager
    192.168.2.29
    1414
    SYSTEM.DEF.SVRCONN

    ORANGE.QUEUE

    <!--

    -->

    Thanks,
    Veeras

Add a Comment