Skip to content

Instantly share code, notes, and snippets.

@remibantos
Last active August 24, 2022 07:03
Show Gist options
  • Save remibantos/33c366803f189db9b225 to your computer and use it in GitHub Desktop.
Save remibantos/33c366803f189db9b225 to your computer and use it in GitHub Desktop.
Message Driven Beans with Wildfly and Websphere MQ

Message Driven Beans with Wildfly and Websphere MQ

Introduction

This page describes MDB (Message Driven Bean) configuration with Wildfly (> version 8 implementing Java EE 7/8) and Websphere MQ messaging broker.

Websphere MQ Resource Adapter

Description

Websphere MQ provides a resource adapter which is able to interact with latest and even legacy Websphere MQ versions. (See this link for WMQ v8.0 Resource Adapter compatibility details)
It implements Java Connector Architecture (JCA) Java EE specification, allowing to interact with it from a Java EE application server.
Finally it allows Java EE 7 applications using JMS 2.0 specification to interact with legacy WMQ JMS 1.1 providers in an implicit way.

MDB setup

MDB code sample

Bellow is a sample of MDB

package org.rembx.sample.jee;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

/**
 * User: bantos
 */

@MessageDriven(activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true"),
        @ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/jboss/test"),
        @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")})
public class TestMDB implements MessageListener {

    @Override
    public void onMessage(Message message) {

        if (message instanceof TextMessage) {
            try {
                System.out.println(((TextMessage) message).getText());
            } catch (JMSException e) {
                // propagate for transaction rollback
                throw new IllegalArgumentException(e);
            }
        }

    }
}

Note that ActivationSpec annotations used here do not depend on environment. (See following section)

MDB destination configuration

WebsphereMQ resource adapter does not allow to use standalone.xml admin-objects for destination configuration (admin-objects can only be used by messages producers).
Thus we need to configure the whole destination parameters such as JMS provider host, port, (...), in MDB configuration.
Configuring such parameters with MDB ActivationSpec annotations would not help to maintain contextual configuration (related to environment).

jboss-ejb3.xml deployment descriptor (in WEB-INF directory of webapp,

This custom deployment descriptor (See this link for details) allows to declare and maintain properly contextual MDB configuration related to destination by using system properties.

<?xml version="1.0" encoding="UTF-8"?>
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
               xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd
                  http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-spec-2_0.xsd"
               xmlns:mdb="urn:resource-adapter-binding" version="3.1" impl-version="2.0">

    <jboss:enterprise-beans>
        <message-driven>
            <ejb-name>TestMDB</ejb-name>
            <ejb-class>org.rembx.sample.jee.TestMDB</ejb-class>
            <transaction-type>Container</transaction-type>
            <message-destination-type>javax.jms.Queue</message-destination-type>
            <activation-config>
                <activation-config-property>
                    <activation-config-property-name>channel</activation-config-property-name>
                    <activation-config-property-value>${websphere.channel}</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>queueManager</activation-config-property-name>
                    <activation-config-property-value>${websphere.queueManager}</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>transportType</activation-config-property-name>
                    <activation-config-property-value>${websphere.transportType}</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>hostName</activation-config-property-name>
                    <activation-config-property-value>${websphere.hostName}</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>port</activation-config-property-name>
                    <activation-config-property-value>${websphere.port}</activation-config-property-value>
                </activation-config-property>
            </activation-config>
        </message-driven>
    </jboss:enterprise-beans>
    <assembly-descriptor>
        <mdb:resource-adapter-binding>
            <ejb-name>TestMDB</ejb-name>
            <mdb:resource-adapter-name>${websphere.resource.adapter}</mdb:resource-adapter-name>
        </mdb:resource-adapter-binding>
    </assembly-descriptor>
</jboss:ejb-jar>

standalone.xml

The following resource-adapters subsystem configuration has to be added

        <subsystem xmlns="urn:jboss:domain:resource-adapters:2.0">
            <resource-adapters>
                <resource-adapter id="wmq.jmsra.rar">
                    <archive>
                        wmq.jmsra.rar
                    </archive>
                    <transaction-support>NoTransaction</transaction-support>
                    <connection-definitions>
                        <connection-definition class-name="com.ibm.mq.connector.outbound.ManagedConnectionFactoryImpl" jndi-name="java:/jboss/MyConnectionFactory" use-java-context="true" pool-name="mqconn">
                            <config-property name="hostName">
                                ${websphere.hostName:localhost}
                            </config-property>
                            <config-property name="password">
                                ${websphere.password:mqm}
                            </config-property>
                            <config-property name="queueManager">
                                ${websphere.queueManager:QUEUE.MANAGER}
                            </config-property>
                            <config-property name="port">
                                ${websphere.port:1414}
                            </config-property>
                            <config-property name="channel">
                                ${websphere.channel:SYSTEM.AUTO.SVRCONN}
                            </config-property>
                            <config-property name="transportType">
                                ${websphere.transportType:CLIENT}
                            </config-property>
                            <config-property name="username">
                                ${websphere.username:mqm}
                            </config-property>
                            <security>
                                <application/>
                            </security>
                        </connection-definition>
                    </connection-definitions>
                    <admin-objects>
                        <admin-object class-name="com.ibm.mq.connector.outbound.MQQueueProxy" jndi-name="java:/jboss/test" use-java-context="true" pool-name="MQ.QUEUE.NAME">
                            <config-property name="baseQueueName">
                                ${websphere.queueName:Q_QUEUE}
                            </config-property>
                        </admin-object>
                    </admin-objects>
                </resource-adapter>
            </resource-adapters>
        </subsystem>

Then, destination contextual configuration is defined through syste-properties. (These properties are referenced by WMQ resource-adapter configuration (see above) and jboss-ejb3.xml MDB configuration)

<system-properties>
        <property name="websphere.hostName" value="< WMQ HOST >"/>
        <property name="websphere.port" value="< WMQ PORT >"/>
        <property name="websphere.channel" value="< WMQ CHANNEL >"/>
        <property name="websphere.transportType" value="< WMQ TRANSPORT TYPE >"/>
        <property name="websphere.queueManager" value="< WMQ HQUEUE MANAGER >"/>
        <property name="websphere.queueName" value="< WMQ QUEUE NAME >"/>
        <property name="websphere.resource.adapter" value="< WMQ RESOURCE ADAPTER ARCHIVE NAME (such as wmq.jmsra.rar) >"/>
</system-properties>

Messages push configuration

Sample of JMS messages producer

The following EJB pushes messages to configured test destination :

package org.rembx.sample.jee;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.jms.*;
import java.util.UUID;

@Stateless
public class ResourceSample {

    @Resource(mappedName = "java:/jboss/MyConnectionFactory")
    ConnectionFactory factory;

    @Resource(mappedName = "java:/jboss/test")
    Queue queue;

    public void pushMessage() throws JMSException {
        try (JMSContext context = connectionFactory.createContext()) {
            context.createProducer().send(queue, "Hello World !");
        }
    }
}

Links

@msakho
Copy link

msakho commented Mar 24, 2016

Hi Rémi. Nice article. BTW, I would have used the JMS simplified API to send the message. Less verbose than the JMS classic API
public void pushMessage() {
try (JMSContext context = connectionFactory.createContext();) {
StringBuilder message = new StringBuilder();
message.append("Hello Wold");
context.createProducer().send(inboundQueue, message.toString());
} }

@remibantos
Copy link
Author

@lekhosa, thanks for your comment, I've simplified the messages producer example.

@mrts
Copy link

mrts commented Feb 26, 2017

It can be even simpler, you can inject JMSContext:

@Inject
private JMSContext context;

See WildFly MDB quickstart example. Note that you need to run WildFly with the full profile with ${jboss.home.name}/bin/standalone.{sh,bat} -c standalone-full.xml for JMS to work.

@remibantos
Copy link
Author

remibantos commented Mar 9, 2017

@mtrs thanks, indeed. @JMSConnectionFactory("java:/jboss/MyConnectionFactory") would have to be added too in order to reference the factory declared in WMQ resource adapter configuration/

@sidhuurs
Copy link

sidhuurs commented Jul 16, 2017

Thanks for great article. Couple of questions.... is it not possible to add ConnectionFcatory jndi to MDB through annotation ? do we need to deploy wmq.jmsra.rar into wildfly as a module ? is not required at to add resource adopter to MDB as a resource through annotation?

@foukad
Copy link

foukad commented Oct 5, 2021

Bonjour Rémi,
merci pur cet article très intéressants. Je voudrais savoir comment je peut activer le SSL avec mon MDB (sslCipherSuite)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment