The following question is from Enthuware:
The developer of a MDB wants to ensure that a message is redelivered if the onMessage method of the bean throws a RuntimeException. What should he do?
a) Nothing. This is guaranteed by the container.
b) He should use container managed transactions with transaction attribute of REQUIRED.
c) He should use Bean managed transaction, catch any exception, and call UserTransaction.rollback().
d) He should use Bean managed transactions and use JMS API for message acknowledgement.
My answer was a) while the answer given was b). This is the explanation given:
In this case, the transaction will be rolled back and the message will be redelivered. As per section 13.6.3.2 of EJB 3.0 Core specification:
A transaction must be started before the dequeuing of the JMS message and, hence, before the invocation of the message-driven bean’s onMessage method. The resource manager associated with the arriving message is enlisted with the transaction as well as all the resource managers accessed by the onMessage method within the transaction. If the onMessage method invokes other enterprise beans, the container passes the transaction context with the invocation. The transaction is committed when the onMessage method has completed. If the onMessage method does not successfully complete or the transaction is rolled back, message redelivery semantics apply.
I do agree that when using CMT with the REQUIRED transaction attribute message redelivery takes place. However, I think the same happens when using BMT in which case is the responsability of the container.
As per the spec, section 5.4.14 (Message Acknowledgement for JMS MDBs):
If bean-managed transaction demarcation is used, the message receipt cannot be part of the bean-managed transaction, and, in this case, the receipt is acknowledged by the container. If bean-managed transaction demarcation is used, the Bean Provider can indicate whether JMS AUTO_ACKNOWLEDGE semantics or DUPS_OK_ACKNOWLEDGE semantics should apply by using the activationConfig element of the MessageDriven annotation or by using the activation-config-property deployment descriptor element. The property name used to specify the acknowledgment mode is acknowledgeMode.
Then section 5.4.17 (Dealing with exceptions) specifies:
If a message-driven bean uses bean-managed transaction demarcation and throws a RuntimeException, the container should not acknowledge the message.
Am I missing something? Is it that message redelivery and message acknowledge are two unrelated things? Please, explain.