subscriber.setMessageListener(null) / subscriber.close() questions
frawolff Sep 15, 2011 9:05 AMHi,
The JMS API documentation states: "The effect of calling MessageConsumer.setMessageListener
while messages are being consumed by an existing listener or the consumer is being used to consume messages synchronously is undefined." (MessageConsumer class)
I understand that synchronous and asynchronous delivery modes cannot be used at the same time.
Here is a code snippet that works with JBM (from a standalone Java client application) and reproduce more or less some of the code logic I am currently writing (the semaphore here is used to mimic the asynchronous processing / long-polling timeout of a asynchronous servlet):
{code}
final TopicSubscriber sub = session.createDurableSubscriber(topic, subscriptionId);
final List<Message> messages = Collections.synchronizedList(new ArrayList<Message>());
final Semaphore done = new Semaphore(1);
done.acquire();
sub.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
sub.setMessageListener(null);
messages.add(message);
done.release();
}
catch (JMSException e) {
e.printStackTrace();
}
}
});
// Wait for a onMessage() call with a 20 seconds timeout.
boolean timeout = done.tryAcquire(20, TimeUnit.SECONDS);
// Reset the message listener if it has never been called.
if (timeout)
sub.setMessageListener(null);
// Try to get all pending messages (if any).
Message message = null;
while ((message = sub.receiveNoWait()) != null)
messages.add(message);
sub.close();
// do something with the messages...
{code}
Questions:
1. Calling setMessageListener(null) in the onMessage(...) message works: the onMessage method is executed in a JBM thread and reseting the message listener in the same thread doesn't seem to a problem, even if it the JMS API documentation speaks about "undefined" behaviour in this case. Is it valid to call setMessageListener(null) here (JBM / HornetQ / JMS in general)?
2. The second call (after the timeout) is more problematic: setMessageListener(null) isn't called from a JBM thread and it can possibly be executed during a concurrent execution of the onMessage(...) method, from a JBM thread. Again, is it valid to call setMessageListener(null) here (JBM / HornetQ / JMS in general)?
3. The call to the close() method at the end shouldn't be problem. The documentation states: "This call blocks until a receive
or message listener in progress has completed". Because it is called after the listener has been reset to null and after receiveNoWait() calls (if any), it shouldn't block at all. Am I right?
I could live without the following (commented out) part of the code:
{code}
done.tryAcquire(20, TimeUnit.SECONDS);
// if (timeout)
// sub.setMessageListener(null);
// Message message = null;
// while ((message = sub.receiveNoWait()) != null)
// messages.add(message);
sub.close();
{code}
The close() call would block if a onMessage() call is executed at the same time but it has an annoying drawback: I must close the subscriber and I cannot cache it for later reuses (this is not so bad but it can cause performance issues)...
Thanks for any clarification.