This question is mostly focused on Websphere Application Server (WAS) when using Websphere MQ (WMQ) since that is what I'm most familiar with. However, I think everything I'm talking about more generally applies to all Java EE application servers since I'm sticking to Java standard interfaces. I'd prefer an explanation related to the standards, but I'd still be quite thrilled with an answer specific to WAS/WMQ.
JMS 1.1 defines a mechanism for JMS to interface with an application server. The rough process is that a ConnectionConsumer is created at some point to monitor a Queue or Topic. When a message shows up, the JMS implementation gets a ServerSession object from the ServerSessionPool, loads the message into the Session associated with the ServerSession, and then calls start() on the ServerSession object. The ServerSession then is responsible for scheduling the message for processing by an MDB on an application server thread. The MDB gets the message as part of its onMessage() method and can do whatever processing it needs to.
This is all good, until the MDB decides that it wants to send another message in response to the one it received. In order to do this, the MDB has to look up or inject a ConnectionFactory object, get a Connection, then a Session, then a MessageProducer, and then finally send the message. This all seems quite wasteful. As part of the message delivery to the MDB, a Connection and Session object have already been created. If the MDB could somehow get access to that Session, it could avoid having to do all that extra work and avoid having to create all those extra Connections. That extra work as a cost - in order to just send a reply message to a request message, the MDB has to use two Connections and two Sessions (one each to get the message and send the response). When using global transactions, I believe that this forces the application server to process the transaction as a two-phase commit transaction (at least some, if not all, application servers can optimize a global transaction involving only a single resource by processing it as a one-phase commit). Making the transaction a two-phase transaction significantly increases the overhead of processing the message and also introduces all sorts of new complexity (in-doubt transactions being one of the biggest).
The JMS 1.1 spec notes: "Since many listeners will need to use the services of its session, the listener is likely to require that its session be passed to it as a constructor parameter" which seems to indicate that it would be perfectly acceptable for the MDB to use the Session that delivered the initial message to also send a response. However, I'm not aware of any mechanism to retrieve this Session object from an MDB in a standard way. I'm also not aware of any mechanism to retrieve it in a non-standard way. I can't even find a question or blog post regarding this anywhere.
So, the question is: Why is this the case? The JMS API is quite convoluted, but, I don't see anything in it that would make it hard for an MDB to use the Session that fed it the original message to send a response if it could access it. Is there some reason why the MDB wouldn't be able to use this Session object? Is there a standards compliant method to get access to the Session? Is there a non-standards compliant way? Are application servers / JMS implementations smart to optimize a global transaction involving operations on two Connections on a single JMS queue manager into a one-phase commit transaction (my research and understanding of the standards seem to indicate this isn't possible)?