JMS 2.0 Early Draft - Simplified API Sample Code


Java Message Service (JSR 343) is undergoing a major revision as part of Java EE 7. The Early Draft of the specification has been available for a few weeks now and online javadocs are now available. Several other specifications such as JPA 2.1, JAX-RS 2.0, EJB 3.2, JavaServer Faces 2, and CDI 1.1 in the Java EE 7 umbrella have released early drafts. Some of the specs have been explained in detailed:
This blog will provide an update on JMS 2.0 Early Draft.

JMS 1.1 was released in Dec 2003. A lot has chnged in the Java landscape since then - think about annotations, generics, auto-closeable, dependency injection, and a lot more. The Java EE platform itself has evolved extensively since then, especially Java EE 6 is a "game changer". There are multiple JMS implementations still running solid and so there is lot of development/deployment experience on that as well. Keeping all of that, and much more, in mind, the main goals of JMS 2.0 are:
  • Changes to improve ease of development
  • Clarification of relationship between the JMS and other Java EE specifications
  • Definition of a new mandatory API to allow any JMS provider to be integrated with any Java EE application server
  • Extensions to support Java EE 7
  • Other enhancements as requested by the community
This blog will take a code sample from the section 11.4 of the Early Draft to highlight how ease-of-development changes are now coming to JMS 2.0.

This is how a message is sent using the existing JMS API:

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

@Resource(lookup="jms/inboundQueue")
Queue inboundQueue;

public void sendMessageOld (String payload) {
Connection connection = null; try {
connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer messageProducer = session.createProducer(inboundQueue); TextMessage textMessage = session.createTextMessage(payload); messageProducer.send(textMessage); } catch (JMSException e) {
// do something
} finally {
try {
if (connection != null)
connection.close();
} catch (JMSException e2) {
// do something else
}
} }
This works very well but several issues with it:
  1. Multiple intermediate objects such as Connection, Session, and MessageProducer need to be created in order to send a message. All these objects serve a purpose but makes the JMS application more complicated. It also leads to lots of boilerplate code as well.
  2. The arguments to createSession are confusing. The first argument specifies whether the session is transacted or not. The second argument specifies, how, if you used the session to receive messages, how those messages would be acknowledged. These two arguments are not independent. If the first argument is set to true then the second argument is irrelevant. So we only need one argument here.

    The other part is when this method is in a EJB then the transactions are controlled by the container. Or if a bean-managed transactions are used then the transaction would be started and committed using the UserTransaction API, not by methods in the JMS API. In fact, the EJB spec says that if this code is running in a transaction then the arguments to createSession are completely ignored. And even then we are required to supply some arguments here to satisfy the contract.
  3. The Connection need to explicitly closed in the finally block in order to release the resources appropriately on the server side. The code does not even show closing of MessageProducer and Session and And the finally block gets ugly with nested exceptions.

Now lets take a look at how the new API will simplify the programming model:

@Resource(lookup = "jms/connectionFactory")
ConnectionFactory connectionFactory;
@Resource(lookup="jms/inboundQueue") Queue inboundQueue;
public void sendMessageNew (String payload) { try (JMSContext context = connectionFactory.createContext();){ context.send(inboundQueue,payload); } }
Simple, isn't it ?

Here are the main changes:
  1. All the boilerplate is gone. Instead just create a ConnectionFactory, create a context from it, and invoke send on it.
  2. The destinatation (inboundQueue) is now specified on send insead of MessageProducer.
  3. Connection is now auto-closeable so try block will close it autoamatically.
  4. New methods throw runtime exception so the code looks much cleaner.

And if you are using Dependency Injection, then the code can be further simplified to:

@Inject
@JMSConnectionFactory("jms/connectionFactory")
private JMSContext context;
@Resource(mappedName = "jms/inboundQueue")
private Queue inboundQueue;
public void sendMessageNew(String payload) {
context.send(inboundQueue, payload);
}
Some clean ups to note here are ...
  • No need for application to instantiate JMSContext
  • The same injected JMSContext is available in other places, if within the same CDI scope
How cool is that ?

Here is yet another example on how the simplified API receives a message synchronously:

@Inject
@JMSConnectionFactory("jms/connectionFactory")
private JMSContext context;
@Resource(lookup="jms/inboundQueue") Queue inboundQueue;
public String receiveMessageNew() { JMSConsumer consumer = context.createConsumer(inboundQueue); return consumer.receivePayload(String.class); }

The section 11.4 of the JMS 2.0 Early Draft provide more lot more samples with the standard (or existing) API and the simplified (or new) API.

Do you like the direction that the JMS 2.0 Expert Group is taking ? Would you like to provide feedback and contribute ?

The latest progress on JMS 2.0 can be tracked at:

Help us make JMS 2.0 better, simpler, easier to use. Join users@jms-spec and contribute!

Comments:

This is a great change into Java Messaging Technology.I am so impressed........

Posted by Rahi Akela on April 21, 2012 at 06:31 AM PDT #

Looks good, better late than never.

I was able to do something similar with the spring jmsTemplate (http://bit.ly/9MfgnA) since 2007.

Posted by Kamal Govindraj on April 22, 2012 at 06:01 AM PDT #

Great use of Java 7 features and the code is terse and also the code is easier to understand and maintain.

Posted by Ramandeep Nanda on April 23, 2012 at 04:59 AM PDT #

I'm quite happy to see that CDI comes into play wit JMS. However, it would be an error not to know how to get rid of the default proposed behaviour. Great illusion would be to think of JMS as simply put a message on Queue/Topic and trust the defaults. A real messaging base in a business context is often pondered of custom needs defined in the software architecture/strategy: durability, availability, filters, ...
As always, CDI can be considered here quite welcome, but it won't be in most cases accepted in terms of default behaviour.

Posted by guest on July 10, 2012 at 01:27 AM PDT #

My nvidia hardware and software, which I wanted to update, came back with the message that they required the latest version of Java, and sent me to this website. I see nothing at this website which allows me to download the latest version of Java. I'm not interested in an "early draft". You geeks will never learn to communicate with ordinary people. How do I get "the latest version of Java?"

Posted by guestRichard Sherman on December 26, 2012 at 11:23 PM PST #

The latest version of Java can be downloaded from:

http://www.oracle.com/technetwork/java/javase/downloads/index.html

Posted by Arun Gupta on December 27, 2012 at 07:30 AM PST #

Post a Comment:
Comments are closed for this entry.
About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today