#7 Mockrunner JMS should not need exposeListenerSession = false

David Boden

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:
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.