Per-queue message time-to-live (TTL)

One of the RabbitMQ protocol extension to the AMQP specification is that we can specify the messages lifetime on a queue. This is done setting the x-message-ttl argument to a non-negative integer value, representing the time to live in milliseconds.

For instance, if we want to use a queue named "ttl", with a time to live of half a second, we could write something like this (I use Java 7, as you can deduce from the diamond operator):
public class SendRecTTL {
    private final static String QUEUE_NAME = "ttl";
    private final static int TTL = 500;
    private Map<String, Object> args = new HashMap<>();

    public SendRecTTL() { args.put("x-message-ttl", TTL); }

    // ...

        channel.queueDeclare(QUEUE_NAME, false, false, false, args);
A message sent to this queue would expire after half a second, and would be considered "dead".

I have written a simple test application for the current RabbitMQ version (2.8.2) that sends and receives a message on such a queue. Adding a sleep between the two actions, we can see what happen if the delay is too big.

Better if your code is prepared to not receive anything, not hanging forever:
QueueingConsumer.Delivery delivery = consumer.nextDelivery(1000);
if(delivery == null)
{
    // ...
Full Java source code on github.

Go to the full post

Hello Maven

As a primer on Maven, there is nothing better than the Five Minutes Getting Started Page on its Apache site. Here you could find just a few extra notes I jotted down when I was reading it.

Once you have downloaded and unzipped the Maven package on your machine, you could run this basic command:
mvn --version
to ensure it is up and ready.

The most common issues you could have at this time are:
  • you can't see Maven from your current directory
  • Maven can't see Java
Ensure that the environment variables PATH and JAVA_HOME are properly set to avoid this problems. PATH should include also the Maven bin folder, and JAVA_HOME should refer to your preferred base JDK directory (notice that JDK is required, JRE is not enough).

Create a project

You can create a Java project from scratch running this Maven command (it is a single line, even if I split it to make it more readable):
mvn archetype:generate -DgroupId=package.name -DartifactId=app.name
-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
I have used "helloMaven" as artifact id, and "hello" as group id. The artifact id is the root directory where all the stuff related to this you application will be stored, and the group id is the name of a package that would be created, and where a simple hallo App would be created by Maven.

Proxy issue?

Maven tries to connect to its remote repository to get what it needs and couldn't be found locally (or for a newer version of it). If you get an error here, it is often due to a proxy issue.

If you do have such problem, you should have a look at the settings.xml file in the conf directory in you Maven installation.

In the "proxies" section you should create a "proxy" block containing all the information required to go through your proxy. In its minimal form it looks something like this:
<proxy>
  <protocol>http</protocol>
  <host>your.proxy</host>
  <port>80</port>
</proxy>
When Maven works fine, you get a directory structure based in the specified artifactId, that would contain in its first level a src folder and a pom.xml

The Project Object Model (if you wonder what pom stands for) XML that I got is:
<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>hello</groupId>
  <artifactId>helloMaven</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>helloMaven</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
Project build

To build our project we run:
mvn package
The result is published in the "target" folder. And, if we had no error, we can run our application in this way:
java -cp target/helloMaven-1.0-SNAPSHOT.jar hello.App
Notice that the JAR name is built putting together the artifact id and the version field, as stored in the POM.

Go to the full post

JMS Request-Reply

Implementing the Request-Reply messaging pattern with ActiveMQ is not complicated. The client component sends a request to the server on the dedicated queue, it attaches to it, as properties, the destination queue where it expects to find the reply, and a correlation id to uniquely identify the request-reply couple. The server uses these information to generate a consistent reply.

The complete Java source code is on github, here I comment just what I think are the most interesting part of the code.

This it the client, after establishing a connection to the broker:
Destination destination = session.createQueue(REQUEST_QUEUE_NAME); // 1
MessageProducer producer = session.createProducer(destination);
Destination dRep = session.createTemporaryQueue(); // 2
TextMessage message = session.createTextMessage(arg);
message.setJMSCorrelationID(UUID.randomUUID().toString()); // 3
message.setJMSReplyTo(dRep); // 4
producer.send(message);
// ...
MessageConsumer consumer = session.createConsumer(dRep); // 5
Message reply = consumer.receive(); // 6
// ...
1. The queue where the requests are sent.
2. A second queue, for the replies. We could have used a "normal" queue, but it is more common to create a cheaper temporary queue for this task.
3. We could keep track by hand of the unique message ids generated by the application, or we could delegate to Java the generation of an unique id, as I did here.
4. The queue to be used as destination for the reply is stored in the JMSReplyTo message property.
5. A consumer is created on the reply queue.
6. And the client patiently waits for an answer from the server.

The interesting part of the server is where it replies to the client:
if(message instanceof TextMessage) {
    TextMessage answer = session.createTextMessage(); // 1
    answer.setText("Reply to " + ((TextMessage) message).getText());
    answer.setJMSCorrelationID(message.getJMSCorrelationID()); // 2
    MessageProducer producer = session.createProducer(null); // 3
    producer.send(message.getJMSReplyTo(), answer);
}
1. The message to be sent as answer.
2. The correlation id is sent back to the client.
3. A producer with no associated queue is created, we are going to explicitly set the destination in its send() method using the JMSReplyTo message property.

Go to the full post

Embedding a broker by BrokerService

Instead of having the ActiveMQ broker as a standalone process, we could decide to have it embedded in one of our Java processes. The other processes would access it in the same way as before, but from other threads within, we could send and receive messages to the broker using the faster internal vm protocol.

A possible advantage of this solution is that the broker could be programmatically configured before it starts, and we could have a logic to determine when to stop it:
BrokerService broker = new BrokerService();
broker.setBrokerName("myBroker");
broker.setDataDirectory("data/"); // 1
// ...
broker.addConnector("tcp://localhost:61616"); // 2
broker.start(); // 3
// ...
broker.stop(); // 4
// ...
1. For a default setup, in the data directory it is created a folder for the broker (using its name, in this case we set it to "myBroker") containing a folder where the KahaDB files for message persistence are stored.
2. Let's our broker to be mimic of a standard broker.
3. When the broker setup is completed, we start it.
4. Shutting down the broker.

The complete Java source code for this example is on github.

Go to the full post

Selecting messages by custom properties

A JMS message comes with a number of standard properties, providing information on the associated message. For example, each message comes with a message id that could be fetched calling getJMSMessageID(). Besides, we can use custom properties to enrich a message in any way we think make sense for our specific case. An interesting aspect of custom properties is that we can use them to discriminate on which message a consumer should receive.

Think to an application where the producer generates messages for the best offers we have in our hardware store. The consumer could be interested in all or only in a subset of them. For this reason, it could be useful to put in the message payload just a generic description, and use custom properties to store structured information, as the product name and its price.

In this way the consumer could easily specify if it wants to get all the messages, or create a selector on the custom properties. The rules to create a selector are coming by simplification from the SQL conditional expressions.

The complete Java source code of this example is on github, it is written for ActiveMQ, so you should have this MOM installed and working on your development environment.

The producer delegates the most interesting part of its job to the send() method, that creates a message, fills it with specific data, and then send it to its associated queue:
TextMessage message = session.createTextMessage();
message.setText(txt);
message.setStringProperty(PROP_DES, des); // 1
message.setDoubleProperty(PROP_PRICE, price); // 2
producer.send(message);
1. Create a String property named as defined in the first parameter ("Description"), and containing the value stored in the second one ("Pins" and "Nails" in my test example).
2. The PROP_PRICE (actually, "Price") property is of type double.
In this test it is handy using a MessageListener, as discussed in a previous post, so that all the relevant messages are consumed by its onMessage() method:
logger.info("{}: {}", PROP_DES, message.getStringProperty(PROP_DES)); // 1
logger.info("{}: {}", PROP_PRICE, message.getDoubleProperty(PROP_PRICE)); // 2
logger.info("Message id: {}", message.getJMSMessageID()); // 3
logger.info("Message: {} ", ((TextMessage) message).getText());
1. The PROP_DES property is retrieved from the message, as the String that it is.
2. PROP_PRICE is a double, but we could have managed it as a String, calling getStringProperty(). ActiveMQ knows how to convert the internal double value to a String, so this cast works fine. If we tried to do the other way round, extracting a double from (1), we would have got a NumberFormatException.
3. There is not much use for this line here, but it is just to show a standard JMS property at work.

We need just one fundamental step, telling the JMS Session that the consumer has to get only some message:
switch (arg) {
    case "Nails":
    case "Pins":
        filter = PROP_DES + " = '" + arg + "'"; // 1
        consumer = session.createConsumer(destination, filter);
        break;
    case "Cheap":
        filter = PROP_PRICE + " < 15"; // 2
        consumer = session.createConsumer(destination, filter);
        break;
    default:
        consumer = session.createConsumer(destination); // 3
        break;
}
1. The string "Description = Nails" (or "Description = Pins") is passed in the next line to the session as a message selector for the consumer that has to be created. Only the messages true under that condition are delivered to this consumer.
2. Same as above, but the condition is now "Price < 15".
3. A "normal" consumer is created, with no associated selector.

Go to the full post

Asynchronous Hello ActiveMQ consumer

It is simple to modify the hello ActiveMQ example to change the consumer from syncronous to asyncronous.

If we want to asynchronously consume a message, we have to create a class that implements the JMS MessageListener interface, something like:
private class MyMessageListener implements MessageListener {
    @Override
    public void onMessage(Message message) {
        if(message instanceof TextMessage) {
            try {
                logger.info("Received {} ", ((TextMessage) message).getText());
            } catch (JMSException e) {
                logger.error("Can't extract text from received message", e);
            }
        }
        else
            logger.info("Unexpected non-text message received.");
    }
}
Then the consumer code changes only slightly:
MessageConsumer consumer = session.createConsumer(destination);
consumer.setMessageListener(new MyMessageListener()); // 1
try{ Thread.sleep(1000); } catch(InterruptedException e) {} // 2
1. Associate to the consumer an instance of our listener.
2. Usually we should implement a more sophisticated way of keeping alive the consumer till all the relevant messages are consumed. But for this simple example sleeping for a second should be enough.

The Java source code for the hello producer-consumer example, both in the synchronous and asynchronous flavor, is on github.

Go to the full post

Hello ActiveMQ

Writing an hello application with ZeroMQ is very easy, RabbitMQ requires a bigger effort, and ActiveMQ is not complicated, but probably the less immediate in the company. This escalation in complication is reflected also in the system's responsiveness (ZeroMQ is blazing fast and, compared to it, ActiveMQ could seem slow) but is well repaid by a higher level of offered services.

It is impossible to say in abstract which Message Queue structure is "better". It is more a matter of selecting the adequate one for specific environment requirements. A reason to decide for ActiveMQ is often that it implements the JMS specification.

In any case, say that we have already decided, and we have installed ActiveMQ on on our machine. Now it is time to write an hello application.

ActiveMQ is bundle with SLF4J as logger. I have talked of the trickiness in their relation in a previous post, so let's assume this is not an issue anymore. If you don't even know what SLF4J is, you could have a look at another post where I have written some notes on its installation.

Producer

The following code is all you need to establish a connection to the ActiveMQ broker and put a text message on a queue:
ConnectionFactory factory = new ActiveMQConnectionFactory(); // 1
Connection connection = null;
try {
    connection = factory.createConnection(); // 2
    connection.start();
    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 3
    Destination destination = session.createQueue(QUEUE_NAME); // 4
    MessageProducer producer = session.createProducer(destination); // 5
    TextMessage message = session.createTextMessage(arg); // 6
    producer.send(message); // 7
    logger.info("Sending: {}", message.getText()); // 8
} catch(JMSException ex) {
    ex.printStackTrace();
} finally { try { if(connection != null) connection.close(); } catch (JMSException e) {} } // 9
1. Since no address is specified, ActiveMQ assumes we want to connect to default broker, on localhost:61616.
2. A new connection to the browser is created and, in the next line, started.
3. On a connection we create a session, that could be transactional. Here we don't need it, so we pass "false" as first parameter. The second parameter specify if we want to acknowledge explicitly the message consume or not. Here we let ActiveMQ to take care of this.
4. Where the message is going to be sent. If the queue specified does not exist, ActiveMQ creates it for us.
5. The producer is an object created by the session for a specified destination that takes care of the message move from this client to the broker.
6. A text message is created from a String (in this case "arg" is the variable containing it).
7. The producer sends the message.
8. Remember that we are using SLF4J as a logger, if you wander about the strange syntax in the string, you may be interested in the post I have written on the efficiency reason for it.
9. Whatever happens in the try block, we want the connection to be closed.

Consumer

Consuming a message on ActiveMQ is not much different than producing it:
MessageConsumer consumer = session.createConsumer(destination); // 1
Message message = consumer.receive(1000); // 2
if(message == null)
    logger.info("No pending message on {} queue.", QUEUE_NAME);
else if(message instanceof TextMessage) // 3
    logger.info("Received: {}", ((TextMessage)message).getText());
else // 4
    logger.info("Unexpected non-text message consumed.");
1. First difference, we create a consumer on the session.
2. A message is consumed. The passed parameter is a timeout. If no message is waiting for us on the queue, and nothing arrives in a second, the consumer returns a null.
3. In the producer we created a text message, so we expect it to be of the same type here. If this is what we have, we work with it.
4. If we get here we are perplexed: who put a non-textual message on our queue?

You you want to play with the complete source Java code, you can find it on github.

Go to the full post