JMS request/reply from an EJB

This blog has moved to http://frankkieviet.blogspot.com

Comments:

Frank, Your blog is a wonderful source of information on JCA, JMS and up to a certain extent JTA. Please continue posting great articles like these ones as it's hard to find good sources of information on those subjects. I can't wait to read more on this !

Posted by Ludovic Orban on August 26, 2006 at 02:15 AM PDT #

Thank you for your kind feedback! Let me know what topics you would be interested in.

Posted by Frank Kieviet on August 26, 2006 at 04:48 PM PDT #

Very Good!

Posted by Luo Shifei on October 13, 2006 at 12:39 PM PDT #

Hi Nice article. In most aplications we have requirement of sending acknowledge/acceptance and confrmation/rejection messages back to sender application. So is using request/reply i/e synchronous message communication a nice option when volume of messages to be handled is really high. Also what if there is some error in receiver process/ infrastructure issue etc. What would be exception handing approach in this case. thx mansih

Posted by manish dhall on November 12, 2006 at 01:59 PM PST #

Hi Manish Dhall,

Request/reply and high load situations. It depends on the situation and circumstances that you're working in if request/reply may give you a performance benefit over synchronous calls.

There are some situations where request/reply might give you a performance benefit. For example, if in your code you would need data from 10 services, you could send requests to these 10 services and wait for the result; this would be faster (lower latency) than to fire off each request and wait for the response sequentially.

However, on the other hand, you are occupying a thread while waiting for a response. So if you're only sending a request to one service, you might see a performance degradation due to the overhead of JMS.

If the responder is offline, the requestor would be waiting indefinetely or until timeout. If the requestor cannot handle the reply, the whole transaction would likely be rolled back and reprocessed.

Some of these problems can be circumvented using a different programming model. If the requestor would not block until the response comes in but return immediately, and if the response would be processed by another MDB, there would not be any blocking threads. The MDB would have to be able to resurrect the state that was present when the request was sent. This kind of asynchronous programming model may be better implemented using other tools, e.g. using BPEL.

Posted by Frank Kieviet on November 13, 2006 at 03:35 AM PST #

Hi Frank, Your blog really showed some intresting concepts regarding transaction control in EJBs and JMS. But however, when I try to code in such a fashion, the response message always shows up a null!!! I tried both the CMP and the BMP approach. The only difference in my code is that I am not using a temporary queue but I am using a server administered queue. I double checked whether the message is sent on the commit(it does) and the MDB associated with the first queue even processes the message. After the processing of the message, the MDB itself populates a response queue. My ejb is actually waiting for this response queue and it always times out. I have attached the code. I would appreciate your help on this.Thanks-Aditya public void sendRecieve() { try { String connectionInputFactoryName = "java:comp/env/jms/costingHighLevelInputQueueCF"; String inputQueueName = "Java:comp/env/jms/costingHighLevelInputQueue"; String outputQueueName = "java:comp/env/jms/costingHighLevelOutputQueue"; Queue inputQueue = null; Queue outputQueue = null; QueueSender queueSender = null; InitialContext initialContext = new InitialContext(); mySessionCtx.getUserTransaction().begin(); queueConnectionFactory = (QueueConnectionFactory) PortableRemoteObject.narrow(initialContext.lookup(connectionInputFactoryName), QueueConnectionFactory.class); queueConnection = queueConnectionFactory.createQueueConnection(); queueSession = queueConnection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE); inputQueue = (Queue) PortableRemoteObject.narrow(initialContext.lookup(inputQueueName), Queue.class); ReviewDTO reviewDTO = new ReviewDTO(); reviewDTO.setAgentName("Aditya Narayan Barimar"); queueSender = queueSession.createSender(inputQueue); Message theMessage = queueSession.createObjectMessage(reviewDTO); String correlationId = Long.toString(System.currentTimeMillis()); theMessage.setJMSCorrelationID(correlationId); queueSender.send(theMessage); mySessionCtx.getUserTransaction().commit(); mySessionCtx.getUserTransaction().begin(); outputQueue = (Queue) PortableRemoteObject.narrow(initialContext.lookup(outputQueueName), Queue.class); QueueReceiver queueReceiver = queueSession.createReceiver(outputQueue); Message reply = queueReceiver.receive(5000); System.out.println("reply message is: " + reply); mySessionCtx.getUserTransaction().commit(); } catch (Throwable t) { t.printStackTrace(); } finally { if (queueConnection != null) { try { queueSession.close(); queueConnection.close(); System.out.println("Queue connection has been closed"); } catch (Throwable t) { t.printStackTrace(); } } } }

