How to receive MQMessage using JmsListener - jms

I am upgrading my application from a regular java application to Spring boot application.
I am connecting with an external application, using IBM MQ.
At the old version i got an MQMessage object and used only the feedback field. like this:
MQQueue currQ = this.qMgr.accessQueue("myQueue",MQC.MQOO_INQUIRE + MQC.MQOO_INPUT_SHARED + MQC.MQOO_FAIL_IF_QUIESCING);
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.options = MQC.MQGMO_SYNCPOINT;
MQMessage mqMsg = new MQMessage();
currQ.get(mqMsg, gmo);
System.out.println("feedback: " + mqMsg.feedback);
In my new code, I am using JmsListener:
#JmsListener(destination = "myQueue", containerFactory = "jmsListenerContainerFactory")
public void myQueueListener(String message) {
System.out.println("feedback: " + ???);
}
How do i get the feedback field?
I have no control on the external application that sends the message.

The chapter JMS fields and properties with corresponding MQMD fields explains the header mapping. You have two options to access the headers (see also this answer), here is one of it:
#JmsListener(destination = "myQueue", containerFactory = "jmsListenerContainerFactory")
public void myQueueListener(String message, #Header("JMS_IBM_Feedback") Integer feedback) {
System.out.println("feedback: " + feedback);
}

Related

How to session manually in a java project that connects to a JMS MQ with xml as payload and gets the response from the remote jms endpoint

I have been searching for Java code to send an XML payload to the JMS endpiont and also receive the response in XML format only. Everyone is writing the producer and consumer but nobody is giving code for existing jms endpoint with payload.
Plug In- Tibco EMS
Connection factory – com.tibco.tibjms.TibjmsConnectonfactory
Server URL - tcp://10.xxx.xx.xx:69999
User name – scott
Password - tiger
XML payload:
<?xml version="1.0" encoding="UTF-8"?>
<MYServices>
<header>
<version>1.0</version>
</header>
<body>
<srv_req>
<req_due_amount>
<card_no>blablanumber</card_no>
</req_due_amount>
</srv_req>
</body>
</MYServices>
JMS endpoint
jms://session_name::queue_name::request_topic
import javax.jms.*;
import java.util.Enumeration;
public class JMSExample{
protected static final String SERVICE_QUEUE = "QUEUE_NAME_THAT_IS_CREDTED_IN_SERVER_FOR_ACCEPTING";
static String serverUrl = "tcp://10.xxx.xxx.xxx:xxxxx";
static String userName = "UR_UserID";
static String password = "UR_Pass";
public static void sendTopicMessage(String topicName, String messageStr) {
Connection connection = null;
Session session = null;
MessageProducer msgProducer = null;
Destination destination = null;
try {
TextMessage msg;
System.out.println("Publishing to destination '" + topicName
+ "'\n");
ConnectionFactory factory = new com.tibco.tibjms.TibjmsConnectionFactory(serverUrl);
connection = factory.createConnection(userName, password);
connection.start();
session = connection
.createSession(false,javax.jms.Session.AUTO_ACKNOWLEDGE);
TemporaryQueue tempQueue = session.createTemporaryQueue();
TextMessage message_t = session.createTextMessage(messageStr);
//This step is compulsory to get the reply from JMS server
message_t.setJMSReplyTo(tempQueue);
MessageProducer producer = session.createProducer(session.createQueue(SERVICE_QUEUE));
producer.send(message_t);
System.out.println("INFO:: The producer has sent the message"+message_t);
Destination dest = tempQueue;
MessageConsumer consumer = session.createConsumer(dest);
Message replyMsg = consumer.receive();
TextMessage tm = (TextMessage) replyMsg;
System.out.println("INFO The response is "+ replyMsg);
consumer.close();
producer.close();
session.close();
connection.close();
} catch (JMSException e) {
System.out.println("Error :: there was exception"+e);
e.printStackTrace();
}
}
/*-----------------------------------------------------------------------
* main
*----------------------------------------------------------------------*/
public static void main(String[] args) {
JMSExample5.sendTopicMessage(SERVICE_QUEUE,
"<?xml version = \"1.0\" encoding = \"UTF-8\"?>\n" +
"<MYServices>\n" +
" <header>\n" +
" <Version>1.0</Version>\n" +
" <SrvType>OML</SrvType>\n" +
" <SrvName>REQ_BALANCE_ENQUIRY</SrvName>\n" +
" <SrcApp>BNK</SrcApp>\n" +
" <OrgId>BLA</OrgId>\n" +
" </header>\n" +
" <body>\n" +
" <srv_req>\n" +
" <req_credit_card_balance_enquiry>\n" +
" <card_no>12345678</card_no>\n" +
" </req_credit_card_balance_enquiry>\n" +
" </srv_req>\n" +
" </body>\n" +
"</MYServices>\n");
}
}

Sending a Message with Spring Cloud Stream and RabbitMq changes ID

