I have a pair of JMS application classes, let's call them XMIT and RECV. An external application creates sequential messages and sends them to XMIT, which writes them to two JMS queues, Primary and Auxiliary. By default, XMIT writes messages to Primary, but if XMIT detects that an incoming message has a sequence number that isn't the last sequence number written to Primary plus one, it begins writing messages to Auxiliary, and notifies the external application that it had better find the missing messages and send them down, which can happen in tandem with new messages being sent.
When XMIT is writing to Auxiliary, it checks each incoming message to see if it has a sequence number of one greater than the last message written to Primary. If it does, the message is written to Primary, otherwise, it is written to Auxiliary. If the message sequence number is not only last Primary sequence + 1 but also first Auxiliary message sequence -1, then messages are read from Auxiliary, written to Primary, and then acknowledged to Auxiliary,
The upshot of this is supposed to be that Primary gets only consecutive messages, and if there is any break in the sequence, we spill to Auxiliary until the missing records can be provided.
RECV deals only with the Primary queue. It retrieves messages at the behest of another external application, and acknowledges them only when that application says it's done with them. Because any JMS acknowledgement automatically acknowledges any previously received messages, and because RECV wants to acknowledge messages individually and not necessarily in sequence, it uses a QueueBrowser on Primary to locate messages, get an Enumeration, step through that Enumeration and send the messages up to the external app along with the JMS message ID, all without doing a Receive. Each message passed up is added to a LinkedHashMap in sequence order, and when the external app indicates that a particular message should be released, the Map entry is flagged as released, and a scan of the Map is done and any consecutive set of entries starting at the beginning which are flagged as released are received and acknowledged from the Primary Queue.
The upshot of this is that RECV can deliver multiple messages to the external app without allowing JMS to release any of them, and that it can allow the external app to release them in a random order, with RECV only receiving and acknowledging them as it knows that the external app is done not only with that message but all previous sequence numbers as well.
Here's the problem.
If I run the XMIT external app and let it feed XMIT until it's done, and then start RECV and let it feed its external app, all is fine. If I start RECV and let it stall for want of input, and then start XMIT to start feeding the Primary queue, things run fine until we hit the first gap in sequence numbers. Let's say that we get 1, 2, 3, followed by 6. 6 gets written to Auxiliary and the XMIT external app gets told that 4 and 5 are required. 4 and 5 get sent down in due course, and get written to Primary, at which point 6, 7, and 8 which have accumulated in Auxiliary are copied to Primary following 4 and 5.
Except RECV sees 3, and the next time he requests an Enumeration form the QueueBrowser, the first message he sees is 6, even though 4 and 5 were both written to Primary before 6.
I can't figure out why RECV doesn't see the messages in sequence order. I know that the JMS spec says that the QueueBrowser Enumeration isn't guaranteed to be a snapshot of the Queue, but I would still expect that whatever got put into it was in the order that the messages were written.
This is JBoss 7.2.0 Final using HornetQ. Any ideas ?