Tuesday Jun 25, 2013

JMSContext, @JMSDestinationDefintion, DefaultJMSConnectionFactory with simplified JMS API: TOTD #213


"What's New in JMS 2.0" Part 1 and Part 2 provide comprehensive introduction to new messaging features introduced in JMS 2.0. The biggest improvement in JMS 2.0 is introduction of the "new simplified API". This was explained in the Java EE 7 Launch Technical Keynote. You can watch a complete replay here.

Sending and Receiving a JMS message using JMS 1.1 requires lot of boilerplate code, primarily because the API was designed 10+ years ago. Here is a code that shows how to send a message using JMS 1.1 API:

@Stateless
public class ClassicMessageSender {

@Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
ConnectionFactory connectionFactory;

@Resource(mappedName = "java:global/jms/myQueue")
Queue demoQueue;

public void sendMessage(String payload) {
  Connection connection = null;
    try {
      connection = connectionFactory.createConnection();
      connection.start();
      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      MessageProducer messageProducer = session.createProducer(demoQueue);
      TextMessage textMessage = session.createTextMessage(payload);
      messageProducer.send(textMessage);
    } catch (JMSException ex) {
      ex.printStackTrace();
    } finally {
      if (connection != null) {
        try {
          connection.close();
        } catch (JMSException ex) {
          ex.printStackTrace();
        }
      }
    }
  }
}

There are several issues with this code:
  • A JMS ConnectionFactory needs to be created in a application server-specific way before this application can run.
  • Application-specific destination needs to be created in an application server-specific way before this application can run.
  • Several intermediate objects need to be created to honor the JMS 1.1 API, e.g. ConnectionFactory -> Connection -> Session -> MessageProducer -> TextMessage.
  • All APIs throw checked exceptions and so try/catch block must be specified.
  • Connection need to be explicitly started and closed, and that bloats even the finally block.
The new JMS 2.0 simplified API code looks like:


@Stateless
public class SimplifiedMessageSender {

  @Inject
  JMSContext context;

  @Resource(mappedName="java:global/jms/myQueue")
  Queue myQueue;

  public void sendMessage(String message) {
    context.createProducer().send(myQueue, message);
  }
}

The code is significantly improved from the previous version in the following ways:
  • The JMSContext interface combines in a single object the functionality of both the Connection and the Session in the earlier JMS APIs.  You can obtain a JMSContext object by simply injecting it with the @Inject annotation. This of course works only in Java EE Web or EJB applications and does not apply in Java SE-based applications where injection is not available.
  • No need to explicitly specify a ConnectionFactory. A default ConnectionFactory under the JNDI name of
    java:comp/DefaultJMSConnectionFactory
    is used if no explicit ConnectionFactory is specified.
  • The destination can be easily created using newly introduced @JMSDestinationDefinition as:
    @JMSDestinationDefinition(name = "java:global/jms/myQueue",
            interfaceName = "javax.jms.Queue")

    It can be specified on any Java EE component and the destination is created during deployment.
  • Creating JMSConsumer also starts the connection so there is no need to explicitly start it.
  • JMSContext, Session, Connection, JMSProducer and JMSConsumer objects are now AutoCloseable. This means that these resources are closed automatically by the management of try-with-resources statement.
  • New simplified API throws a new unchecked exception, JMSRuntimeException. This means try/catch blocks are not required.
  • Method chaining on JMSProducers allows to use builder patterns.
  • No need to create separate Message object, you can specify the message body as an argument to the send() method instead.

Want to try this code ? Download source code!

Download Java EE 7 SDK and install.
Start GlassFish: bin/asadmin start-domain
Build the WAR (in the unzipped source code directory): mvn package
Deploy the WAR: bin/asadmin deploy <source-code>/jms/target/jms-1.0-SNAPSHOT.war

And access the application at http://localhost:8080/jms-1.0-SNAPSHOT/index.jsp to send and receive a message using classic and simplified API.