I'm using Spring Cloud Stream and RabbitMq to exchange Messages between different microservices.
Thats my setup to publish a message.
public interface OutputChannels {
static final String OUTPUT_CHANNEL = "outputChannel";
#Output
MessageChannel outputChannel();
}
.
#EnableBinding(OutputChannels.class)
#Log4j
public class OutputProducer {
#Autowired
private OutputChannels outputChannels;
public void createMessage(MyContent myContent) {
Message<MyContent> message = MessageBuilder
.withPayload(myContent)
.build();
outputChannels.outputChannel().send(message);
log.info("Sent message: " + message.getHeaders().getId() + myContent);
}
}
And the setup to receive the message
public interface InputChannels {
String INPUT_CHANNEL = "inputChannel";
#Input
SubscribableChannel inputChannel();
}
.
#EnableBinding(InputChannels.class)
#Log
public class InputConsumer {
#StreamListener(InputChannels.INPUT_CHANNEL)
public void receive(Message<MyContent> message) {
MyContent myContent = message.getPayload();
log.info("Received message: " + message.getHeaders().getId() + ", " + myContent);
}
}
I am able to successfully exchange messages with this setup. I would expect, that the IDs of the sent message and the received message are equal. But they are always different UUIDs.
Is there a way that the message keeps the same ID all the way from the producer, through the RabbitMq, to the consumer?
Spring Messaging messages are immutable; they get a new ID each time they are mutated.
You can use a custom header or IntegrationMessageHeaderAccessor.CORRELATION_ID to convey a constant value; in most use cases, the correlation id header is set by the application to the ID header at the start of a message's journey.

JMS Temporary Queue - Replies not returning back to client

I'm trying to move away from Weblogic to JBoss, and as such I'm trying to implement the things I was able to implement on Weblogic on JBoss.
One of those things is our notification system where the client sends a request to an MDB and the MDB sends a reply back to the client.
This was a breeze in Weblogic, but on Jboss, nothing seems to work. I keep getting this error:
javax.jms.InvalidDestinationException: Not an ActiveMQ Artemis Destination:ActiveMQTemporaryQueue[da00b1a2-114d-4be9-930d-926fc20c2fce]
Is there something I need to configure on my Jboss?
EDIT
I realise that I probably didn't phrase the question very well.
What happens is this: I have a client and a server MDB (message driven bean). The client sends a message to a queue and waits for a response from the server. The server picks the message from the queue and sends a response to the client, which the client picks up and displays.
On Jboss, messages from the client go smoothly, and the server picks it up, but as soon as the server MDB tries to send a response to the client, that error is thrown.
My client code (excerpt):
int TIME_OUT = 60000;
//prepare factory
Properties prop = new Properties();
prop.setProperty("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory");
prop.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
prop.setProperty("java.naming.provider.url", "http-remoting://remotehost:8080");
prop.setProperty("java.naming.security.principal", "guest-user")
prop.setProperty("java.naming.security.credentials", "Password#1")
String queueConnectionFactory = "jms/RemoteConnectionFactory";
Context context = new InitialContext(prop);
QueueConnectionFactory qconFactory = (QueueConnectionFactory) context.lookup(queueConnectionFactory);
//prepare queue and sessions
QueueConnection qcon = qconFactory.createQueueConnection(prop.getProperty("java.naming.security.principal"), prop.getProperty("java.naming.security.credentials"));
QueueSession qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) context.lookup("jms/TestQueue2");
//create message
NotificationWrapper wrapper = //object initialised with something
ObjectMessage om = qsession.createObjectMessage(wrapper);//NotificationWrapper wrapper
//create producer
MessageProducer producer = qsession.createProducer(queue);
//create temporary queue
TemporaryQueue tempqueue = qsession.createTemporaryQueue();
om.setJMSReplyTo(tempqueue);
//start connection
qcon.start();
//send message and wait for response
producer.send(om);
MessageConsumer consumer = qsession.createConsumer(tempqueue);
Message callback = consumer.receive(TIME_OUT);
//print message from server
if (callback != null) {
System.out.println("Response received from server. Print here...");
//message from server
} else {
System.out.println("No Response received from server. Problems!!!");
}
//close all connections
if (consumer != null) {
consumer.close();
}
if (producer != null) {
producer.close();
}
if (qsession != null) {
qsession.close();
}
if (qcon != null) {
qcon.close();
}
My Server code (excerpt):
#MessageDriven(mappedName = "TestQueue2", activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/TestQueue2"),
#ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
})
public class ServerSide implements MessageListener {
private static final QueueConfigProperties queueConfigProp = QueueConfigProperties.getInstance();
private Context context;
private QueueConnectionFactory qconFactory;
private QueueConnection qcon;
private QueueSession qsession;
private MessageProducer producer;
public ServerSide() {
try {
initialiseQueueFactory("jms/RemoteConnectionFactory");
//initialiseQueueFactory("jms/GreenpoleConnectionFactory");
prepareResponseQueue();
Properties prop = new Properties();
prop.setProperty("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory");
prop.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
prop.setProperty("java.naming.provider.url", "http-remoting://remotehost:8080");
prop.setProperty("java.naming.security.principal", "guest-user")
prop.setProperty("java.naming.security.credentials", "Password#1")
String queueConnectionFactory = "jms/RemoteConnectionFactory";
Context context = new InitialContext(prop);
QueueConnectionFactory qconFactory = (QueueConnectionFactory) context.lookup(queueConnectionFactory);
qcon = qconFactory.createQueueConnection(queueConfigProp.getProperty("java.naming.security.principal"), queueConfigProp.getProperty("java.naming.security.credentials"));
qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
} catch (NamingException | ConfigNotFoundException | IOException | JMSException ex) {
//error log
}
}
#Override
public void onMessage(Message message) {
try {
if (((ObjectMessage) message).getObject() instanceof NotificationWrapper) {
//send response
if (message.getJMSReplyTo() != null) {
logger.info("sending response");
respondToSenderPositive(message);
Response resp = new Response();
resp.setRetn(0);
resp.setDesc("Notification submitted to queue.");
producer = qsession.createProducer(message.getJMSReplyTo());
producer.send(qsession.createObjectMessage(resp));
producer.send(msg_to_send);
}
} else {
//some message printed here
}
} catch (JMSException ex) {
//error logs
} catch (Exception ex) {
//error logs
}
}
}
The issue was to do with the configuration of the destination queue which is a remote queue: the client and server are both running on different JVMs. Remote Queues on Jboss are named differently from those on Weblogic.
The name of a remote queue should be something like this: java:jboss/exported/jms/TestQueue2
Refer to the JBoss documentation for a more detailed explanation on queues: https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.0/html-single/configuring_messaging/index