Posted by Aditya on November 16, 2006 at 01:46 PM PST #

Hi Aditya,

The first thing I always check when I get null messages if I called <tt>connection.start()</tt>: I've made that mistake so often it's not funny anymore.

Did you call <tt>connection.start()</tt>?

Frank

Posted by Frank Kieviet on November 16, 2006 at 02:01 PM PST #

Hi Frank, That was quick!!Thanks for your response and you were spot on!! I had not called connection.start() when I am using the UserTransaction!Now, I am getting a response message!!But do you think I must call the same when I am using container managed transaction? Any other pitfalls that i must look out for in case of CMP? Because my team out here is quite apprehensive of using user transactions in a bean and would definitely like to port the application to a CMP bean. Again, Thanks a million for your help!!

Posted by Aditya on November 16, 2006 at 04:53 PM PST #

Hi Aditya,

You also need to call <font face="courier new,courier,monospace">Connection.start()</font> in a CMT bean.

When you move this code to CMT, you will have to do receive() of the message in a separate bean instance, calling a method that was declared with transaction=<font face="courier new,courier,monospace">REQUIRES_NEW</font>. This is more complicated than using BMT, so if you have the choice between CMT and BMT, I would choose BMT. You don't always have the choice: e.g. if your code resides in an MDB, you would not want to change the semantics of the onMessage() method just because you want to do a request/reply from it.

Frank

&nbsp;

Posted by Frank Kieviet on November 17, 2006 at 08:16 AM PST #

Hi....that was a nice article and like you said...something which looks to be trivial turns out to be a lot more complicated.I have one question pertaining to the request reply mode mentioned above.Like mentioned, when we send a message, we invoke it as a new transaction during which the main transaction is suspended. What would happen, if on return to the main transaction (after the message has been sent to the queue) an exception occurs in the main transaction? Will the message be reposted or this has to be taken care of programatically?? Since sending of the message is done in a seperate transaction, probably the message is not reposted if an exception occurs in the main transaction?

Posted by Sid on December 04, 2006 at 12:56 PM PST #

Hi Sid,

If an exception happens in the main transaction, that transaction will be rolled back. If that results in a retry depends on what called the code: if it was called in an MDB, the JMS server will generally retry to send the message. In that case the request will be sent again.

What happened to the first reply? Although the main transaction was rolled back, the request was sent to the request queue (committed), and a reply was likely sent to the reply queue. Probably you would use a temporary queue for the reply queue. The temporary queue gets deleted automatically when the connection is closed, so effectively the reply is being discarded without being processed.

Frank&nbsp;

Posted by Frank Kieviet on December 04, 2006 at 02:14 PM PST #

Hello First, thanks for the explanation, I had lots of trouble with this issue. I found an other way to do it (although it requires application server specific code): using the TransactionManager to suspend the transaction before creating the session and resuming right after it: QueueConnection c = ...; TransactionManager tm = ... (AS-specific); Transaction t = tm.suspend(); QueueSession s = c.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); tm.resume(t); ...

Posted by Martin on December 06, 2006 at 12:03 AM PST #

> c.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
In fact, these arguments are ignored, so they have no effect whatsoever.

in Jboss it actually works and the message is sent before EJB transaction ended.
Also using java:/Jms to get Connection factory instead of java:/JmsXA might help:
@Resource(mappedName = "java:/Jms")
ConnectionFactory factory;

Nice blog by the way.

Posted by Vlad E on January 16, 2008 at 11:51 PM PST #

Hi Frank,

I know this is an old post but I am hoping that you will be able to help me.

I am using Glassfish V2U2 and want to use a request/reply scenario from my MessageDrivenBean (MDB).

From what your blog says I need to change the MDB from using Container Managed Transactions to Bean Managed Transactions. Is this correct? I would be very grateful if you could tell me how I can do this.

Best wishes,
Dan

Posted by Dan Dubois on July 13, 2008 at 07:15 AM PDT #

Re Dan:

Changing the transaction attribute of the MDB has other ramifications, and you typically don't want to do that just to be able to do a request/reply.

There are two options: you can create a SLSB with the TransactionAttribute set to REQUIRES_NEW; in this SLSB you would send your request.

