Comparing Messaging standards: JMS vs AMQP

In this article we will discuss about messaging standards that can be used to decouple sender and receiver of messages by means of a Messaging Broker. In this first article we will focus on the differences between JMS and AMQP.

Most of Java EE developers know that JMS is a the standard Java API for communicating with Message Oriented Middleware (MOM). As a matter of fact, JMS is a part of the Java JEE, and allows two different Java applications to communicate; those applications could be using JMS clients and yet still be able to communicate, yet kept being decoupled. It's considered to be robust and mature.

Since JMS is part of Java EE, it is typically used when both client and servers are running in a JVM. What if client and server are using a different language or platform ?

A common solution is to switch to a different protocol, such as AMQP (which stands for 'Advanced Message Queuing Protocol'). AMQP is an open standard application layer protocol for delivering messages. It can go P-2-P (One-2-One), publish/subscribe, and some more, in a manner of reliability and secured way.

At a bird eye's view are the main features of AMQP:

  • Platform independent wire level messaging protocol
  • Consumer driven messaging
  • Interoperable across multiple languages and platforms
  • It is the wire level protocol
  • Can achieve high performance
  • Supports long lived messaging
  • Supports classic message queues, round-robin, store and forward
  • Supports transactions (across message queues) and distributed transactions (XA, X/Open, MS DTC)
  • Has support for SASL and TLS
  • Allows to control the message flow with Meta-data

So the main difference with JMS (which is a Java EE specification and API) is that AMQP is just a binary wire protocol which was designed for interoperability between different vendors and platforms. As long it's AMQP complaint, changes at the broker level are not needed.

In other words, you can use a pure Java JMS client to communicate with the AMQP protocol if the messaging server supports it.

Let's see a practical example of it. One of the messaging server which supports AMQP is Apache Artemis MQ (and its predecessor ActiveMQ). You can build a sample JMS client/server application featuring the AMQP protocol, just by specifying it in the org.apache.qpid.jms.JmsConnectionFactory Constructor:

package org.apache.activemq.artemis.jms.example;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.qpid.jms.JmsConnectionFactory;

public class AMQPQueueExample {

   public static void main(String[] args) throws Exception {
      Connection connection = null;
      ConnectionFactory connectionFactory = new JmsConnectionFactory("amqp://localhost:5672");

      try {

         // Step 1. Create an amqp qpid 1.0 connection
         connection = connectionFactory.createConnection();

         // Step 2. Create a session
         Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

         // Step 3. Create a sender
         Queue queue = session.createQueue("jms.queue.exampleQueue");
         MessageProducer sender = session.createProducer(queue);

         // Step 4. send a few simple message
         sender.send(session.createTextMessage("Hello world "));

         connection.start();

         // Step 5. create a moving receiver, this means the message will be removed from the queue
         MessageConsumer consumer = session.createConsumer(queue);

         // Step 7. receive the simple message
         TextMessage m = (TextMessage) consumer.receive(5000);
         System.out.println("message = " + m.getText());

      }
      finally {
         if (connection != null) {
            // Step 9. close the connection
            connection.close();
         }
      }
   }
}

This will require in your ArtemisMQ configuration, an acceptor for the AMQP protocol.

<acceptors>
    <acceptor name="AMQP-acceptor">tcp://localhost:5672?protocols=AMQP;</acceptor>
</acceptors>

Let's take the case where a Ruby client wants to send a message to an AMQP broker, or viceversa. Or vice versa. Ruby client can't talk JMS, so we need a message broker that can bridge the two platforms, Java and Ruby.

As AMQP provides a standard messaging protocol that stands across all platforms it doesn't matter which AMQP client is used. In the following example, taken from ArtemisMQ examples (https://github.com/A-MQ/activemq-artemis/tree/master/examples) a Ruby client using the Proton library sends a message to the testQueue running on the ArtemisMQ server:

require 'qpid_proton'

address = "127.0.0.1:5672/testQueue"

messenger = Qpid::Proton::Messenger.new
messenger.start

msg = Qpid::Proton::Message.new
msg.address = address
msg.subject = "The time is #{Time.new}"
msg.body = "Hello world!"
msg.correlation_id = "554545"

begin
    messenger.put(msg)
rescue Qpid::Proton::ProtonError => error
    puts "ERROR: #{error.message}"
    exit
end

begin
    messenger.send
rescue Qpid::Proton::ProtonError => error
    puts "ERROR: #{error.message}"
    puts error.backtrace.join("\n")
    exit
end

puts "SENT: " + msg.body

messenger.stop

That's all. In the next tutorial of this series, we will see another messaging connectivity protocol called called MQTT which is gaining popularity.

Follow us on Twitter