#7 Mockrunner JMS should not need exposeListenerSession = false

open
nobody
None
5
2012-07-16
2012-07-16
David Boden
No

In the Spring JMS environment, we use SessionAwareMessageListeners as a convenient way to receive requests and send responses back on the same JMS connection.

Spring's JMS' AbstractMessageContainerListener has a method called setExposeListenerSession(boolean) with Javadoc that reads:

/**
* Set whether to expose the listener JMS Session to a registered
* {@link SessionAwareMessageListener} as well as to
* {@link org.springframework.jms.core.JmsTemplate} calls.
* <p>Default is "true", reusing the listener's {@link Session}.
* Turn this off to expose a fresh JMS Session fetched from the same
* underlying JMS {@link Connection} instead, which might be necessary
* on some JMS providers.
* <p>Note that Sessions managed by an external transaction manager will
* always get exposed to {@link org.springframework.jms.core.JmsTemplate}
* calls. So in terms of JmsTemplate exposure, this setting only affects
* locally transacted Sessions.
* @see SessionAwareMessageListener
*/

Mockrunner is one of the JMS providers that needs this value set to false.

Without the flag set to false, the following Exception occurs when you try to send a reply using a SessionAwareMessageListener's session:

java.lang.IllegalStateException: Already value [org.springframework.jms.connection.JmsResourceHolder@22ebbe] for key [com.mockrunner.mock.jms.MockConnectionFactory@ead97b] bound to thread [main]
at org.springframework.transaction.support.TransactionSynchronizationManager.bindResource(TransactionSynchronizationManager.java:189)
at org.springframework.jms.listener.SimpleMessageListenerContainer.processMessage(SimpleMessageListenerContainer.java:336)
at org.springframework.jms.listener.SimpleMessageListenerContainer$2.onMessage(SimpleMessageListenerContainer.java:316)
at com.mockrunner.mock.jms.MockMessageConsumer.receiveMessage(MockMessageConsumer.java:83)
at com.mockrunner.mock.jms.MockTopic.addMessage(MockTopic.java:57)
at com.mockrunner.mock.jms.MockMessageProducer.send(MockMessageProducer.java:89)
at com.mockrunner.mock.jms.MockMessageProducer.send(MockMessageProducer.java:51)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:592)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:569)
at org.springframework.jms.core.JmsTemplate$4.doInJms(JmsTemplate.java:546)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:466)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:543)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:529)

So, what's the problem? Why not just set the flag to false? Well, no big problem, which is why I'm raising this as a feature request and not a bug. The pain is that the nice Spring JMS custom namespace detailed here doesn't support the exposeListenerSession flag:
http://static.springsource.org/spring/docs/3.0.x/reference/jms.html
Specifically, the <jms:listener-container/> tag doesn't support the flag.

That means that switching to Mockrunner involves avoiding the Spring JMS custom namespace and creating a SimpleMessageListenerContainer in long-handed <bean/> configuration.

Discussion