Featured image: Integrate Red Hat AMQ with IBM MQ with Red Hat Fuse

This article presents a sample integration between Red Hat AMQ 7 and IBM MQ, using Red Hat Fuse 7 for the integration. Traditionally, developers have used resource adapters for message bridging with external systems. A resource adapter is a system library that provides connectivity to an enterprise information system (EIS). Similar to how a Java Database Connectivity (JDBC) driver provides connectivity to a database management system, a resource adapter plugs into an application server such as Red Hat JBoss Enterprise Application Platform (JBoss EAP). It then connects the application server, enterprise information system, and the enterprise application.

Resource adapters work well, but the configuration can be overwhelming, especially for scenarios that require adding numerous modules on top of the application server or where the resource adapter contract requires extensive administrative resources. Some scenarios require configuring multiple resource adapters and then arranging the message exchange between them.

Red Hat Fuse provides a simpler, more flexible pattern for routing messages between components. Fuse leverages Apache Camel's JMS component to exchange messages via a Java Message Service (JMS) queue or topic. It relies on Spring’s JMS support for declarative transactions.

Follow the demonstration in the next sections to see for yourself how the JMS component works in a Red Hat Fuse integration.

Set up the Red Hat Fuse project

For this demonstration, we will create a Spring Boot-based Fuse application that uses a Camel route to exchange messages between Red Hat AMQ and IBM MQ. To start, open a shell prompt and enter the following mvn command:

mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate \
-DarchetypeCatalog=https://maven.repository.redhat.com/ga/io/fabric8/archetypes/archetypes-catalog/2.2.0.fuse-760024-redhat-00001/archetypes-catalog-2.2.0.fuse-760024-redhat-00001-archetype-catalog.xml \
-DarchetypeGroupId=org.jboss.fuse.fis.archetypes \
-DarchetypeArtifactId=spring-boot-camel-xml-archetype \
-DarchetypeVersion=2.2.0.fuse-760024-redhat-00001

This command creates the basic project structure, including the Application class:

package com.sample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

So far, the code should look familiar.

Configure the brokers

Next, we'll configure the two brokers. Start by adding a @Configuration bean that contains the following JmsComponent bean declarations (note that the declarations are bound as @Bean using the method name for the id):

package com.sample;

import com.ibm.mq.jms.*;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.camel.component.jms.JmsComponent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter;

@Configuration
public class AppConfig {


    @Bean
    public JmsComponent activemq() throws Exception {
        // Create the connectionfactory which will be used to connect to Artemis
        ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory();
        cf.setBrokerURL("tcp://localhost:61616");
        cf.setUser("admin");
        cf.setPassword("admin");

        // Create the Camel JMS component and wire it to our Artemis connectionfactory
        JmsComponent jms = new JmsComponent();
        jms.setConnectionFactory(cf);
        return jms;
    }



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

    @Bean
    public MQQueueConnectionFactory mqQueueConnectionFactory() {
    // Create the connectionfactory which will be used to connect to IBM MQ
        MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
        mqQueueConnectionFactory.setHostName("localhost");
        try {
            mqQueueConnectionFactory.setTransportType(1);
            mqQueueConnectionFactory.setChannel("DEV.APP.SVRCONN");
            mqQueueConnectionFactory.setPort(1414);
            mqQueueConnectionFactory.setQueueManager("QM1");
        } catch (Exception e) {
           e.printStackTrace();
        }
        return mqQueueConnectionFactory;
    }

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

}

The Red Hat AMQ connection factory is now available under the activemq id. The IBM MQ connection factory is available under the wmq id.

Add the route definition

We're almost done. Our final step is to add the RouteBuilder class, which contains the route definition:

package com.sample;

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

@Component
public class CamelArtemisRouteBuilder extends RouteBuilder {

    public void configure() throws Exception {


        from("timer:mytimer?period=5000").routeId("generate-route")
                .transform(constant("HELLO from Camel!"))
                .to("activemq:queue:QueueIN");


        from("activemq:queue:QueueIN").routeId("receive-route")
                .log("Received a message - ${body} - sending to outbound queue")
                .to("wmq:queue:DEV.QUEUE.1?exchangePattern=InOnly");


    }
}