A replay of JMS 2.0 session from Java EE 7 Launch Webinar provides complete details on what's new in this specification:



Enjoy!

Sunday Apr 22, 2012

Great Indian Developer Summit 2012 Trip Report


I attended the fifth, and my first, Great Indian Developer Summit in the Silicon Valley of India, Bangalore. The conference is spread over 4 days with each day covering .NET, Web, Java, and Workshops respectively. The Java track had 800+ attendees (roughly based on a cursory headcount for the opening keynote) and the hall was packed. The theater style seating allowed the attendees to enjoy the wide screen presentations.

Another unique and cool thing about the conference is that they create life size posters of all the speakers and display them outside the speakers' room. This not only help you identify your room easily but also makes you feel like a celebrity ;-) Here are some pictures of the posters:






Venkat's opening keynote is always fun. He talked about "Refactor your Language Knowledge Portfolio: We're What We Can Code In". His entertaining presentation style keeps the audience engaged and laughing. His Essence vs Ceremony analogy was particularly impressive and I recommend reading that blog.

I gave three presentations and a hands-on workshop and the slides are now available.


This presentation gave an overview of JMS 2.0 and the new features coming there. This presentation had 200+ attendees and 50% of the audience were existing users of JMS. There was a lot interactivity during/after the session. Do you know JMS 2.0 Early Draft is already available ?

The primary goal of this specification is to provide a simplified API and clarify the ambiguities discovered over the past few years. Check out this blog for a quick comparison between the existing and the simplified API. If you have any feature request then its highly recommended to file a JIRA issue at jms-spec.java.net.



This presentation gave an overview of JAX-RS 2.0. Do you know that Early Draft 2 is already available ? Check out this blog for a brief overview of the new features coming in JAX-RS 2.0. You can find the latest updates at jax-rs-spec.java.net and also follow @gf_jersey.



This presentation explained the key concepts of how GlassFish PaaS-enable your Java EE application. The talk also showed how a Java EE application can be deployed where all he services required by the application are dynamically provisioned. A working version of the application, along with instructions, are available at glassfish.org/javaone2011. A video of the application in action is shown below:



The video also shows how the cluster dynamically adjusts to meet the elasticity constraints pre-defined for the application.

The Java EE 6 hands-on lab had about 20 attendees. The self-pace instructions can be downloaded here. I was pretty amazed by the level of interaction. There was one particular guy who who came from the PHP land, was taking notes on a paper notebook, and was asking the most intelligent questions. There were other experienced J2EE/Java EE users who also enjoyed the simplicity introduced in the platform.

And somehow for the past few days the question of Java EE 6 over Spring has come up during each such engagement. My views are clearly expressed at Why Java EE 6 is better than Spring. And do read the interesting discussion in the comments, all the way to the end.

The conference was well organized with a personal introduction of each speaker. The rooms were well marked and the projectors worked very well. The conference crew was very helpful and prompt in reminding about the time remaining. However a 45 minute session is a few minutes too short and so had to tweak my existing slide deck to meet the time requirements.

Multiple conflicting talks were arranged such as Mike's Java EE 7 and mine JMS 2.0, Venkat's "Java 8: A Sneak Peak" and Simon's "Java SE 8 & Beyond". This feedback was conveyed to the organizers. Hopefully they'll be able to do a better job of this next time around.

On a personal side, I enjoyed a team dinner at BBQ Nation and is definitely worth visiting once at least. And could also manage to enjoy a lunch at MTR with Vivek. The ITC Windsor is a nice hotel with a decent fitness center and a great restaurant. The breakfast buffet had a great variety and very scrumptious.

Here are some pictures captured from the event:










And now the complete album:


The Java EE 7 platform will be much more mature by this time next year and who knows I might even submit a Java EE 7 hands-on lab!

Thank you Salt March Media for putting up a great show and providing me an opportunity to present. Looking forward to my participation again next year!

Saturday Apr 21, 2012

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!

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