Kohei Nozaki's blog 

Entries tagged [jms]

In-container JMS consumer/producer example


Posted on Saturday May 14, 2016 at 11:06PM in Technology


In this entry, I’ll show you a complete example of using JMS in a Java EE 7 compliant application container, through creating a webapp which consists of both a consumer and a producer. we’re going to deploy it to a container (WildFly 10.0.0.Final) and see a webapp produces and consumes a message.

Launch the container

Launch WildFly server with the following parameter so the bundled message queue broker (ActiveMQ Artemis) will be launched:

./standalone.sh -c standalone-full.xml

For IntelliJ IDEA, check how to launch WildFly with -c standalone-full.xml from this SO: http://stackoverflow.com/questions/25849810/how-to-run-wildfly-with-standalone-full-xml-from-intellij-idea

Define a queue

Launch jboss-cli and define a queue with this command:

jms-queue add --queue-address=testQueue --entries=queue/test,java:jboss/exported/jms/queue/test

Check if it’s successfully created:

[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default/jms-queue=testQueue:read-resource
{
    "outcome" => "success",
    "result" => {
        "durable" => true,
        "entries" => [
            "queue/test",
            "java:jboss/exported/jms/queue/test"
        ],
        "legacy-entries" => undefined,
        "selector" => undefined
    }
}

Create the webapp which contains consumer/producer

Here we’re going to create following three classes in the webapp:

  • MyProducer: a Stateless Session Bean which produces a message to the queue

  • MyConsumer: a Message-Driven Bean which consumes any messages being sent to the queue

  • MyServlet: Receives HTTP GET request and kicks MyProducer

The whole project can be obtained from My GitHub repository.

MyProducer

@Stateless
@LocalBean
public class MyProducer {

    @Resource(mappedName = "java:/queue/test")
    Queue testQueue;
    @Inject
    JMSContext jmsContext;

    public void enqueue(final String text) {
        jmsContext.createProducer().send(testQueue, text);
    }
}

MyConsumer

@MessageDriven(name = "MyMDB", activationConfig = {
        @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/test"),
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")})
public class MyConsumer implements MessageListener {

    private final static Logger LOGGER = Logger.getLogger(MyConsumer.class.toString());

    @Override
    public void onMessage(final Message msg) {
        if (msg instanceof TextMessage) {
            try {
                final String text = ((TextMessage) msg).getText();
                LOGGER.info(() -> "Received: " + text);
            } catch (final JMSException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

MyServlet

@WebServlet(urlPatterns = "/")
public class MyServlet extends HttpServlet {

    @EJB
    MyProducer myProducer;

    @Override
    protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
        final String text = "Hello, JMS!";
        myProducer.enqueue(text);
        resp.getWriter().write("Published! check output of the consumer: " + text + "\n");
    }
}

Of course you don’t need to put MyConsumer to the webapp which contains MyProducer. this is just an example, and in fact, just for asynchronous/background processing in a webapp, you better use more simple EJB Asynchronous methods or ManagedExecutorService instead of JMS. for real use-case, you may create a dedicated app for queue consumers and place your MyConsumer equivalent into it.

Trigger producing and consuming

Deploy the app and submit HTTP GET request to it as follows.

$ curl http://localhost:8080/jms-example/

If it worked successfully, you’ll see following response from the Servlet:

Published! check output of the consumer: Hello, JMS!

Then check console/output/log of your application container. if the consumer worked successfully, you can see the output something like following:

13:55:18,168 INFO  [class jms.MyConsumer] (Thread-438 (ActiveMQ-client-global-threads-271921988)) Received: Hello, JMS!

Conclusion

As described above, thanks to JMS, we can develop a messaging app without tons of annoying, vendor-specific boilar plate code, in lean and simple semantics. there are no worries of maintaining logic of connection handling, polling loop and so forth in the application code.

And note that there are no use of vendor-specific classes - it uses only standardized API which comes from javaee-api. you may need to alter some portion of code when you deploy this example to other Java EE 7 compliant container such as GlassFish, WebLogic or WebSphere, but that should be few.