The other option is to use a different connection pool for sending the request. This pool would be setup in GlassFish with transaction-support = NoTransaction. This works fine with the JMSJCA resource adapter; I have not checked this with the resource adapters that come with GlassFish.

You can find JMSJCA at http://jmsjca.dev.java.net.

Frank

Posted by Frank Kieviet on July 14, 2008 at 02:46 AM PDT #

Hi Frank,

Thanks for the quick reply. I realize this is not a help forum so please feel free not to reply. :-) I thought your first solution, using a SLSB with REQUIRES_NEW to be the most elegant. Unfortunately I get the following error after my onMessage method has run through:

prepareTransaction (XA) on JMSService:jmsdirect failed for connectionId:1497195242996848640 due to TxID is already in use.
JTS5031: Exception [java.lang.RuntimeException: javax.transaction.xa.XAException] on Resource [prepare] operation.

I then decided to just delegate everything from onMessage to a BMT EJB and follow your blog's example, but still the same exception.

There seems to be very little on the net in the way of support for these types of problems. Your blog entry seems to be the only decent thing on the subject right now and it is from 2006!

Best wishes,
Dan

Posted by Dan Dubois on July 14, 2008 at 11:18 AM PDT #

Re Dan:

You're right, having the MDB delegate to a BMT SLSB is also an option, and perhaps even a better option although it doesn't make that much difference.

I'm suspect that the error that you're getting is because you're passing the connection that you obtained in the MDB to the SLSB? This is something you need to avoid: you need to acquire a brand new connection in the SLSB.

The reason for this is that the MDB's connection is enlisted in the MDB's transaction. When you acquire a new connection in the SLSB, this new connection is enlisted in the SLSB's transaction.

It's really not much code (perhaps a dozen statements), but you have to be very careful that all the statements are in the right order and point to the right objects.

Let me know if, after checking that you're using a separate connection for sending, you still have a problem. I can send you a code snippet that illustrates the solution.

Frank

Posted by Frank Kieviet on July 14, 2008 at 03:56 PM PDT #

Hi Frank,

Again, thank you very much for your response. I would be very grateful for a code snippet. I have created a thread http://forum.java.sun.com/message.jspa?messageID=10338789 with the same topic as this but it also includes my code in question (nicely formatted). Would you be able to post the snippet there for continuity?

Best wishes,
Dan

Posted by Dan Dubois on July 15, 2008 at 01:24 AM PDT #

Hi Frank,

Are you still able to provide the code snippet? The thread mentioned above seems to have died out without anyone providing a proper solution.

Best wishes,
Dan

Posted by Dan Dubois on July 24, 2008 at 02:20 PM PDT #

Hi Frank,

Could you please send the code snippet for using BMT SLSB from CMT MDB.

Thanks & Regards,
Pankaj

Posted by pankaj on August 28, 2008 at 12:21 AM PDT #

Hi Frank,

That was a great article and very informative.I am trying to run a request/reply code in Glassfish.

One client is a Servlet which sends a message to the MDB (other client) and also waits for the response using receive(timeout) . I am using temporaryQueue to implement it.

But is doesnot work . The servlet gets null message or sometimes it timesout.
Also Glassfish is highly unreliable. Sometimes is throws error that Queue could not be injected (I am using Annotations ) .

Can you send me some working example of Request/Reply ? I am not using any transaction in MDB . I am very new to JMS so kindly ignore if I have done wrong somewhere.

Posted by LSK on August 28, 2008 at 03:13 AM PDT #

Hi, I got the same problem with a servlet where I connect to a topic via JMS.
Do you acciddentally know how to resolve the transaction-issue within a servlet ?
Thnak you. Regards AgeBee

Posted by AgeBee on September 04, 2008 at 09:46 PM PDT #

Hi Frank,

It seems a very good article.
But, I did not get the much things from that. It's because of my lack of understanding.

I did not get the following sentenses....Can you explain me those. It will be really great.

1) Applications can communicate with this server using a client runtime....
What this means? what is a client runtime?
2) What is meaning of the resouce adapter?

Again, please explain me...
Thanks,
Rahul

Posted by Rahul on September 28, 2008 at 09:38 AM PDT #

I have received several similar emails like this one.

Posted by links london on December 01, 2009 at 09:49 AM PST #

Post a Comment:
Comments are closed for this entry.
About

fkieviet

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today