A QueueBrowser
is a specialized object that allows
you to peek ahead at pending messages on a Queue
without actually consuming them. This feature is unique to
point-to-point messaging. Queue browsing can be useful for monitoring
the contents of a queue from an administration tool, or for browsing
through multiple messages to locate a message that is more important
than the one that is at the head of the queue. The latter scenario is
what we chose to explore in our new version the wholesaler
application, the QWBrowser
.
QWBrowser
sends out price quotes to multiple
instances of QRetailer
, which respond with
"Buy" orders. To make this more interesting, we'll
modify the retailer so that each order requests a random number of
items. The QWBrowser
may not be able to fulfill
all of the orders from its on-hand inventory.
In order to sell as many items from inventory as possible without
going into backorder, QWBrowser
examines all of
the responses that are pending in the queue, then finds the one order
with a quantity that most closely fits the amount it has in
inventory. It then synchronously consumes all of the messages using
QueueReceiver.receive(long
timeout)
, fulfills the desired order, and places
the rest of them in a back-order status.
If you would like to see this in action, shut down all the other
wholesalers and retailers you may have running. Start one instance of
QWBrowser
and four or more instances of
QRetailer
, each in a separate command window:
java chap5.B2B.QWBrowserlocalhost
WHOLESALER1password
java chap5.B2B.QRetailerlocalhost
RETAILER1password
java chap5.B2B.QRetailerlocalhost
RETAILER2password
java chap5.B2B.QRetailerlocalhost
RETAILER3password
java chap5.B2B.QRetailerlocalhost
RETAILER3password
In the command window for the QWBrowser
, type the
following command:
Surfboards, 999.99, 499.99
When you press Enter, each instance of QRetailer
will get the price quote, and respond with a "Buy Order."
Each order will request a different quantity. You should see output
in the QWBrowser
window indicating that it is
browsing the queue, placing the order for one of the messages, and
placing the rest on back-order status.
The QueueBrowser
object is simple to use. We will
examine this listing from QWBrowser.examineQueue(
)
in detail:
private int examineQueue(int inStockQty) { int cnt = 0; int bestQty = 0; try { System.out.println("In Stock QTY: " + inStockQty); System.out.print ( "Creating QueueBrowser..." );javax.jms.QueueBrowser browser = qSession.createBrowser(receiveQueue);
System.out.println ("[done]");java.util.Enumeration e = browser.getEnumeration( );
while(e.hasMoreElements( )){ System.out.print(" --> getting message " + String.valueOf(++cnt) + "...");javax.jms.TextMessage message = (javax.jms.TextMessage) e.nextElement( );
System.out.println("[" + message.getText( ) + "]"); if (message != null){ int orderQty = message.getIntProperty("QTY"); if ( orderQty > bestQty && orderQty <= inStockQty) bestQty = orderQty; } } // Free any resources in the browserbrowser.close( );
} catch ( javax.jms.JMSException jmse ){ jmse.printStackTrace( ); } System.out.println(" BestQty: " + bestQty); return bestQty; }
First, note the call to create the QueueBrowser
:
System.out.print ( "Creating QueueBrowser..." );
javax.jms.QueueBrowser browser
= qSession.createBrowser(receiveQueue);
System.out.println ("[done]");
The method createQueueBrowser(
)
is a session method. It takes a
Queue
object as a parameter and returns a
QueueBrowser
object. The
createQueueBrowser( )
method, in additon, allows
you to set a message selector using an overloaded method signature.
The QueueBrowser
object contains a
java.util.Enumeration
that holds the messages in
the queue. Here's how to use it:
...java.util.Enumeration e = browser.getEnumeration( );
while(e.hasMoreElements( )){javax.jms.TextMessage message = (javax.jms.TextMessage) e.nextElement( );
System.out.println("[" + message.getText( ) + "]"); ...
When the browser has served its purpose, it must be closed. This informs the JMS provider that it is no longer needed, thus allowing the provider to clean up any resources it may have allocated on the browser's behalf:
// Free any resources in the browser
browser.close( );
Now let's look at the main input loop, which publishes the
prices quotes, browses the queue, then uses a synchronous
QueueReceiver
to consume the messages after it has
browsed them:
public void processInput( ){ try { ... System.out.println ("Enter: Item, Old Price, New Price"); System.out.println(" e.g. Bowling Shoes, 100.00, 55.00"); String dealDesc = stdin.readLine( ); ...publishPriceQuotes(dealDesc,uname, itemDesc, oldPrice,newPrice);
int inStockQty = (int)(java.lang.Math.random( ) * (double)1000);int bestQty = examineQueue(inStockQty);
qConnect.start( ); // Start the connection javax.jms.TextMessage textMessage = null; while( true ){textMessage = (javax.jms.TextMessage)qReceiver.receive(1000);
if ( textMessage == null ){ qConnect.stop( ); break; // No more messages to get } String text = textMessage.getText( ); int qty = textMessage.getIntProperty("QTY"); System.out.println(" Order received - "+text+ " from " + textMessage.getJMSCorrelationID( )); if (qty == bestQty){ System.out.println("Fulfilling order"); // Do some processing to fulfill order } else { System.out.println("Placing in BACK-ORDER status"); // Do some processing to create BACK-ORDER status } } ... }
Messages obtained from a
QueueBrowser
are
copies of messages contained in the queue and are not considered to
be consumed—they are merely for browsing.
It is important to note that the QueueBrowser
is
not guaranteed to have a definitive list of messages in the queue.
The JMS specification allows the QueueBrowser
to
contain a snapshot, or a copy of, the queue as it appears at the time
the QueueBrowser
is created. The behavior may vary
depending on vendor implementation, since the contents of the queue
may change between the time the browser is created and the time you
examine its contents. No matter how small that window of time is, new
messages may arrive and other messages may be consumed by other JMS
clients. Some JMS providers will update
QueueBrowser
s as the status of the queue changes
while others will not.