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.