IBM Websphere MQ displays javax.jms.TextMessage as <RFH > - java

I am sending message from Java Code to Websphere MQ Server and when I am reading the same message on MQ server, it's displaying as:
message<RFH >
Below is the code sending the message to MQ server:
private void sendMessage() throws Exception {
ConnectionFactory cf1 = (ConnectionFactory) new InitialContext().lookup("java:comp/env/jms/wmqCF");
// Lookup Queue resource from JNDI
Queue queue = (Queue) new InitialContext().lookup("java:comp/env/jms/wmqQ1");
Connection con = cf1.createConnection();
// start the connection to receive message
con.start();
// create a queue session to send a message
Session sessionSender = con.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
MessageProducer send = sessionSender.createProducer(queue);
TextMessage msg = sessionSender.createTextMessage("Liberty Sample Message");
// send a sample message
send.send(msg);
if (con != null)
con.close();
System.out.println("Send Message Completed");
}
Expected to be displayed as: Liberty Sample Message.
Any idea, what I am missing here?
Thanks.

And if you retrieve the message with another JMS program then the message data will be "Liberty Sample Message".
You are mixing JMS and non-JMS program types.
.lookup("java:comp/env/jms/wmqQ1");
Set the 'TARGCLIENT' attribute to MQ. i.e. TARGCLIENT(MQ)
Then the message data will not have the RFH2 header.

Setting the targetClient="MQ" as a property of jmsQueue works.
Below is the configuration change in server.xml of WLP:
<jmsQueue id="jms/queue1" jndiName="jms/wmqQ1">
<properties.wmqJms baseQueueManagerName="QMA" baseQueueName="QUEUE1" targetClient="MQ"/>
</jmsQueue>

Related

RabbitMQ not failing send when messages are rejected due to queue size

I am using RMQ and it's JMS client to publish messages to RMQ (this is a requirement i have, I can't use their java client instead of JMS client).
So, basically I do this:
RMQConnectionFactory factory = new RMQConnectionFactory() ;
factory.setUsername(props.getProperty("rmq.username"));
factory.setPassword(props.getProperty("rmq.password"));
factory.setHost(props.getProperty("rmq.host"));
factory.setVirtualHost(props.getProperty("rmq.virtualHost"));
factory.setPort(Integer.parseInt(props.getProperty("rmq.port")));
Connection connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
String queueName = managerProps.getProperty("rmq.queue.name");
Queue queue = session.createQueue(queueName);
producer = session.createProducer(queue);
TextMessage msg = session.createTextMessage(text);
msg.setText(text);
producer.send(msg);
I have a policy set up on RMQ overflow: reject-publish, so if it's over the limit RMQ is supposed to send a nack when the queue is full, but I don't seem to get it.
The question is - how do I determine if the message was rejected? I assume the producer.send(msg) to be synchronous and throw exception if the message is not published, but I don't get any exceptions, it just looks like everything got published.
JMS spec has a send(msg, CompletionListener) with a listener with two methods onCompletion and onException, but it doesn't look like RMQ JMS client implemented this method.
Is there another way to make sure that message made it through?
RabbitMQ use Publisher Confirms to guarantee that a message isn't lost, so if your Queue overflow behavior is reject-publish, the confirm channel will got a nack. It is also contains in many AMQP client.
But in JMS client, I have check the code in rabbitmq-jms-client, and no send implementaion contains CompletionListener. So if you want to enjoy reliable publish, please use AMQP client.
I did some digging, the CompletionListener is part of JMS 2.0 and RMQ only implements JMS 1.1, that's the reason it's not there.
But it looks like I can do something with transactions. I would need to change the code like this:
RMQConnectionFactory factory = new RMQConnectionFactory() ;
// ... skipping the code here
connection.start();
// set session to be transacted
session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
String queueName = managerProps.getProperty("rmq.queue.name");
Queue queue = session.createQueue(queueName);
producer = session.createProducer(queue);
TextMessage msg = session.createTextMessage(text);
msg.setText(text);
producer.send(msg);
// commit transaction
session.commit();
This will work if the queue is not full, but will throw an exception after a rejected message with this:
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method(reply-code=406, reply-text=PRECONDITION_FAILED - partial tx completion, class-id=90, method-id=20)
I can then catch the exception and do what I need to do to resend/save the message.

