We have a unique problem.
We are using message driven beans to get messages off IBM MQ series queue and we need to send this message on to another system (say system A) asynchronously (i.e this system has its own input queue). We need to wait for 45 sec and if we don't get a response from system A, we need to send a message to yet another system (say System B)asynchronously stating that system A failed to respond. We have no way of achieving this synchronous behaviour using the async messaging protocol. My specific question is as follows:
Can we spawn a new thread in the Message driven bean?
Specifically can I do this?
public void onMessage( Message m )
//Do some calculations and send the message to system A
//Save the tran into a table and set the expiration
//flag to a N.
//Spawn a new thread that waits for 45 secs...
new Thread( new TimeManager() ).start();
The TimeManager waits for the designated period and later, wakes up and sends the no response message to System B after looking at the expiration flag that was set in the MDB. If indeed System A responds, it sets the expired flag in the table to a Y and sends the response. Is this a good way of getting the desired result?
P.S I did try to run this bean in BEA Weblogic and it seemed to work just fine.. it creates a new thread for each message we put in the input queue. I remember someone telling me that we can't spawn threads in EJBs...How is it working then?
Appreciate your feedback
It's not "you can't use threads", it's "you shouldn't use threads".
In other words, it's not guaranteed to work even though most often it's not a problem to start your own threads.
BEA is recommending the use of the JMX API (javax.management.timer.*( instead of the deprecated WebLogic Time Services but I haven't used it (neither the JMX timer API nor the WebLogic proprietary stuff).
The chapter 24 of the EJB spec recommends several programming restrictions such as using threads, IO package, perform I/O using the AWT and so on. If your app server seems to work today, it may not in future; your code may not be portable cross platforms.
It's better to create a RMI server that resides out side of the EJB container. Have this server to communicate with System A or System B. Of course with the BEA server the RMI process can be configured as a start up process to ensure its availability.
If you decid not go with the RMI solution, at least try to use the java.util.Timer class where you don't have to directly create any threads.
EJB soultion tends to reduce software complexities yet limits the programmer's ability in certain situations.
Thanks a lot for the input. I had a couple of questions regarding both the approaches you guys have given...
1. Using the JMX timer api. I did some research on this and I could not find out whether Weblogic 7.0 supports J2ee 1.4 and ejb 2.1 or not. Is there any patch we need to install to get the factory 7.0 version up to speed?
2. Regarding the RMI server approach:
If we were to have an external RMI server, and let the MDB make an RMI call to it, this would be a blocking call, that makes the MDB's onMessage() method block till it gets a response right? Is this a good option? If, for some reason, the RMI server fails to respond quickly, the MDBs will just be waiting doing nothing.. Does this create scalability problems? Could you please give me some more input into this.. I really want to pursue this path and see how it performs. Also, if we use the java.util.Timer, does it make a difference, because internally, it creates a new thread anyway right? Appreciate your feedback Tony.
You don't need to block at all. YOu call the RMI server.foo() then foo() starts a thread to communicate with System A. Once the thread is started it returns.
Hope this helps.
You say that both System A and B accept input in Queues. Why not let them send their response to a Queue as well? The way you simulate a synchronous call using asynchronous MQ is that, when the MDB puts the request message to, say System A's input Queue, it should create a Temp Queue and specify this Queue as the JMS's ReplyToQ. With the receive(time)call, you can wait on the temp Q you just created for the 45 seconds -- just say receive(45000L). This way, if you don't receive a message within 45 seconds, the blocked receive() call will return empty and you can proceed to do the same with System B.
If you know MQ, then you probably know MA88 SupportPac, which provides two layers to make calls from Java. The MQ Classes for Java operate on a layer above the native MQ and the MQ Classes for JMS operate just above the MQ Classes for Java. I am not a programmer and so, pl. double-check the syntax with the "MQ Using Java" redbook @ www.redbooks.ibm.com
Hey Srini -
Your idea is great... but the only problem we have is that the other systems, A and B are legacy and the managers who maintain them are very bull-headed.. We can't expect them to change the way these work. Yes both systems A and B have input and output queues and they have hard-coded their response to go the respective queues.. They will not change the code to send the reply to a temporary queue (which we could pass them, via the reply to in the JMS message). I will talk to my other team members about the other support you have mentioned... Thanks for your feedback and please do update me if you come up with something else.
Since the systems have output Q, you may go directly to the output Q and do a search to find a message with a CorrelationID matching your MessageID.
MQ will take your message ID and populate the Corr ID in the reply. You have to make sure A & B do that...