This is a simple Java web application demonstrating the use of the Java Message Service (JMS) with Jakarta EE. The application consists of a message producer (a servlet) and a message consumer (a Message-Driven Bean).
- Jakarta EE 10: The application is built on the Jakarta EE platform, which provides the APIs for developing and running enterprise Java applications.
- Java Message Service (JMS) 3.1: JMS is a Java API that allows applications to create, send, receive, and read messages. It enables loosely coupled, reliable, and asynchronous communication between different components of a distributed application.
- Maven: This project uses Maven for dependency management and building.
The project has one main dependency declared in the pom.xml:
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>10.0.0</version>
<scope>provided</scope>
</dependency>This dependency provides all the necessary Jakarta EE APIs, including JMS. The scope is set to provided because the application server (like GlassFish, WildFly, or Payara) will provide the implementation of these APIs at runtime.
This project demonstrates a simple Publish/Subscribe messaging model using a JMS Topic.
-
ConnectionFactory: A
ConnectionFactoryis an object that a client uses to create a connection with a JMS provider. It is the entry point to the JMS API. In this project, theConnectionFactoryis injected using the@Resourceannotation:@Resource(lookup = "jms/myDefaultConnectionFactory") private ConnectionFactory factory;
The
lookupattribute specifies the JNDI name of the resource. -
Topic: A
Topicis a type of JMS destination used for publish/subscribe messaging. Messages are published to a topic, and all subscribed consumers will receive a copy of the message. TheTopicis also injected via@Resource:@Resource(lookup = "myTopic") private Topic topic;
-
Message Producer: A
MessageProduceris an object created by aSessionthat sends messages to a destination (a topic or a queue). -
Message Consumer: A
MessageConsumeris an object created by aSessionthat receives messages sent to a destination. In this project, we use a Message-Driven Bean (MDB) as our consumer, which is a more modern and convenient approach in Java EE.
This servlet acts as the message producer. When you access the /test URL, it sends 10 text messages to the myTopic.
package lk.kaushalya.jms;
import jakarta.annotation.Resource;
import jakarta.jms.*;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/test")
public class Test extends HttpServlet {
// 1. Inject the ConnectionFactory and Topic resources
@Resource(lookup = "jms/myDefaultConnectionFactory")
private ConnectionFactory factory;
@Resource(lookup = "myTopic")
private Topic topic;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
// 2. Create a JMS Connection
Connection connection = factory.createConnection();
connection.start();
// 3. Create a JMS Session
// false -> not transacted
// AUTO_ACKNOWLEDGE -> The session automatically acknowledges a client's receipt of a message.
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 4. Create a Message Producer from the Session to the Topic
MessageProducer producer = session.createProducer(topic);
// 5. Create and send 10 messages
for (int i = 1; i <= 10; i++) {
String line = "Default Connection Message " + i + " - JMS-SecondClient -";
TextMessage txtMessage = session.createTextMessage();
txtMessage.setText(line);
producer.send(txtMessage);
}
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
}Commented Code Explanation:
The Test.java servlet contains some commented-out code:
// InitialContext ic = new InitialContext();
// ConnectionFactory factory = (ConnectionFactory) ic.lookup("jms/myDefaultConnectionFactory");This shows the "old" way of looking up JNDI resources manually. Instead of manual lookup, the project uses @Resource annotation for dependency injection, which is a cleaner and more modern approach provided by Java EE.
// Topic topic = session.createTopic("newTopic");This line shows how you could create a topic programmatically. However, in this application, the topic is pre-configured on the application server and looked up via JNDI, which is the standard practice.
This is a Message-Driven Bean (MDB) that acts as a message consumer. It listens for messages on myTopic.
package lk.kaushalya.jms;
import jakarta.ejb.ActivationConfigProperty;
import jakarta.ejb.MessageDriven;
import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.MessageListener;
// 1. Declare this class as a Message-Driven Bean
@MessageDriven(activationConfig = {
// 2. Configure the MDB to listen on the "myTopic" destination
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "myTopic"),
})
public class MessageReceiver implements MessageListener {
// The onMessage method is automatically called by the container when a message arrives.
@Override
public void onMessage(Message message) {
try {
// 3. Extract the text from the message and print it to the console
System.out.println("MessageReceiver onMessage : "+message.getBody(String.class));
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
}The @MessageDriven annotation tells the EJB container that this bean is driven by messages. The activationConfig properties configure the MDB, specifying the JNDI name of the destination (myTopic) it should listen to.
When a message is published to myTopic, the container invokes the onMessage method of the MessageReceiver bean, passing the message as an argument.
- Prerequisites: You need a Jakarta EE 10 compatible application server (e.g., GlassFish 7, Payara Server, WildFly).
- Configure JMS Resources: You need to configure the JMS resources (
ConnectionFactoryandTopic) on your application server.- Connection Factory JNDI Name:
jms/myDefaultConnectionFactory - Topic JNDI Name:
myTopic
- Connection Factory JNDI Name:
- Build the Project: Build the project using Maven to produce a
.warfile.mvn clean install
- Deploy: Deploy the generated
JMS-WebApplication.warfile to your application server. - Test: Access the following URL in your browser:
http://localhost:8080/JMS-WebApplication/test(the host and port may vary depending on your server configuration). - Check the Output: Check the server logs. You should see the messages printed by the
MessageReceiver.