Using a Message Broker - PART 1: Docker Image
In this guide, we will extend the example created in WildFly Java Microservice - PART 1: Docker Image and add an external Message Broker connectivity.
Prerequisites
To complete this guide, you need:
External Message Broker
Apache Artemis
We will use Apache Artemis in this guide in its containerized version: see Artemis Official Image.
Start Apache Artemis:
podman network create demo-network
podman run --rm --name my-artemis \
--network=demo-network \
-p 8161:8161 \
-p 61616:61616\
-e AMQ_USER=admin \
-e AMQ_PASSWORD=admin \
-e AMQ_DATA_DIR=//home/jboss/data \
quay.io/artemiscloud/activemq-artemis-broker-kubernetes:latest
Note
|
we started the container with the --rm flag: this way it is disposed of automatically when we stop it
|
Note
|
We started the my-artemis container with the --network=bridge option: later in this guide, this will allow us to connect to the my-artemis container from the my-jms-app container; |
Maven Project
pom.xml
dependencies
Add the following dependencies to the pom-xml
file dependencies
section:
<dependency>
<groupId>jakarta.ejb</groupId>
<artifactId>jakarta.ejb-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.jms</groupId>
<artifactId>jakarta.jms-api</artifactId>
<scope>provided</scope>
</dependency>
wildfly-maven-plugin
We need to add some features that are necessary when to connect to the broker and to support a Message Driven Bean.
We can add these features by adding the remote-activemq
layer to our application; add the following to the the wildfly-maven-plugin configuration in the pom.xml
file:
<layers>
…
<layer>ejb</layer>
<layer>remote-activemq</layer>
…
</layers>
You should end up with the wildfly-maven-plugin configured like in the following:
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>5.0.0.Final</version>
<configuration>
<feature-packs>
<feature-pack>
<location>org.wildfly:wildfly-galleon-pack:32.0.0.Final</location>
</feature-pack>
<feature-pack>
<location>org.wildfly.cloud:wildfly-cloud-galleon-pack:7.0.0.Final</location>
</feature-pack>
</feature-packs>
<layers>
<layer>cloud-server</layer>
<layer>ejb</layer>
<layer>remote-activemq</layer>
</layers>
</configuration>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
Java Classes
Add the following classes to the project:
package org.wildfly.examples.mdb;
import jakarta.ejb.ActivationConfigProperty;
import jakarta.ejb.MessageDriven;
import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.MessageListener;
import jakarta.jms.TextMessage;
import java.util.logging.Logger;
@MessageDriven(
name = "GettingStartedQueueMDB",
activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "queue/gettingStartedQueue"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "jakarta.jms.Queue"),
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")}
)
public class GettingStartedQueueMDB implements MessageListener {
private static final Logger LOGGER = Logger.getLogger(GettingStartedQueueMDB.class.toString());
public void onMessage(Message rcvMessage) {
TextMessage msg = null;
try {
if (rcvMessage instanceof TextMessage) {
msg = (TextMessage) rcvMessage;
LOGGER.info("Received Message from queue: " + msg.getText());
} else {
LOGGER.warning("Message of wrong type: " + rcvMessage.getClass().getName());
}
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
}
package org.wildfly.examples;
import jakarta.annotation.Resource;
import jakarta.inject.Inject;
import jakarta.jms.JMSContext;
import jakarta.jms.JMSDestinationDefinition;
import jakarta.jms.JMSDestinationDefinitions;
import jakarta.jms.JMSException;
import jakarta.jms.Queue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@JMSDestinationDefinitions(
value = {
@JMSDestinationDefinition(
name = "java:/queue/gettingStartedQueue",
interfaceName = "jakarta.jms.Queue",
destinationName = "getting-started-queue",
properties = {"enable-amq1-prefix=false"}
)
}
)
@Path("/message")
public class GettingStartedQueueEndpoint {
@Resource(lookup="java:/queue/gettingStartedQueue")
private Queue queue;
@Inject
private JMSContext context;
@GET
@Path("/send")
@Produces(MediaType.TEXT_PLAIN)
public Response sendMessage(final @QueryParam("content") String content) throws JMSException {
String response = "Sent " + content + " to " + queue.getQueueName();
context.createProducer().send(queue, content);
return Response.ok(response).build();
}
}
Build the application
$ mvn clean package
...
[INFO] Copy deployment /home/ehugonne/dev/wildfly/guides/get-started-microservices-on-kubernetes/simple-microservice-jms/target/ROOT.war to /home/ehugonne/dev/wildfly/guides/get-started-microservices-on-kubernetes/simple-microservice-jms/target/server/standalone/deployments/ROOT.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.848 s
[INFO] Finished at: 2024-07-18T10:06:17+02:00
[INFO] ------------------------------------------------------------------------
Docker Image
Build the Docker Image
Build the Docker Image with the following command:
$ podman build -t my-jms-app:latest .
STEP 1/3: FROM quay.io/wildfly/wildfly-runtime:latest
STEP 2/3: COPY --chown=jboss:root target/server $JBOSS_HOME
-→ 4609f8ed0c7f
STEP 3/3: RUN chmod -R ug+rwX $JBOSS_HOME
COMMIT my-jms-app:latest
-→ db4677f5bf4f
Successfully tagged localhost/my-jms-app:latest
db4677f5bf4f471f5624bd63a21fce3d91b7b3b93e985d3e86a8a4b0682d85cd
Run the Docker Image
Note that, when running the my-jms-app:latest
Docker Image:
podman run --rm --network=demo-network -p 8080:8080 -p 9990:9990 \
--name=my-jms-app \
-e JBOSS_MESSAGING_CONNECTOR_HOST=my-artemis \
my-jms-app:latest
Note
|
We started the my-jms-app container with the --network=demo-network option just like we did when we started the my-artemis container: the two containers now run in the same demo-network network and we can connect to my-artemis container from the my-jms-app container using the my-artemis name.
|
Check the application
Hit the following URLs, using a utility like curl
:
$ curl -X GET http://localhost:8080/hello/message/send?content=Hello%20World
Sent Hello World to getting-started-queue