About Piotr Nowicki

Piotr is a Java fascinate since his computer science studies (2007). He's currently working as a senior Java EE developer in utilities and industry sector. He's mostly interested in designing and development of web applications using Java EE technology stack.

Java EE 7: JMS 2.0 With Glassfish v4

Java EE 7 has been recently accepted by the Executive Committee. This means that soon we should have Java EE 7 application servers available on the market. One of the specifications that constitutes Java EE 7 is JMS 2.0. Some interesting improvements were introduced since version 1.1.

JMS has a lot of weird stuff like: Connection#createSession(boolean transacted, int acknowledgeMode) method.

First method argument (transacted) defines if the session should be transacted. Java EE applications have JTA that takes care of transactions. We can choose if transactions are supported (default) or not. So why do we need this argument then?
 
Second method argument (acknowledgeMode) is an integer constant taken from Session object. Seriously, integers constants makes the API seems sooo legacy. Finally, what is a meaning of those parameters in Java EE environment? JavaDoc says that acknowledgeMode is ignored if the session is transacted.

What does it all means? Nothing less than: those arguments doesn’t have any sense for JMS producer used in Java EE context. That’s why they encourage you to use (true, 0) parameter values to avoid unnecessary confusion. This smells of legacy.

Ok, but let’s get back to the main subject. I wanted to take a look what’s new in JMS world and how it allows me to code easier and in more maintainable way. I’ve prepared a simple web application that uses JMS 2.0, JAX-RS and EJB (SLSB and MDB) and pushed it to my github repository here.

Prerequisites and Infrastructure

To be able to run this code you should create a sample queue. I’ve configured it under the jms/queue/myqueue JNDI name.

I was using Glassfish v4 build 87. To use Java EE 7 API I needed to add following Maven dependency:

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0-b87</version>
    <scope>provided</scope>
</dependency>

which resides in this repository:

<repository>
    <id>Java EE 7</id>
    <url>https://maven.java.net/content/groups/promoted/</url>
</repository>

And that’s all for the configuration.

Payload and REST Configuration

BusinessObject is a simple object that will act like a payload for our JMS messages. It will be sent by producer and received by consumer. Nothing fancy here, so let’s move along. RESTConfiguration is even simpler – it just defines JAX-RS endpoint prefix for our application. This prefix is: “/rest”. You can invoke producer EJB’s by accessing your application URL /rest/producer/jms11 or /rest/producer/jms20 (e.g. http://localhost:8080/jms2_0_spike/rest/producer/jms20).

JMS Producer

Now this is where things starts to be interesting. Below you can find JMS 1.1 code for a SLSB JMS message producer:

@Stateless 
public class JMS11Producer {

    @Resource(lookup = "jms/__defaultConnectionFactory")
    private ConnectionFactory connectionFactory;

    @Resource(lookup = "jms/queue/myqueue")
    private Queue queue;

    @Path("/jms11")
    @GET
    public String produce() {
        String status = "OK";

        Connection connection = null;
        try {
            connection = connectionFactory.createConnection();
            Session session = connection.createSession(true, 0);
            MessageProducer producer = session.createProducer(queue);

            BusinessObject payload = new BusinessObject(UUID.randomUUID().toString());

            ObjectMessage message = session.createObjectMessage();
            message.setObject(payload);

            producer.send(message);
        } catch (JMSException e) {
            status = e.getMessage();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    status = e.getMessage();
                }
            }
        }
        return status;
    }
}

Despite the JAX-RS result status fiddling, that’s an obnoxius lot of boilerplate code that fuzzies method main responsibility. It should just send a message to the queue but it does an awful lot of things. It creates a connection, session (nasty, ignored parameters included), object type message, initializes it and then finally sends the message to the queue… oh yeah – of course don’t forget about checked exceptions and nested try/catch blocks. We can try to optimize it — e.g. by moving Connection creation to some @PostConstruct method and closing to @PreDestroy — but it’s still a lot of unnecesary noise.

Now let’s take a look at functionally the same code expressed in JMS 2.0:

@Stateless 
public class JMS20Producer {

    @Resource(lookup = "jms/queue/myqueue")
    private Queue queue;

    @Inject
    private JMSContext jmsContext;

    @Path("/jms20")
    @GET
    public String produce() {
        BusinessObject payload = new BusinessObject(UUID.randomUUID().toString());

        jmsContext.createProducer().send(queue, payload);

        return "OK";
    }
}

Pretty neat, huh? It’s much easier to figure out what this method is doing: it creates a payload and sends it to the queue. That’s it – that’s all this method is about. Exception handling, connection and session creation, message type – everything is done for us. If those responsibilities can be moved to the container to ease developer’s life, so why not doing it?

Let’s take a look at few JMS 2.0 features used in this example:

  • no need for ConnectionFactory,
  • no need for Connection or Session,
  • JMSContext is a new object that combines Connection and Session capabilities; it can be injected by the container,
  • no checked exceptions – just JMSRuntimeException,
  • chain-invocation for message producing makes it easier to read.

JMS Consumer

Message Consumer hasn’t been changed so much since JMS 1.1. It’s still a MDB but now it’s easier to get to the expected payload because of message casting with message.getBody(Clazz):

@MessageDriven(mappedName = "jms/queue/myqueue") 
public class Consumer implements MessageListener {

    @Override
    public void onMessage(Message message) {
        try {
            // In JMS 1.1:
            //          ObjectMessage objectMessage = (ObjectMessage)message;
            //          BusinessObject payload = (BusinessObject)objectMessage.getObject();
            BusinessObject payload = message.getBody(BusinessObject.class);
            System.out.println("Message received: " + payload);
        } catch (JMSException e) {
            System.err.println("Error while fetching message payload: " + e.getMessage());
        }
    }
}

Conclusion

This was just a very quick glance at JMS 2.0. However, I found it interesting to see how much cleaner code can be produced in comparison to JMS 1.1. For more detailed information about JMS 2.0 take a look at its official specification.
 

Reference: Java EE 7: JMS 2.0 With Glassfish v4 from our JCG partner Piotr Nowicki at the Piotr Nowicki's Blog blog.
Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

2 Responses to "Java EE 7: JMS 2.0 With Glassfish v4"

  1. Kavinder Singh says:

    very nicely explained article for people who even don’t have idea about the JMS1.1 . Even I got the idea how this will work.

  2. Al says:

    Useless. J2EE tutorial already shows all of this. How about you show how to connect using a Java client instead? That is almost impossible to find on the web.

Leave a Reply


4 + = five



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books