In the above route, messages are produced from a timer component that fires new messages every five seconds. Messages are sent through the Red Hat AMQ queue named QueueIN. After logging the message body, they are sent to the sink destination, which is DEV.QUEUE.1.

We've completed the integration setup. Next, we'll run the application and verify that it's working.

Start the brokers and run the application

Before running the application, we need to start the two broker instances. Make sure your Red Hat AMQ server is up and running. If it is not already running, enter the following command:

./artemis run

Next, start IBM MQ. For this purpose, you can use a container image of IBM MQ with the developer license:

$ podman run --env LICENSE=accept --env MQ_QMGR_NAME=QM1 --publish 1414:1414 --publish 9443:9443 --detach ibmcom/mq

Finally, use the standard Spring Boot Maven plug-in to start the Red Hat Fuse application:

$ mvn spring-boot:run

Verify the application

As the application starts, you will see from the Spring Boot console that messages are logged on the console:

12:10:12.552 [Camel (camel-1) thread #1 - JmsConsumer[INCOMING]] INFO receive-route - Received a message - HELLO from Camel! - sending to outbound queue
13:20:37.935 [Camel (camel-1) thread #1 - JmsConsumer[INCOMING]] INFO receive-route - Received a message - HELLO from Camel! - sending to outbound queue
13:20:42.954 [Camel (camel-1) thread #1 - JmsConsumer[INCOMING]] INFO receive-route - Received a message - HELLO from Camel! - sending to outbound queue
13:20:47.966 [Camel (camel-1) thread #1 - JmsConsumer[INCOMING]] INFO receive-route - Received a message - HELLO from Camel! - sending to outbound queue

You can log into the running container process to check that the message has been received on the IBM MQ side:

$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
52f0f72d56ed docker.io/ibmcom/mq:latest 5 hours ago Up 5 hours ago 0.0.0.0:1414->1414/tcp pensive_bose

The output shows the message has been received:

$ podman exec --tty --interactive 52f0f72d56ed bash bash-4.4$ /opt/mqm/samp/bin/amqsbcg DEV.QUEUE.1 QM1

MQGET of message number 1
****Message descriptor****

StrucId : 'MD ' Version : 2
Report : 0 MsgType : 8
Expiry : -1 Feedback : 0
Encoding : 546 CodedCharSetId : 850
Format : 'MQEVENT '
Priority : 0 Persistence : 0
MsgId : X'414D512073617475726E2E71756575650005D30033563DB8'
CorrelId : X'000000000000000000000000000000000000000000000000'
BackoutCount : 0
ReplyToQ : ' '
** Identity Context
UserIdentifier : ' '
AccountingToken :
X'0000000000000000000000000000000000000000000000000000000000000000'
ApplIdentityData : ' '
** Origin Context
PutApplType : '7'
PutDate : '19970417' PutTime : '15115208'
ApplOriginData : ' '
GroupId : X'000000000000000000000000000000000000000000000000'
MsgSeqNumber : '1'
Offset : '0'
MsgFlags : '0'
OriginalLength : '104'

**** Message ****

length - 104 bytes

Conclusion

This article discussed how to connect multiple JMS providers (in this case, Red Hat AMQ and IBM MQ) by registering their JMS ConnectionFactory components as Spring beans. After registering the ConnectionFactory beans, we injected them into a Camel JMS component configuration. We then defined the Camel JMS component and used it as part of a Camel route to move messages from both ends of the application.

To get started with Red Hat Fuse, visit the Red Hat Fuse download page. To learn more about using Red Hat Fuse for message broker integration, see Integrate IBM WebSphere MQ with JBoss Fuse.

About the author

Francesco Marchioni is a senior technical account manager for Red Hat Middleware products based in Rome, Italy. Read more about open source contributions to the JBoss developer community at mastertheboss.com.