Java Platform, Enterprise Edition

Java EE Journal

Subscribe to Java EE Journal: eMailAlertsEmail Alerts newslettersWeekly Newsletters
Get Java EE Journal: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


J2EE Journal Authors: Stackify Blog, Sumith Kumar Puri, Javier Paniza, Yakov Fain, Ken Fogel

Related Topics: Java EE Journal, Intel XML, XML Magazine, Java Developer Magazine, Java in the Cloud

Blog Feed Post

GlassFish, Open MQ, and the Ear-Eye Problem By @YFain

You look at the code everything looks perfect, but it doesn’t work no matter how long you look at it

GlassFish, Open MQ, and the Ear-Eye Problem

Yesterday I’ve been updating code examples for the messaging chapter for the 2nd edition of my Java book. While doing this, I ran into an issue, then fixed it, but the cause and the solution illustrate the situation that we call “Ear-Eye”, which comes from and old joke popular in the USSR, where TV propaganda was stating that everything is great while people had hard time finding food in store. Here’s the joke:

An old lady comes to a medical center saying that she needs to see an Ear-Eye specialist. The receptionist replied, “There is no such specialization in medicine. Why would you need such a doctor?” The old lady answered, “What I hear on the radio, I don’t see in the real life.”

In programming, we have similar situations quite often – you look at the code everything looks perfect, but it doesn’t work no matter how long you look at it. In such cases you should call a colleague simply saying “I got an Ear-Eye problem”. An extra pair of eyes usually helps. After looking at the monitor for half an hour, I realized that I got an Ear-Eye situation, but it was not a one piece of code, but required a two server setup so it was not a quick thing for explain to a colleague. Eventually, I fixed it myself and am happy to share my story with you.

I’ve been using the Java EE GlassFish 4.1 as an application server, and Open MQ 5.1 as a JMS provider. You can use Open MQ separately, but it’s conveniently bundled with GlassFish. While most of the JMS code samples show how to send/receive messages from Java EE clients using JNDI, it may give novice Java developers a false feeling that this is the only way to do messaging.

So I updated my old code samples to illustrate how to use JMS 2.0 goodies in standalone clients talking directly to Open MQ server. Started Open MQ from the command line with the imqbrokerd script, configured the queue, tested the sender and receiver and all worked as the doctor ordered (no, not that doctor). For those, who are not in the know, Open MQ runs on port 7676 by default. Here’s my standalone JMS sender:

public class DirectMessageSender{

public static void main(String[] args){

ConnectionFactory factory;

factory = new com.sun.messaging.ConnectionFactory();

try( JMSContext context = factory.createContext("admin","admin")){

factory.setProperty(ConnectionConfiguration.imqAddressList,

"mq://127.0.0.1:7676,mq://127.0.0.1:7676");

Destination ordersQueue = context.createQueue("TradingOrdersQueue");

JMSProducer producer = context.createProducer();

// Send msg to buy 200 shares of IBM at market price

producer.send(ordersQueue,"IBM 200 Mkt");

System.out.println("Placed an order to TradingOrdersQueue");

} catch (JMSException e){

System.out.println("Error: " + e.getMessage());

}

}

}

And this is the stand alone receiver:

