In this recipe we are going to create a very simple JMS application that places a message on a queue in ActiveMQ and consumes that message from the queue immediately after. This example demonstrates many of the JMS APIs that we will be using in the future recipes.
In this recipe, we will be referencing the simple-jms-application
project that contains the full working code and Maven POM file. You should have a default installation of the ActiveMQ Broker running before attempting to execute the sample application in this recipe.
To run the sample for this recipe you will need to perform the following steps:
Open a terminal and start an instance of the ActiveMQ Broker.
Open a second command-line window, change to the directory where the
simple-jms-application
project is located, and execute the following command:mvn compile exec:java
This will build and run the sample application and you should see an output similar to the following, assuming everything goes well:
INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------ [INFO] Building Simple-JMS-Application 1.0 [INFO] ------------------------------------------------------------------ [INFO] Starting SimpleJMS example now... Producer sent a Message Consumer received a Message, it reads: Woohoo! Finished running the SimpleJMS example. [INFO] ------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------ [INFO] Total time: 1.249s [INFO] Finished at: Mon Feb 25 17:19:30 EST 2013 [INFO] Final Memory: 6M/265M [INFO] ------------------------------------------------------------------
Now that we've run the example, let's take a look at the code and see how it works. The complete source code is located in the file SimpleJMS.java
in the example simple-jms-application
. You are encouraged to open the file and refer to it during this discussion.
This example defines three methods: before()
, run()
, and after()
, which we call in sequence. Each of these methods breaks out the basic steps you must do in any JMS application:
public class SimpleJMS { private final String connectionUri = "tcp://localhost:61616"; private ActiveMQConnectionFactory connectionFactory; private Connection connection; private Session session; private Destination destination; public void before() throws Exception { connectionFactory = new ActiveMQConnectionFactory(connectionUri); connection = connectionFactory.createConnection(); connection.start(); session = connection.createSession( false, Session.AUTO_ACKNOWLEDGE); destination = session.createQueue("MyQueue"); }
In the before()
method we set up our connection to the ActiveMQ Broker and create the basic JMS boilerplate objects that we'll use in the run()
method later. The setup here proceeds as follows:
Create a new JMS
ConnectionFactory
using the concrete typeActiveMQConnectionFactory
, which is provided in the ActiveMQ client library. TheConnectionFactory
is supplied the URI of our running broker, namely,tcp://localhost:61616
. EveryActiveMQConnectionFactory
needs a URI telling where and how to connect to the broker.Create a new JMS
Connection
object by invoking theConnectionFactory
object'screateConnection
method. If the connection to the broker cannot be created we will get an exception at this point.We can now start our new
Connection
. A JMSConnection
object won't deliver any messages to yourMessageConsumer
until you start it so it's very important to remember to callconnection.start()
.Create a new JMS
Session
object by calling theConnection
object'screateSession()
method. SinceSession
requires a message acknowledgement mode, we specify that in thecreateSession()
method. We choose auto acknowledgement mode so we don't have to worry about manually acknowledging messages in this simple application.Finally we create a
Destination
object that our application'sproducer
andconsumer
will use to send and receive our simple message. In our example we create a queue but it would work exactly the same if we had used a Topic domain for this simple example.
Once the before()
method completes, our little application is ready to go; so we next call the run()
method to do the work. The code for the run()
method is shown next:
Tip
Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
public void run() throws Exception { MessageProducer producer = session.createProducer(destination); try { TextMessage message = session.createTextMessage(); message.setText("Woohoo!"); producer.send(message); } finally { producer.close(); } MessageConsumer consumer = session.createConsumer(destination); try { TextMessage message = (TextMessage) consumer.receive(); } finally { consumer.close(); } }
This method is divided into two parts, one of which performs the send of our simple message and then our attempts to receive it. Let's break down the send portion first:
Using the
Session
we created earlier, we first create aMessageProducer
; this is the object that will allow us to send our simple message.Create a new
TextMessage
object using theSession
object and assign it a payload at the same time.Send the message using the
MessageProducer
object'ssend()
method. TheMessageProducer
object knows where to send the message since we passed in aDestination
object when we created it.Finally, we close down the
MessageProducer
object since we won't use it again in this application.
Now that we've seen how a message is sent, we can look at how receiver code works:
First we create a
MessageConsumer
object usingSession
just as we did for theMessageProducer
previouslyWe use the
MessageConsumer
object blocking thereceive()
call to wait for the broker to route the message we sent previously to our producerOnce we receive the message we need to cast it to the correct type since the
receive()
method returns a base message referenceWe print out a little message showing the payload of the
TextMessage
we sent previouslyFinally, we close down our consumer since we are done with that as well
All that's left is to call the after()
method, which simply closes the Connection
object we opened in the before()
method and our application comes to an end.
public void after() throws Exception { if (connection != null) { connection.close(); } }
Closing Connection
will take care of closing out any resources created by the connection, so we omit the call to the close()
method of our Session
.
This simple application demonstrates many of the elements of the JMS API that you will use in the messaging applications that you write in the future. Unlike our future examples this one incorporates both a producer and consumer within the same application. In our future examples, we will generally break apart the producer and consumer into separate applications for a more realistic demonstration.
Before we move onto the remainder of the examples in this book, it's a good idea to understand the Maven project files that build and run our projects. A Maven POM file defines the various modules of a project and allows us to specify all the required libraries we need to be assembled in order for our project to run. Maven also allows for various plugins to be specified in the POM file that can perform actions beyond just compiling code and downloading dependencies. Let's take a look at the POM file that we used to run our first application, it's located in the directory of our simple-jms-application
example:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.apache.activemq.recipes</groupId> <artifactId>SimpleJMS</artifactId> <version>1.0</version> <name>Simple-JMS-Application</name> <description>A simple JMS application</description> <dependencies> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-client</artifactId> <version>5.8.0</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.2</version> </dependency> </dependencies> </project>
As you can see, the POM file is just a basic XML file with sections for project dependencies and a section for specifying the plugins used in the build process.
Take note of the dependencies that we specified in our SimpleJMS application's POM file. We only needed to bring in the <activemq-client>
dependency and a log4j plugin so that the ActiveMQ client knows what logger our project is using. Maven figures everything else out for us so that we don't have to fuss with classpath issues and just focus on our ActiveMQ skills. It's good to get an idea of how Maven works if you haven't used it already as it can greatly streamline your build process.
In our SimpleJMS application we created a connection to the ActiveMQ Broker by creating an instance of ActiveMQConnectionFactory
and giving it a URI string that told it how to connect to ActiveMQ. We used the string, tcp://localhost:61616
in our example, which tells the client that it should use a TCP-style connection to connect to the broker on port 61616. ActiveMQ supports a number of different connection options beyond TCP such as SSL, HTTP, NIO, and more. You can get more information on how to use those connection types and on configuration options that can be added to the URI string on the ActiveMQ website, the following links provide an overview of the connection URI configuration syntax and options: