TemporaryQueue を介して別のモジュールの MDB とメッセージを同期的に交換する必要がある EJB モジュールがあります。EJB コンテナー (私の場合は Glassfish 4.0) はトランザクション環境を前提としています。BEAN 管理のトランザクションを使用し、UserTransaction オブジェクトを使用してトランザクションの開始と終了を示す必要がありますか。
私のコードの概要は次のとおりです。
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class CommunicationJMSUtils {
@Resource
private UserTransaction ut;
@Inject
private JMSContext context;
@Resource(lookup = "jms/DestinationQueue")
private Queue destination;
private static final long JMS_COMMUNICATION_TIMEOUT = 5000;
public Map<String, String> getClientordersData(String id) throws JMSException {
try {
MapMessage mm = context.createMapMessage();
ut.begin();
TemporaryQueue replyQueue = context.createTemporaryQueue();
mm.setJMSReplyTo(replyQueue);
mm.setStringProperty(<...>);
<...>
mm.setString(<...>);
<...>
context.createProducer().send(destination, mm);
ut.commit();
ut.begin();
ObjectMessage om = (ObjectMessage) context.createConsumer(replyQueue).receive(JMS_COMMUNICATION_TIMEOUT);
ut.commit();
if (om != null) {
return om.getBody(Map.class);
} else {
throw new JMSException("Failed to receive reply within " + JMS_COMMUNICATION_TIMEOUT);
}
} catch (NotSupportedException | RollbackException | HeuristicMixedException | HeuristicRollbackException | SecurityException | IllegalStateException | SystemException ex) {
<...>
}
}
}
最初の問題は、時々、このコード (受信部分) が例外で失敗することです。
MQJMSRA_DS4001: _checkDestination:Temporary Destination not owned by parent connectionId=1760697170479431168
明らかに、TemporaryQueue は同じ JMSContext で作成されます。
そして 2 つ目の問題は、このコードの「脆弱性」です。context.createMapMessage() を最初のトランザクション内に配置するか、TemporaryQueue の作成を最初のトランザクションの外に移動すると、このスニペットは間違いなく失敗します。
残念ながら、JMS のチュートリアルやドキュメントは、その特定のユース ケースを実際にはカバーしていません。Java EE で JMS 2.0 を使用して JMS 要求/応答パターンを実装する正しい方法は何ですか?