Getting Started with the HornetQ Messaging System
Join the DZone community and get the full member experience.
Join For FreeMessaging systems (or MOM for Message-oriented middleware) are systems focused on sending and receiving messages to increase the interoperability, flexibility and the performance of applications. They decouple the producers of messages from the consumers. The producers and consumers of messages are completely independent and are not aware of each other spatially (they can run on different nodes) and temporally (they do not need to be running at the same time, the producers can send messages even if there is no consumers and vice versa). This allows to create systems more flexible and loosely coupled than using remote procedure calls (or RPC).
Messaging systems are often used to implement as message bus which loosely couples heterogeneous systems together. Using a message bus to decouple disparate systems allows the systems to grow independtly and adapt more easily. It provides more flexibility to add new systems or update existing ones since they don't have brittle tight-coupled dependencies on each other.
Features
Current release
The current release of HornetQ is 2.0.0.
This release is the first release of HornetQ, why does it start at 2? Actually, HornetQ is the spiritual successor from JBoss Messaging. As the team was developing the next generation of JBoss Messaging, it realized that it was such a change in scope and design from the previous project than it was renamed to emphasis its new broader scope.
- Documentation and examples
- HornetQ ships with more than 80 examples showing all the features one by one to help the user understand them. The documentation is task-orientated and describes for each feature its goal, its use and its configuration.
- JMS 1.1 API - HornetQ provides the full JMS 1.1 API (connection, session, destinations, etc.) and more (dead letter, expiry queue, last value queue, preack mode)
- Optimised Core API - HornetQ also provides its own client side API which goes beyond what is possible with JMS to take advantage of all the features offered by HornetQ which are not available through the JMS API
- Flexible integration - HornetQ is small, with few dependencies and can be used to suit your need. You can run it standalone, integrated into JBoss Application Server or in other dependency injection frameworks, or directly instantiated from your code: it is your choice to integrate it as it fits.
- JavaEE support - In addtion to JMS, HornetQ provide support for additional JavaEE API used for enterprise applications. HornetQ is a fully functional XAResource which can be enlisted in any JTA transaction. HornetQ also provides a JCA adaptor that can be used by Java EE application servers to consume message via Message-Driven Beans
- Multiple transport choices - HornetQ low level transport is completely pluggable. Two implementations are provided: one is using Netty to communicate remotely and the other is a in-vm implementation to connect clients and servers running inside the same Java Virtual Machine. The Netty implementation provides support for TCP, SSL, HTTP and Servlet.
- Management - HornetQ provides an extensive management API that can be accessed using JMX. Alternatively, it is possible to manage HornetQ by sending messages to a special management address. In the same way, management notifications emitted by HornetQ servers can be received using JMX or by consuming messages.
- High-performance journal for message persistence - HornetQ provides message persistence using its own built-in, high performance journal. This journal is a unique piece of technology that automatically detects if HornetQ is running on Linux and uses Linux AIO via a native code layer for astonishing performance. If AIO is not available, the journal seamlessly falls back to using Java NIOto offer great performance on any Java platform. HornetQ 2.0.0 performance has been published using on SPECjms2007.
There are many other features which are described on HornetQ Features wiki page.
Getting Started with HornetQ
The best way to getting started with HornetQ is to download it and run one of the examples.
- Download HornetQ distribution:
$ wget http://sourceforge.net/projects/hornetq/files/2.0.0.GA/hornetq-2.0.0.GA.zip/download
- Unzip it
$ unzip hornetq-2.0.0.GA.zip
- Go to the JMS Queue example:
$ cd hornetq-2.0.0.GA/examples/jms/queue
- Run the example with build.sh:
$ ./build.sh
...
[java] Sent message: This is a text message
[java] Received message: This is a text message
[java] example complete
[java]
[java] #####################
[java] ### SUCCESS! ###
[java] #####################
This example starts one HornetQ server, sends and receives a JMS text message on a Queue and stops the server.
From there, the next step is to read the documentation to know which jars are required on the client side to use HornetQ and start sending and receiving messages from your application.
Client example
Let's write some code now. We will use a standalone ready-to-use HornetQ server and write a JMS client to send and receive messages on a queue.
First, let's start the server from the HornetQ distribution:
$ cd hornetq-2.0.0.GA/bin/
$ ./run.sh
...
HornetQ Server version 2.0.0.GA (Hornet Queen, 113) started
Now, we write a simple JMS client which will connect to the HornetQ server and use the JMS Queue /queue/ExampleQueue available on the server:
// Step 1. Create an initial context to perform the JNDI lookup.
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.PROVIDER_URL, "jnp://localhost:1099");
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces ");
Context ctx = new InitialContext(env);
// Step 2. Lookup the connection factory
ConnectionFactory cf = (ConnectionFactory)ctx.lookup("/ConnectionFactory");
// Step 3. Lookup the JMS queue
Queue queue = (Queue)ctx.lookup("/queue/ExampleQueue");
// Step 4. Create the JMS objects to connect to the server and manage a session
Connection connection = cf.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Step 5. Create a JMS Message Producer to send a message on the queue
MessageProducer producer = session.createProducer(queue);
// Step 6. Create a Text Message and send it using the producer
TextMessage message = session.createTextMessage("Hello, HornetQ!");
producer.send(message);
System.out.println("Sent message: " + message.getText());
// now that the message has been sent, let's receive it
// Step 7. Create a JMS Message Consumer to receive message from the queue
MessageConsumer messageConsumer = session.createConsumer(queue);
// Step 8. Start the Connection so that the server starts to deliver messages
connection.start();
// Step 9. Receive the message
TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
System.out.println("Received message: " + messageReceived.getText());
// Finally, we clean up all the JMS resources
connection.close();
// Step 1. Create an initial context to perform the JNDI lookup.
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.PROVIDER_URL, "jnp://localhost:1099");
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces ");
Context ctx = new InitialContext(env);
// Step 2. Lookup the connection factory
ConnectionFactory cf = (ConnectionFactory)ctx.lookup("/ConnectionFactory");
// Step 3. Lookup the JMS queue
Queue queue = (Queue)ctx.lookup("/queue/ExampleQueue");
// Step 4. Create the JMS objects to connect to the server and manage a session
Connection connection = cf.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Step 5. Create a JMS Message Producer to send a message on the queue
MessageProducer producer = session.createProducer(queue);
// Step 6. Create a Text Message and send it using the producer
TextMessage message = session.createTextMessage("Hello, HornetQ!");
producer.send(message);
System.out.println("Sent message: " + message.getText());
// now that the message has been sent, let's receive it
// Step 7. Create a JMS Message Consumer to receive message from the queue
MessageConsumer messageConsumer = session.createConsumer(queue);
// Step 8. Start the Connection so that the server starts to deliver messages
connection.start();
// Step 9. Receive the message
TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
System.out.println("Received message: " + messageReceived.getText());
// Finally, we clean up all the JMS resources
connection.close();
To run this code, you need to add the following jars to your classpath:
- hornetq-core-client.jar -- HornetQ client library
- hornetq-jms-client.jar -- client implementation of the JMS API
- netty.jar -- the high-performance client/server socket framework
- hornetq-transports.jar -- integration code to use Netty with HornetQ
- jnp-client.jar -- JNDI library
Once the code is compiled, you can run it:
Sent message: Hello, HornetQ!
Received message: Hello, HornetQ!
Such a simple example does not relect how powerful and flexible messaging systems really are. They really shine on complex heterogeneous systems where they help manage complexity and increase performance by decoupling systems.
Integration
HornetQ server is designed using POJOs to make it simple to integrate it in multiple environments.
HornetQ adapts to your specific environment and not the opposite. It can be run standalone (leveraging JBoss Microcontainer) or you can directly instantiate HornetQ POJOs in your code to embed a server.
HornetQ distribution contains scripts to deploy it in JBoss AS 4 & 5 and it will be the default messaging system in JBoss AS 6.
Finally, HornetQ will also be used by next release of TorqueBox to provide task queues to Ruby applications.
Advanced Features
HornetQ provides advanced constructs to help applications use recurring messaging patterns. Let's introduce some of them.
Core Bridges
Core bridges are used to create message flows
between two HornetQ servers which are remotely separated.
Core bridges are resilient and will cope with temporary connection failure allowing them to be an ideal choice for
forwarding over unreliable connections, e.g. a WAN.
Core Bridges are configured and managed by the HornetQ servers so that you do not have to deal with them manually.
An example of Core bridge configuration looks like:
<!-- the bridge will consume message from the "source" and forward them to the "target" -->
<bridge name="my-bridge">
<queue-name>jms.queue.source</queue-name>
<forwarding-address>jms.queue.target</forwarding-address>
<reconnect-attempts>-1</reconnect-attempts>
<connector-ref connector-name="target-connector"/>
</bridge>
Diverts
Diverts allow messages to be transparently
"diverted" or copied from one address to another with just some simple configuration defined on the server side.
Diverts can be exclusive -- the message is diverted to the new address and does not go to the old address at all --
or non-exclusive -- the message goes to old address and a copy of the message is also sent to the new address.
For example, non-exclusive diverts can therefore be used for splitting message flows if there is a requirement to monitor every order sent to an order queue without making any changes to the client application logic .
An example of divert configuration looks like:
<!-- the divert will divert messages sent to the "orders" queue and also send them to the "monitoring" topic -->
<divert name="order-divert">
<address>jms.queue.orders</address>
<forwarding-address>jms.topic.monitoring</forwarding-address>
<exclusive>false</exclusive>
</divert>
JMS Bridges
JMS bridges
can consume JMS messages from a source JMS destination and send them to a target JMS destination, typically on a different server.
Like a Core bridge, the JMS bridge have built-in resilience to failure
so if the source or target server connection is lost, e.g. due to
network failure, the bridge will retry connecting to the source and/or
target until they come back online. When it comes back online it will
resume operation as normal.
Unlike Core bridge, the JMS bridge an also be used to bridge messages from other JMS servers than HornetQ, as long as they are JMS 1.1 compliant. This helps migrating applications to HornetQ by providing a bridge to a previous legacy messaging systems during the migration phase.
Want more?
This is a brief introduction to HornetQ and lots of powerful features have not been mentioned (clustering, high availability, flow control, paging, etc.). If you want more information, the web site is the primary source of information.
The latest release's quick start guide and user manual will have you sending and receiving messages in no time. If you encounter issues, ask the community on the user forum or open JIRA issues.
You can also follow the project on Twitter and on the project blog.
Getting involved?
If you want to get involved in the project, come join the team on #hornetq IRC channel.
Opinions expressed by DZone contributors are their own.
Comments