2
votes

I need to send message from spring integration to Non jms application via IBM MQ

I have tried to send message but unfortunately, the receiver non jms application is not able consume due to unwanted Jms headers Included in the message and getting data format exception

How to remove jms headers before sending message to non jms application using spring integration

I have found some reference link in IBM MQ site

https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.dev.doc/q032140_.htm

2
The answer I flagged this for close as dup against describes how to "How to remove jms headers before sending message to non jms application using spring integration". The answer Morag provided below is how to force them to be removed on the destination queue where the non-jms application consumes from.JoshMc
@JoshMc is right. It is likely a duplicate. But what's missing in the linked question is the reference to chapter Creating destinations in a JMS application. With the information from this chapter it is clear that you can configure your request queue in Spring Integration like this queue:///YOUR.REQ.QUEUE?targetClient=1 to omit the RFH2 header.Daniel Steinmann

2 Answers

2
votes

There are a number of ways to do this, as can be seen in the spread of comments and answers you have already received. How you do it really depends on you.

As Daniel states you can modify the queue url.

As Morag states you can use MQSC to alter the queue.

You can also do this by code. You haven't provided any code so its not easy to tell you how to do this, but if you cast your destination (queue) to an MQDestination you can exclude the RFH2 headers using the IBM JMS API.

RFH2 will be excluded

    import javax.jms.Destination;
    import com.ibm.mq.jms.MQDestination;
    import com.ibm.msg.client.wmq.WMQConstants;
    ...

    Destination destination = ...
    ...


    MQDestination mqDestination = (MQDestination) destination;
    destination.setTargetClient(WMQConstants.WMQ_CLIENT_NONJMS_MQ);

I have this tested with this service in Spring


import com.ibm.mq.jms.MQDestination;
import com.ibm.msg.client.wmq.WMQConstants;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;

import javax.jms.*;

@Service
public class SendMessageNonJmsService {

    protected final Log logger = LogFactory.getLog(getClass());

    final private JmsTemplate myNonJmsTemplate;

    @Autowired
    private ConnectionFactory connectionFactory;

    SendMessageNonJmsService(JmsTemplate myNonJmsTemplate) {
        this.myNonJmsTemplate = myNonJmsTemplate;
    }

    public void sendAsNonJms(String msg) {
        Destination destination = null;
        JMSContext context = connectionFactory.createContext();
        destination = context.createQueue("queue:///audit");
        try {
            MQDestination mqDestination = (MQDestination) destination;
            mqDestination.setTargetClient(WMQConstants.WMQ_CLIENT_NONJMS_MQ);
        }
        catch (JMSException ex) {
            logger.warn("JMSException preparing message destination : "
                            + ex.getErrorCode() + " : "
                            + ex.getMessage());
        }
        myNonJmsTemplate.send(destination, session -> session.createTextMessage(msg));
    }

}

As an alternative if you want your sending code to be as simple as

    public void sendAsNonJms(String msg) {
        myNonJmsTemplate.send("audit", session -> session.createTextMessage(msg));
    }

Then you can set a destination resolver on your JmsTemplate

    @Bean("myNonJmsTemplate")
    public JmsTemplate myNonJmsTemplate() {
        JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
        jmsTemplate.setDestinationResolver(new OurDestinationResolver());
        return jmsTemplate;
    }

where your destination resolver looks something like:

import com.ibm.mq.jms.MQDestination;
import com.ibm.msg.client.wmq.WMQConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.support.destination.DestinationResolver;

import javax.jms.*;

public class OurDestinationResolver implements DestinationResolver {

    protected final Log logger = LogFactory.getLog(getClass());

    @Autowired
    private ConnectionFactory connectionFactory;

    @Override
    public Destination resolveDestinationName(Session session, String dest, boolean pubSub) throws JMSException {
        Destination destination = null;

        if (pubSub) {
            destination = session.createTopic(dest);
        } else {
            destination = session.createQueue(dest);
        }

        MQDestination mqDestination = (MQDestination) destination;
        mqDestination.setTargetClient(WMQConstants.WMQ_CLIENT_NONJMS_MQ);

        return destination;
    }
}
0
votes

To ensure a consuming IBM MQ Application that doesn't understand the extraneous headers that are added by JMS (and other applications which use Message Properties), make the following change to the queue that the non-JMS application is getting from.

ALTER QLOCAL(queue-name) PROPCTL(NONE)

This has the benefit that any applications that do understand how to process JMS headers, can still receive them. Other solutions that remove the headers at put time result in all applications not receiving the headers. This solution allows those that can to receive them and those than can't not to be affected by them.

It is a very good solution when you have a mixture of applications. It also allows the "fix" to happen with a simple administrative command instead of requiring a change to an application.