Integration with IBM MQ made simple with Camel

In this article we will learn how to route JMS messages to IBM MQ broker using a Camel Route.

IBM MQ provides these messaging and queuing capabilities across multiple modes of operation: point-to-point ; publish/subscribe. You can easily integrate with this messaging provider by using the camel JMSComponent by setting the MQQueueConnectionFactory properties either in configuration or using Java DSL.

Let’s check how to write a Java DSL class which defines the JmsComponent named “mq” which takes the MQQueueConnectionFactory from Class variable:

import org.apache.camel.component.jms.JmsComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.connection.JmsTransactionManager;
import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.ibm.mq.jms.MQQueueConnectionFactory;
import com.ibm.msg.client.wmq.WMQConstants;

@Configuration
@EnableTransactionManagement
public class JmsConfiguration {
  private static final Logger LOG = LoggerFactory.getLogger(JmsConfiguration.class);
  private String host = "localhost";
  private int port = 1414;
  private String queueManager = "QM1";
  private String channel = "DEV.APP.SVRCONN";
  private String username = "app";
  private String password = "";
  private long receiveTimeout = 2000;

  @Bean
  public JmsComponent mq() {
    JmsComponent jmsComponent = new JmsComponent();
    jmsComponent.setConnectionFactory(mqQueueConnectionFactory());
    return jmsComponent;
  }

  @Bean
  public MQQueueConnectionFactory mqQueueConnectionFactory() {
    MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
    mqQueueConnectionFactory.setHostName(host);
    try {
      mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
      mqQueueConnectionFactory.setChannel(channel);
      mqQueueConnectionFactory.setPort(port);
      mqQueueConnectionFactory.setQueueManager(queueManager);
    } catch (Exception e) {
      LOG.error(e.getMessage(), e);
    }
    return mqQueueConnectionFactory;
  }

  @Bean
  public UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter(
      MQQueueConnectionFactory mqQueueConnectionFactory) {
    UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter =
        new UserCredentialsConnectionFactoryAdapter();
    userCredentialsConnectionFactoryAdapter.setUsername(username);
    userCredentialsConnectionFactoryAdapter.setPassword(password);
    userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqQueueConnectionFactory);
    return userCredentialsConnectionFactoryAdapter;
  }

  @Bean
  @Primary
  public CachingConnectionFactory cachingConnectionFactory(
      UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter) {
    CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    cachingConnectionFactory.setTargetConnectionFactory(userCredentialsConnectionFactoryAdapter);
    cachingConnectionFactory.setSessionCacheSize(500);
    cachingConnectionFactory.setReconnectOnException(true);
    return cachingConnectionFactory;
  }

  @Bean
  public PlatformTransactionManager jmsTransactionManager(
      CachingConnectionFactory cachingConnectionFactory) {
    JmsTransactionManager jmsTransactionManager = new JmsTransactionManager();
    jmsTransactionManager.setConnectionFactory(cachingConnectionFactory);
    return jmsTransactionManager;
  }
}

In order to use the JMSComponent, you can implement a simple Route like this:

import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

@Component
public class CamelRouteBuilder extends RouteBuilder {
  public void configure() throws Exception {
    from("timer:mytimer?period=5000")
        .routeId("generate-route")
        .transform(constant("HELLO from Camel!"))
        .to("mq:queue:DEV.QUEUE.1");
  }
}

In order to use the JMSComponent with IBM MQ, you need to add both dependencies to your project:

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-jms</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.ibm.mq</groupId>
    <artifactId>com.ibm.mq.allclient</artifactId>
    <version>9.1.0.5</version>
</dependency>

On the other hand, if you prefer, you can stick to Spring XML configuration to define your IBM MQ Connection Factory and Route:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd        http://camel.apache.org/schema/spring       http://camel.apache.org/schema/spring/camel-spring.xsd">
     	
   <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
       		
      <route id="timer">
          			
         <from uri="timer://foo?fixedRate=true&period=10000"/>
          			
         <setBody>
             				
            <simple>${date:now:yyyy-MM-dd'T'HH:mm:ss}</simple>
             			
         </setBody>
          			
         <log message="SENDING MESSAGE"/>
          			
         <to uri="mq:queue:DEV.QUEUE.1"/>
          			
         <log message="SENT MESSAGE"/>
          		
      </route>
       		
      <route id="get">
          			
         <from uri="mq:queue:DEV.QUEUE.1"/>
          			
         <log message="GOT MESSAGE with headers: ${in.headers}"/>
          			
         <log message="GOT MESSAGE with Body ${in.body}"/>
          		
      </route>
       	
   </camelContext>
     	
   <bean id="mqConnectionFactory" class="com.ibm.mq.jms.MQConnectionFactory">
       		
      <property name="hostName" value="localhost"/>
       		
      <property name="port" value="1414"/>
       		
      <property name="queueManager" value="QM1"/>
       		
      <property name="channel" value="DEV.APP.SVRCONN"/>
       		
      <property name="transportType" value="1"/>
       		
      <property name="shareConvAllowed" value="0"/>
       	
   </bean>
    	
   <bean id="mqcredential" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
       		
      <property name="targetConnectionFactory" ref="mqConnectionFactory"/>
       		
      <property name="username" value="app"/>
       		
      <property name="password" value=""/>
       	
   </bean>
    	
   <bean id="mq" class="org.apache.camel.component.jms.JmsComponent">
       		
      <property name="connectionFactory" ref="mqcredential"/>
       		
      <property name="maxConcurrentConsumers" value="1"/>
       		
      <property name="cacheLevelName" value="CACHE_CONSUMER"/>
       	
   </bean>
    
</beans>