Spring Message Listener Names

I have created several spring 4.1.6 #JmsListener methods for receiving messages from queues. I would like to get the list of listener names for admin purpose:
#JmsListener(
destination = "${jms.destination.name}"
, containerFactory = "myJmsContainerFactory"
, id ="myListener")
public void receiveMessage(String message) {
System.out.println("Received <" + message + ">");
}
and I want to display the id/name of the listeners for admin purposes. I can stop and start the listeners with the JmsListenerEndpointRegistry, but can't see how to get the name of the specific listeners.
JmsListenerEndpointRegistry registry = context.getBean(org.springframework.jms.config.JmsListenerEndpointRegistry.class);
Collection<MessageListenerContainer> listeners = registry.getListenerContainers();
MessageListenerContainer mlc = registry.getListenerContainer("myListener");
System.out.println("Running" + mlc.isRunning());
mlc.stop();
In debug the Collection can be seen as a Collections$UnmodifiableCollection with a LinkedHashMap that has the listener id ,myListener in this case, as the key value of the LinkedHashMap
This question was quite old, but I solved it this way:
Set<String> listenerContainerIds = registry.getListenerContainerIds();
for (String id : listenerContainerIds) {
MessageListenerContainer listenerContainer = registry.getListenerContainer(id);
...
}
I got the reference to the MessageListenerContainer und via getListenerContainerIds, I got the name of the ID to the reference.
Hope this helps...

ActiveMQ, topic does not bounce message

Imho the following code should create a new message, which is immedeatelly fetched again. But the output is zero. Why?
public static void main(String[] args) throws JMSException, NamingException {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
props.setProperty(Context.PROVIDER_URL,"tcp://localhost:61616");
props.setProperty("topic.MyTopic", "FOO.BAR");
// create a new intial context, which loads from jndi.properties file
Context ctx = new InitialContext(props);
// lookup the connection factory
TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("ConnectionFactory");
// create a new TopicConnection for pub/sub messaging
TopicConnection conn = factory.createTopicConnection();
// lookup an existing topic
Topic mytopic = (Topic) ctx.lookup("MyTopic");
// create a new TopicSession for the client
TopicSession session = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
// create a new publisher to produce messages
TopicPublisher publisher = session.createPublisher(mytopic);
// create a new subscriber to receive messages
TopicSubscriber subscriber = session.createSubscriber(mytopic);
subscriber.setMessageListener(new MessageListener() {
public void onMessage(Message msg) {
try {
TextMessage textMessage = (TextMessage) msg;
String txt = textMessage.getText();
System.out.println(txt);
} catch (JMSException e) {
e.printStackTrace();
}
}
});
TextMessage message = session.createTextMessage();
message.setText("Kebap: Pommes");
publisher.publish(message);
}
Okay, I found the problem. The example from the ActiveMQ website isn't that good ... but they also provide an answer for my problem.
http://activemq.apache.org/i-am-not-receiving-any-messages-what-is-wrong.html

Resources