public class DirectObjectMessageReceiver implements MessageListener{

ConnectionFactory factory = new com.sun.messaging.ConnectionFactory();

JMSConsumer consumer;

DirectObjectMessageReceiver(){

try( JMSContext context = factory.createContext("admin","admin")){

factory.setProperty(ConnectionConfiguration.imqAddressList(

"mq://127.0.0.1:7676,mq://127.0.0.1:7676");

Destination ordersQueue = context.createQueue("TradingOrdersQueue");

consumer = context.createConsumer(ordersQueue);

consumer.setMessageListener(this);

System.out.println("Listening to the TradingOrdersQueue...");

// Keep the program running - wait for messages

Thread.sleep(100000);

} catch (InterruptedException e){

System.out.println("Error: " + e.getMessage());

}

catch (JMSException e){

System.out.println("Error: " + e.getMessage());

}

}

public void onMessage(Message msg){

try{

System.out.println("Got the message from TradingOrdersQueue: " +

msg.getBody(Order.class));

System.out.println("\n === Here's what toString() on the message prints \n" + msg);

} catch (JMSException e){

System.err.println("JMSException: " + e.toString());

}

}

public static void main(String[] args){

new DirectObjectMessageReceiver();

}

}


As you see, the code is has several lines specific to Open MQ implementation, which is not great, but gives me a segway to explain the benefits of JNDI and resource injection. Then I explained how to map GlassFish JNDI queue name to a physical queue in the Open MQ server. So here’s the servlet that serves as a JMS sender, and the JNDI name OutgoingTradeOrders is mapped to a physical queue named TradingOrdersQueue.

@WebServlet("/MessageSenderServlet")

public class MessageSenderServlet extends HttpServlet {

@Resource(lookup ="java:comp/DefaultJMSConnectionFactory")  // JNDI name

ConnectionFactory factory;

@Resource(lookup = "OutgoingTradeOrders")  // JNDI name

Destination ordersQueue;

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException{

try( JMSContext context = factory.createContext("admin","admin")){

JMSProducer producer = context.createProducer();

// Send msg to buy 200 shares of IBM at market price

producer.send(ordersQueue,"IBM 200 Mkt");

System.out.println("Placed an order to OutgoingTradeOrders");

}

}

}


Got my Open MQ server running, then deployed the servlet and started GlassFish. The servlet obediently sent a message to the queue OutgoingTradeOrders. Basically, I wanted to implement the following workflow:

figure_30-10

The rest seemed to be easy – I wanted to run my standalone message receiver against the Open MQ server to prove that it’s getting messages from TradingOrdersQueue. Started the receiver, it printed “Listening to the TradingOrdersQueue…” and nothing else. Where is the message that the servlet sent? Is there something wrong with the queue names mapping? Started the Open MQ admin console – looks good, the TradingOrdersQueue is there. Started GlassFish Admin Tool – the OutgoingTradeOrders is properly mapped to TradingOrdersQueue.

Then I decided run the servlet again to send a second message to the queue. Maybe the first message got stuck somewhere and the second one would push it out? Nope, no miracles. Tested again the standalone sender and the receiver – work fine. But where are the servlet’s messages?

What would you do in this situation? Correct, it’s time to take a peek into the queue from the servlet’s code to see if is anybody there. Added QueueBrowser to the servlet, which properly showed me the messages sent by the servlet – they were sitting nicely next to each other in the OutgoingTradeOrders queue. Man!

Added the QueueBrowser to the standalone message receiver – the TradingOrdersQueue is empty. What next? I knew this was an Ear-Eye case, but still it would be nice if I could have blamed someone, wouldn’t it? Should I open a ticket at the GlassFish JIRA? Or is it an issue of Open MQ?

Later. I decided to walk my doggy (his name is Sammy) out. During the walk I was thinking about that case when two group of workers started building a tunnel from both sides of the river hoping to meet in the middle, but built two tunnels instead. When I came back, I decided to see if there is something fishy with the port numbers.

I have the only distribution of GlassFish which has the only subdirectory called mq, where the Open MQ software resides. So in both cases (imqbrokerd and GlassFish) I’d be starting the same instance of the Open MQ server, right? Wrong! While imqbrokerd starts it on port 7676, GlassFish start the embedded OpenMQ on port 27676, which is not written in their admin guides. If found a system variable JMS_PROVIDER_PORT deep inside in the GlassFish file glassfish/domains/domain1/config/domain.xml!

This was a situation with tho tunnels! The standalone clients were sending messages to the server running on port 7676, while the servlet was pumping messages to the Open MQ instance running on the port 27676! After changing the port from 277676 to 7676 everything started working!

I would have caught this bug a lot faster, but the GlassFish Admin console was showing me the physical queue TradingOrderQueue that I configured on the server running on port 7676! That’s why I was sure that I was working with the only instance of Open MQ. This is clearly a design flow in the GlassFish Admin Console – instead of showing the physical queues by actually connecting to the Open MQ server, they just read if from the config file.

Anyway, the Ear-Eye issue is resolved. That’s all folks.

Read the original blog post at http://yakovfain.com

Read the original blog entry...

More Stories By Yakov Fain

Yakov Fain is a Java Champion and a co-founder of the IT consultancy Farata Systems and the product company SuranceBay. He wrote a thousand blogs (http://yakovfain.com) and several books about software development. Yakov authored and co-authored such books as "Angular 2 Development with TypeScript", "Java 24-Hour Trainer", and "Enterprise Web Development". His Twitter tag is @yfain