How to set Persistence to JMS client?

I set up a connection with Weblogic IBM Webpsphere MQ through JMS with using a secure channel using SSL.
My application on Weblogic received message from MQ.
Sending answer to reply queue.
The response header is present MQMD, it fills java. In parameter Persistence JMS send value "1". Other system need to received value "0" at Persistence. How to set this parameter to java?
I guess that parameter is javax.jms.deliverymode. But how to set it i don't know.
Anyway thank you for help.
The corresponding property on JMS is the delivery mode (Int parameter to be set) to set Persistent and non persistent messages.
You can refer this URL from IBM for details
You should try like this:
public String sendMessage(ConnectionFactory connectionFactory,
Destination destination,
Destination jmsReplyTo,
CorrelationType correlationType,
CallOptions<String> callOptions,
String rqUid,
JMSAbstract transport) throws JMSException {
Connection connection = null;
Session session = null;
MessageProducer producer = null;
try {
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(destination);
// Set JMS DeliverMode (1/2)
producer.setDeliveryMode(1);
// create message
Message message = createTextMessage(session, jmsReplyTo, correlationType, callOptions, rqUid, transport);
// send message
producer.send(message);
return correlationType.getCorrelationId(message);
} finally {
closeResource(connection, session, null, producer, rqUid);
}
}
It`s just a java example. Also you can set persistence flag in Queue configuration in IBM WebSphere. I mean MQQueue have method setPersistence. If you using IBM java objects in your project, you can set persistence by calling that method:
MQQueue mqQueue = new MQQueue("QueueName");
mqQueue.setPersistence(1);
I The answer of 0x5a4d is ok but better to use this like IBM best practices
//Persistentmode = 1
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
//Persistentmode = 2
producer.setDeliveryMode(DeliveryMode.PERSISTENT);

IBM MQ failure to send/receive all JMS Messages

I am using IBM MQ to produce messages while receiving it through a consumer on my client. To create the connection I'm using JmsConnectionFactory, along with provided properties to set up the connection with the server. So from what I understand is, as the consumer the only way to recognize the messages produced by the server is through the onMessage call. I'm currently testing this by creating a local producer and local consumer and assuring that every message sent by the producer is received by the consumer.
I'm running into the following problems:
I'm not receiving all messages produced.
Depending on the size of the message, more of them are received if they are smaller.
Here is code for the creation of the producer:
JmsConnectionFactory cf = ff.createConnectionFactory();
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, qm.getHost());
int port = ###;
cf.setIntProperty(WMQConstants.WMQ_PORT, port);
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, qm.getChannel());
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, qm.getQueueManagerName());
Connection connection = cf.createConnection(qm.getUser().getUsername(), qm.getUser().getPassword());
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(qm.getDestinationName());
LOG.debug("Destination Created at " +qm.getDestinationName());
msgSender = session.createProducer(destination);
msgSender.setDeliveryMode(DeliveryMode.PERSISTENT);
And this is how the producer is sending messages:
/**
* msgSender is the MessageProducer object
**/
private void produceMessages(int numOfMessages) throws JMSException, InterruptedException {
for (int i = 0; i < numOfMessages; i++) {
String text = "Message #" +i;
TextMessage message = session.createTextMessage(text);
msgSender.send(message);
}
}
On the consumer side, I am simply printing received messages and verifying visually:
#Override
public void onMessage(Message m) {
System.out.println(((TextMessage)m).getText());
}
I am not fully familiar with how IBM MQ works. Could the reason for the missing messages reside on the MQ simply ignoring messages that are produced before a message is fully sent?
I would say the issue is residing on your consumer side, rather than your simulated producer. Your message producer should be sending messages to MQ just fine, but multiple consumers are probably competing to retrieve these messages from the connection you have set up (given the same queue manager properties). So unless no one else is trying to consume from your IBM MQ, you're going to be expected to miss some messages.
You should use other method of send(Message m, CompletionListener l) to send new messages only after completion.
And if you use "Best Effort", it still will lose messages. You can try "Express" instead.

Cannot receive embedded ActiveMQ statistics message

I am trying to get subscription statistics for my topic from embedded ActiveMQ through my JUnit test. I am able to subscribe to that topic, send a message to that topic and am able to receive that message in my listener/subscriber.
However, when I try to get statistics from that ActiveMQ, the consumer receive times out. And if I don't add the "receiveTimeout" than the consumer waits indefinitely for the message. Here is my code for the statistics:
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");
connectionFactory.setStatsEnabled(true);
Connection connection = connectionFactory.createConnection();
connection.setClientID(format("ActiveMqStatistics-%s", System.nanoTime()));
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue replyTo = session.createTemporaryQueue();
MessageConsumer consumer = session.createConsumer(replyTo);
String queueName = "ActiveMQ.Statistics.Subscription";
Queue testQueue = session.createQueue(queueName);
MessageProducer producer = session.createProducer(testQueue);
Message msg = session.createMessage();
msg.setJMSReplyTo(replyTo);
producer.send(msg);
System.out.println("Statistics request sent. Waiting to receive reply...");
long receiveTimeout = 5000L;
MapMessage reply = (MapMessage) consumer.receive(receiveTimeout);
assertNotNull(reply);
for (Enumeration e = reply.getMapNames();e.hasMoreElements();) {
String name = e.nextElement().toString();
System.out.println(name + "=" + reply.getObject(name));
}
connection.close();
I get assertion failure because the "reply" is null.
Any ideas?
I order for this to work you need to create a Broker instance that has the Statistics Broker plugin installed, it is not out of the box.
In the XML configuration you can enable it as follows:
<broker ...>
<plugins>
<statisticsBrokerPlugin/>
</plugins>
</broker>
Or in a unit test you might create an in VM broker using something similar to the following code.
protected BrokerService createBroker() throws Exception {
BrokerService answer = new BrokerService();
BrokerPlugin[] plugins = new BrokerPlugin[1];
plugins[0] = new StatisticsBrokerPlugin();
answer.setPlugins(plugins);
answer.setDeleteAllMessagesOnStartup(true);
answer.addConnector("tcp://localhost:0");
answer.start();
return answer;
}
I had the same issue and I found the solution. I am configuring the activeMQ embeded broker using the XML and I could add the statisticsBrokerPlugin as follows.
<!-- lets create an embedded ActiveMQ Broker -->
<amq:broker useJmx="false" persistent="false" enableStatistics="true" brokerName="xxx-test-broker" brokerId="xxx-test">
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:0" />
</amq:transportConnectors>
**<amq:plugins>
<amq:statisticsBrokerPlugin/>
</amq:plugins>**
</amq:broker>
So my activeMQ connection URL will be vm://localhost.
I think this will be useful for someone.

Synchronous behavior with JMS Topic

I have below pseudo code of flow which uses queue to send the message and then listen to topic synchronously. The underlying JMS provider is Tibco EMS.
//Send to Queue
Connection connection = createConnection(); // get the JMS connection
Session session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("sample.queue");
MessageProducer messageProducer = session.createProducer(queue);
Message message = createMessage(); //create JMS message
messageProducer.send(message);
Now, I listen to a topic using same session object created and wait till there is a response.
Topic topic = session.createTopic("sample.topic");
MessageConsumer messageConsumer = session.createConsumer(topic);
//wait for the reply.
Message responseMessage = messageConsumer.receive(60000);
if(responseMessage != null) {
System.out.println("Message received..");
}
The problem that I am facing is that the message object is coming out as null. I tested with a jms monitoring tool and the topic does have some message, but the above code is not able to pick it up even after 60 secs.
Any idea what am I missing here ?
Figured it out. Just before calling messageConsumer.receive();, a call to connection.start() to start the delivery of the message.

Categories