JMS Expiration after it has been receive not working - glassfish

The title might be confusing but this is what I want to accomplish. I want to send a jms message from 1 ejb to another, the 2nd ejb has a message listener and this is now working properly. But I wanted the 1st ejb to create a temporary destination queue where the 2nd ejb would respond - this is also working properly.
My problem is in the 2nd ejb, it's calling a 3rd party web service that on some occasion would respond after a long time, and the temporary queue should expire on that time. But the problem is it doesn't according to java.net: http://java.net/projects/mq/lists/users/archive/2011-07/message/22
The message hasn't been delivered to a client and it expires -- in this case, the message is deleted when TTL is up.
The message is delivered to the JMS client (it's in-flight). Once this happens, since control is handed to the jms client, the broker cannot expire the message.
Finally, the jms client will check TTL just before it gives the message to the user application. If it's expired, we will not give it to the application and it will send a control message back to the broker indicating that the message was expired and not delivered.
So, it was received but no reply yet. Then on the time where it would write to the temporary queue it should already be expired but for some reason I was still able to write to the queue and I have the ff in my imq log:
1 messages not expired from destination jmsXXXQueue [Queue] because they have been delivered to client at time of the last expiration reaping
Is there another implementation where I can detect if the temporary queue is already expired? So that I can perform another set of action? Because my problem right now is ejb2 respond late and there is no more jms reader from ejb1 because it's already gone.

It works now, my solution was to wrap the 1st Stateless bean (the one where the first jms message originates) inside a bean managed transaction. See code below:
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
#LocalBean
public class MyBean {
public void startProcess() {
Destination replyQueue = send(jmsUtil, actionDTO);
responseDTO = readReply(jmsUtil, replyQueue, actionDTO);
jmsUtil.dispose();
}
public Destination send(JmsSessionUtil jmsUtil, SalesOrderActionDTO soDTO) {
try {
utx.begin();
jmsUtil.send(soDTO, null, 0L, 1,
Long.parseLong(configBean.getProperty("jms.payrequest.timetolive")), true);
utx.commit();
return jmsUtil.getReplyQueue();
} catch (Exception e) {
try {
utx.rollback();
} catch (Exception e1) {
}
}
return null;
}
public ResponseDTO readReply(JmsSessionUtil jmsUtil, Destination replyQueue,
SalesOrderActionDTO actionDTO) {
ResponseDTO responseDTO = null;
try {
utx.begin();
responseDTO = (ResponseDTO) jmsUtil.read(replyQueue);
if (responseDTO != null) {
//do some action
} else { // timeout
((TemporaryQueue) replyQueue).delete();
jmsUtil.dispose();
}
utx.commit();
return responseDTO;
} catch (Exception e) {
try {
utx.rollback();
} catch (Exception e1) {
}
}
return responseDTO;
}
}

Related

Axis2 web service stub failing

We have a website written in Java that makes a web service call. Recently, we have noticed that we are recieving a null response from the web service (The endpoint is a 3rd party not maintained by us).
I've tracked down the point at which our code is failing and it's in our stub. See the code below, the code is failing between the two System.out.println lines. My problem is that no exception is thrown, so I don't know why the _operationClient.execute(true); fails. Would anyone have any idea how I can go about solving this?
public SuggestXResponseE suggestX(SuggestXE suggestX0)
throws java.rmi.RemoteException {
org.apache.axis2.context.MessageContext _messageContext = null;
try {
org.apache.axis2.client.OperationClient _operationClient = _serviceClient.createClient(_operations[0].getName());
_operationClient.getOptions().setAction("http://www.test.com/service/suggestX");
_operationClient.getOptions().setExceptionToBeThrownOnSOAPFault(true);
addPropertyToOperationClient(_operationClient, org.apache.axis2.description.WSDL2Constants.ATTR_WHTTP_QUERY_PARAMETER_SEPARATOR, "&");
// create a message context
_messageContext = new org.apache.axis2.context.MessageContext();
// create SOAP envelope with that payload
org.apache.axiom.soap.SOAPEnvelope env = null;
env = toEnvelope(getFactory(_operationClient.getOptions().getSoapVersionURI()),
suggestX0,
optimizeContent(new javax.xml.namespace.QName("http://www.test.com/service",
"suggestX")));
//adding SOAP soap_headers
_serviceClient.addHeadersToEnvelope(env);
// set the message context with that soap envelope
_messageContext.setEnvelope(env);
// add the message contxt to the operation client
_operationClient.addMessageContext(_messageContext);
System.out.println("Log message 1");
//execute the operation client
_operationClient.execute(true);
System.out.println("Log message 2");
org.apache.axis2.context.MessageContext _returnMessageContext = _operationClient.getMessageContext(
org.apache.axis2.wsdl.WSDLConstants.MESSAGE_LABEL_IN_VALUE);
org.apache.axiom.soap.SOAPEnvelope _returnEnv = _returnMessageContext.getEnvelope();
java.lang.Object object = fromOM(
_returnEnv.getBody().getFirstElement(),
SuggestXResponseE.class,
getEnvelopeNamespaces(_returnEnv));
return (SuggestXResponseE) object;
} catch (org.apache.axis2.AxisFault f) {
// Handle exception.
}
finally {
_messageContext.getTransportOut().getSender().cleanup(_messageContext);
}
}
System.out.println("Log message 1");
//execute the operation client
_operationClient.execute(true);
System.out.println("Log message 2");
If you're getting the first log message but not the second one, then one of two things is happening:
System.exit() is being called somewhere within _operationClient.execute(). You'd recognize this by the fact the process exits.
More likely, _operationClient.execute() is throwing something.
You say it's not throwing an exception, but it could be throwing an Error or some other kind of Throwable. It's not normally advised to catch non-Exception throwables, but you could add some code to do it temporarily:
try {
_operationClient.execute(true);
} catch (Throwable t) {
log.error(t);
throw t;
}
You might find that you're getting an OutOfMemoryError or a NoClassDefFoundError because some jar is missing from your deployment, for example.

RabbitMQ - Non Blocking Consumer with Manual Acknowledgement

I'm just starting to learn RabbitMQ so forgive me if my question is very basic.
My problem is actually the same with the one posted here:
RabbitMQ - Does one consumer block the other consumers of the same queue?
However, upon investigation, i found out that manual acknowledgement prevents other consumers from getting a message from the queue - blocking state. I would like to know how can I prevent it. Below is my code snippet.
...
var message = receiver.ReadMessage();
Console.WriteLine("Received: {0}", message);
// simulate processing
System.Threading.Thread.Sleep(8000);
receiver.Acknowledge();
public string ReadMessage()
{
bool autoAck = false;
Consumer = new QueueingBasicConsumer(Model);
Model.BasicConsume(QueueName, autoAck, Consumer);
_ea = (BasicDeliverEventArgs)Consumer.Queue.Dequeue();
return Encoding.ASCII.GetString(_ea.Body);
}
public void Acknowledge()
{
Model.BasicAck(_ea.DeliveryTag, false);
}
I modify how I get messages from the queue and it seems blocking issue was fixed. Below is my code.
public string ReadOneAtTime()
{
Consumer = new QueueingBasicConsumer(Model);
var result = Model.BasicGet(QueueName, false);
if (result == null) return null;
DeliveryTag = result.DeliveryTag;
return Encoding.ASCII.GetString(result.Body);
}
public void Reject()
{
Model.BasicReject(DeliveryTag, true);
}
public void Acknowledge()
{
Model.BasicAck(DeliveryTag, false);
}
Going back to my original question, I added the QOS and noticed that other consumers can now get messages. However some are left unacknowledged and my program seems to hangup. Code changes are below:
public string ReadMessage()
{
Model.BasicQos(0, 1, false); // control prefetch
bool autoAck = false;
Consumer = new QueueingBasicConsumer(Model);
Model.BasicConsume(QueueName, autoAck, Consumer);
_ea = Consumer.Queue.Dequeue();
return Encoding.ASCII.GetString(_ea.Body);
}
public void AckConsume()
{
Model.BasicAck(_ea.DeliveryTag, false);
}
In Program.cs
private static void Consume(Receiver receiver)
{
int counter = 0;
while (true)
{
var message = receiver.ReadMessage();
if (message == null)
{
Console.WriteLine("NO message received.");
break;
}
else
{
counter++;
Console.WriteLine("Received: {0}", message);
receiver.AckConsume();
}
}
Console.WriteLine("Total message received {0}", counter);
}
I appreciate any comments and suggestions. Thanks!
Well, the rabbit provides infrastructure where one consumer can't lock/block other message consumer working with the same queue.
The behavior you faced with can be a result of couple of following issues:
The fact that you are not using auto ack mode on the channel leads you to situation where one consumer took the message and still didn't send approval (basic ack), meaning that the computation is still in progress and there is a chance that the consumer will fail to process this message and it should be kept in rabbit queue to prevent message loss (the total amount of messages will not change in management consule). During this period (from getting message to client code and till sending explicit acknowledge) the message is marked as being used by specific client and is not available to other consumers. However this doesn't prevent other consumers from taking other messages from the queue, if there are more mossages to take.
IMPORTANT: to prevent message loss with manual acknowledge make sure
to close the channel or sending nack in case of processing fault, to
prevent situation where your application took the message from queue,
failed to process it, removed from queue, and lost the message.
Another reason why other consumers can't work with the same queue is QOS - parameter of the channel where you declare how many messages should be pushed to client cache to improve dequeue operation latency (working with local cache). Your code example lackst this part of code, so I am just guessing. In case like this the QOS can be so big that there are all messages on server marked as belonging to one client and no other client can take any of those, exactly like with manual ack I've already described.
Hope this helps.

test if jms listener is working

i want to test if the JMS listener is working !
to do that i want to test if the Queue size do not change for more than 5 seconds that means that the listener is not working
what should i add to my code please
try {
if ((msgIdMap.contains(tm.getJMSMessageID())) || !(message instanceof TextMessage)) {
System.out.println("\tListener not working !");
} else {
process((TextMessage) message);
}
If the listener is designed, coded and configured correctly it should be working unless there's a problem with the provider. If there is a problem with the provider, the client portion of the provider should detect it and call your ExceptionListener, if it is defined.
So, I would provide an ExceptionListener, by having your class implement the ExceptionListener:
public class MyJMSClass implements javax.jms.ExceptionListener {
then set the listener on the connection to this class:
connection.setExceptionListener(this);
then provide the recovery code:
public void onException(JMSException jmse) {
log.error("JMS exception has occured.. ", jmse);
// handle exception appropriately, perhaps by attempting to reconnect
}

How to make an Attended call transfer with UCMA

I'm struggling with making a call transfer in a UMCA IVR app I've built. This is not using Lync.
Essentially, I have an established call from an outside user and as part of the IVR application, they select an option to be transferred. This transfer is to a configured outside number (ie: Our Live Operator). What I want to do is transfer the original caller to the outside number, and if a valid transfer is established, I want to terminate the original call. If the transfer isn't established, I want to send control back to the IVR application to handle this gracefully.
My problem is my EndTransferCall doesn't get hit when the transfer is established. I would have expected it to hit, set my AutoResetEvent and return a True, and then in my application I can disconnect the original call. Can somebody tell me what I'm missing here?
_call is an established AudioVideoCall. My application calls the Transfer method
private AutoResetEvent _waitForTransferComplete = new AutoResetEvent(false);
public override bool Transfer(string number, int retries = 3)
{
var success = false;
var attempt = 0;
CallTransferOptions transferOptions = new CallTransferOptions(CallTransferType.Attended);
while ((attempt < retries) && (success == false))
{
try
{
attempt++;
_call.BeginTransfer(number, transferOptions, EndTransferCall, null);
// Wait for the transfer to complete
_waitForTransferComplete.WaitOne();
success = true;
}
catch (Exception)
{
//TODO: Log that the transfer failed
//TODO: Find out what exceptions get thrown and catch the specific ones
}
}
return success;
}
private void EndTransferCall(IAsyncResult ar)
{
try
{
_call.EndTransfer(ar);
}
catch (OperationFailureException opFailEx)
{
Console.WriteLine(opFailEx.ToString());
}
catch (RealTimeException realTimeEx)
{
Console.WriteLine(realTimeEx.ToString());
}
finally
{
_waitForTransferComplete.Set();
}
}
Is the behavior the same if you don't use the _waitForTransferComplete object? You shouldn't need it - it should be fine that the method ends, the event will still be raised. If you're forcing synchronous behavoir in order to fit in with the rest of the application though, try it like this:
_call.EndTransfer(
_call.BeginTransfer (number,transferOptions,null,null)
);
I'm just wondering if the waiting like that causes a problem if running on a single thread or something...

How can I send a notification message from server to all clients in WCF (broadcast you can say)?

I want to send notification message every second from net tcp WCF service to all clients,
Broadcast you can say?
After the helpful answers
I wrote the following method that will send notifications (heartbeat) to all connected users
foreach (IHeartBeatCallback callback in subscribers)
{
ThreadPool.QueueUserWorkItem(delegate(object state)
{
ICommunicationObject communicationCallback = (ICommunicationObject)callback;
if (communicationCallback.State == CommunicationState.Opened)
{
try
{
callback.OnSendHeartBeat(_heartbeatInfo.message, _heartbeatInfo.marketstart,_heartbeatInfo.marketend, _heartbeatInfo.isrunning, DateTime.Now);
}
catch (CommunicationObjectAbortedException)
{
Logger.Log(LogType.Info, "BroadCast", "User aborted");
communicationCallback.Abort();
}
catch (TimeoutException)
{
Logger.Log(LogType.Info, "BroadCast", "User timeout");
communicationCallback.Abort();
}
catch (Exception ex)
{
Logger.Log(LogType.Error, "BroadCast", "Exception " + ex.Message + "\n" + ex.StackTrace);
communicationCallback.Abort();
}
}
else
{
DeletionList.Add(callback);
}
}
);
}
I am worried about calling the callback method as the client may close his application, but I handled it using the try catch, decrease the timeout, and send the broad cast in parallel, so is that sufficient?
You'll need to setup a callback service; I wrote a simple beginners guide a while back
In order to do that, you need to create and mantain a list of all connected clients (the general practice to fo this is creating LogIn and LogOut methods to create and manage a list of object representing your clients incuding their CallbackContext).
Then, with a System.Time.Timers, you can loop through the connected client list and send the notification.
Tip. this method could also act as a Keep-Alive or Hear-Beat method (if this isn't it's purpose by design) by adding the possiblity to remove clients from your list if the service cannot send the callback to them.