JMS defines a vendor-neutral (but Java-specific) set of programming interfaces for interacting across different components or systems by means of messages. Messaging enables distributed communication, which is reliable and loosely coupled. A component sends a message to a destination, which in turn is retrieved by the recipient with the mediation of a JMS server.
This tutorial explains how to configure and run some JMS destinations using all versions of the application server ( WildFly, JBoss EAP 6, JBoss AS 6, JBoss AS 5, JBoss 4).
Java Message Service (JMS) Application Programming Interface, and it is used by applications to send asynchronous business-quality messages to other applications. In the messaging world, messages are not sent directly to other applications. Instead, messages are sent to destinations, known as queues or topics.
Applications sending messages do not need to worry if the receiving applications are up and running, and conversely, receiving applications do not need to worry about the sending application’s status. Both senders, and receivers only interact with the destinations.
The JMS API is the standardized interface to a JMS provider, sometimes called a Message Oriented Middleware (MOM) system.
In order to run a JMS application on WildFly / JBoss AS you need to configure:
- The JMS destination on JBoss AS
- The JMS libraries on the client
Configuring JMS destinations on WildFly
JMS destinations can be configured either by adding them in the core configuration file (standalone.xml/domain.xml) or via management interfaces such as the CLI :
Via CLI:
Add JMS queue:
jms-queue add --queue-address= jms.queue.ExampleQueue --entries=java:/jms/queue/exampleQueue,java:/jboss/exported/jms/queue/exampleQueue
Add JMS Topic:
jms-topic add --topic-address=jms.topic.ExampleTopic --entries=java:/jms/topic/exampleTopic,java:/jboss/exported/jms/topic/exampleTopic
Please note that the JNDI binding “java:/jboss/exported/jms/[destination]” is only required if you are connecting to your JMS Destination from a remote JMS Client
Via the configuration file:
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0"> <server name="default"> . . . . <jms-queue name="jms.queue.ExampleQueue" entries="java:/jms/queue/exampleQueue java:/jboss/exported/jms/queue/exampleQueue"/> <jms-topic name="jms.topic.ExampleTopic" entries="java:/jms/topic/exampleTopic java:/jboss/exported/jms/topic/exampleTopic"/> </server> </subsystem>
Configuring JMS client libraries (WildFly):
If you are running a Remote JMS Client, all you need in your Maven pom.xml is including the wildfly-jms-client-bom with the correct version of WildFly in it:
<dependencies> <dependency> <groupId>org.wildfly</groupId> <artifactId>wildfly-jms-client-bom</artifactId> <version>${version.wildfly}</version> <type>pom</type> </dependency> </dependencies>
For example, if running WildFly 24, set as Property:
<properties> <version.wildfly>24.0.0.Final</version.wildfly> </properties>
On the other hand, on the server side if you are using JMS Consumers (such as MDBs), you need to include the jakarta.jakartaee-api which includes the JMS API:
<dependencies> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-api</artifactId> <version>${jakartaee.version}</version> <scope>provided</scope> </dependency> </dependencies>
Coding JMS Applications
In this section we will see some examples of JMS Consumers and Producers. To run the examples, you need to comply with the following requirements:
- JDK 8 or above
- WildFly 10 or above running on 127.0.0.1:8080
- An application user with the credentials jmsuser/Password1!
- A JMS Queue created as follows:
jms-queue add --queue-address=exampleQueue --entries=queue/exampleQueue,java:jboss/exported/jms/queue/exampleQueue
Source code for this example available here: https://github.com/fmarchioni/practical-enterprise-development/tree/master/code/jms
Remote JMS Client
The following is an example Remote JMS Client application which acts as client for the JMS queue “queue/exampleQueue“:
import java.util.logging.Logger; import java.util.Properties; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSConsumer; import javax.jms.JMSContext; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; public class JMSClient { private static String MESSAGE = "Hello, World!"; private static String CONNECTION_FACTORY = "jms/RemoteConnectionFactory"; private static String DESTINATION = "jms/queue/exampleQueue"; public static void main(String[] args) throws Exception { Context namingContext = null; JMSContext context = null; try { // Set up the namingContext for the JNDI lookup final Properties env = new Properties(); env.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory"); env.put(Context.PROVIDER_URL, "http-remoting://127.0.0.1:8080"); env.put(Context.SECURITY_PRINCIPAL, "jmsuser"); env.put(Context.SECURITY_CREDENTIALS, "Password1!"); namingContext = new InitialContext(env); ConnectionFactory connectionFactory = (ConnectionFactory) namingContext .lookup(CONNECTION_FACTORY); System.out.println("Got ConnectionFactory " + CONNECTION_FACTORY); Destination destination = (Destination) namingContext .lookup(DESTINATION); System.out.println("Got JMS Endpoint " + DESTINATION); // Create the JMS context context = connectionFactory.createContext("jmsuser", "Password1!"); context.createProducer().send(destination, MESSAGE); System.out.println("Sent message " + MESSAGE); // Create the JMS consumer JMSConsumer consumer = context.createConsumer(destination); // Then receive the same number of messages that were sent String text = consumer.receiveBody(String.class, 5000); if (text == null) System.out.println("No message Received! Maybe another Consumer listening on the Queue ??"); System.out.println("Received message with content " + text); } catch (Exception e) { System.out.println(e.getMessage()); throw e; } finally { if (namingContext != null) { namingContext.close(); } // closing the context takes care of consumer too if (context != null) { context.close(); } } } }
Local JMS Client (Servlet)
The following is an example of a Servlet application which acts as JMS Local Client for the queue “queue/exampleQueue“:
import javax.faces.application.FacesMessage; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.annotation.Resource; import javax.ejb.Stateless; import javax.enterprise.inject.Model; import javax.inject.Inject; import javax.jms.ConnectionFactory; import javax.jms.DeliveryMode; import javax.jms.JMSConnectionFactory; import javax.jms.JMSContext; import javax.jms.JMSSessionMode; import javax.jms.Queue; @Model public class MessageSender { String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } @Inject JMSContext context; @Resource(mappedName = "java:/queue/exampleQueue") private Queue queue; public void sendMessage() { context.createProducer().send(queue, message); printMessage("Sent message " + message); } private void printMessage(String string) { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, string, string)); } }
Local JMS Consumer (MDB)
The following code is an example of a MDB which consumes messages from the queue “queue/exampleQueue“:
import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "java:/queue/exampleQueue"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), }) public class MDBSample implements MessageListener { public void onMessage(Message message) { try { TextMessage tm = (TextMessage) message; System.out.println("Message received : " + tm.getText()); } catch (JMSException ex) { ex.printStackTrace(); } } }
Configuring JMS for older JBoss versions
- JBoss AS 7 / JBoss EAP 6 (Hornet Q)
JBoss AS 7 JMS destinations can be configured either by adding them in the core configuration file (standalone.xml/domain.xml) or via management interfaces such as the CLI :
Via CLI:
Add JMS queue:
[standalone@localhost:9999 /] jms-queue add –queue-address=queue1 –entries=queues/queue1
[standalone@localhost:9999 /] jms-queue add --queue-address=queue1 --entries=queues/queue1
Add JMS Topic:
[standalone@localhost:9999 /] jms-topic add --topic-address=topic1 --entries=topics/topic1
Via the configuration file:
<subsystem xmlns="urn:jboss:domain:messaging:1.1"> <hornetq-server> . . . . . . . . . . . <jms-destinations> <jms-queue name="testQueue"> <entry name="queue/test"/> </jms-queue> <jms-topic name="testTopic"> <entry name="topic/test"/> </jms-topic> </jms-destinations> </hornetq-server> </subsystem>
- JBoss AS 6 (HornetQ)
HornetQ configuration is located in JBoss 6 in deploy\hornetq.sar. You can add new Topic/Queues by adding them into hornetq-jms.xml file.
<queue name="testQueue"> <entry name="/queue/queueA"/> </queue> <topic name="testTopic"> <entry name="/topic/topicA"/> </topic>
- JBoss AS 5 (JBoss Messaging)
If you are running JBoss 5, which ships with JBoss messaging you can add the following XML (-service.xml) to your deploy folder:
<mbean code="org.jboss.jms.server.destination.QueueService" name="jboss.messaging.destination:service=Queue,name=queueA" xmbean-dd="xmdesc/Queue-xmbean.xml"> <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends> <depends>jboss.messaging:service=PostOffice</depends> </mbean> <mbean code="org.jboss.jms.server.destination.TopicService" name="jboss.messaging.destination:service=Topic,name=topicA" xmbean-dd="xmdesc/Topic-xmbean.xml"> <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends> <depends>jboss.messaging:service=PostOffice</depends> </mbean>
- JBoss AS 4 (JBoss MQ)
If you using JBoss older JMS provider, you can add the following XML (-service.xml) to your deploy folder:
<mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=queueA"> <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends> </mbean> <mbean code="org.jboss.mq.server.jmx.Topic" name="jboss.mq.destination:service=Queue,name=topicA"> <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends> </mbean>