Book Image

Instant Apache ActiveMQ Messaging Application Development How-to

By : Timothy A. Bish
Book Image

Instant Apache ActiveMQ Messaging Application Development How-to

By: Timothy A. Bish

Overview of this book

Apache ActiveMQ is a powerful and popular open source messaging and Integration Patterns server. ActiveMQ is a fully JMS 1.1 compliant Message Broker and supports many advanced features beyond the JMS specification.Instant ActiveMQ Application Development How-to shows you how to get started with the ActiveMQ Message Broker. You will learn how to develop message-based applications using ActiveMQ and the JMS specification. In this book you will learn all the basic skills you need to start writing Java Messaging applications with a firm grounding in the more advanced features of ActiveMQ, giving you the tools to continue to master application development using ActiveMQ. Starting by applying the messaging features of the JMS specification to write basic messaging applications, you will develop a basic JMS application using topics and queues to broadcast events as well as perform Request and Response operations over the JMS. Once you have mastered the simple tasks you will move onto using the advanced features in ActiveMQ to supercharge your messaging applications. You will get to grips with ActiveMQ's scheduler to delay messages. You will also learn how to leverage ActiveMQ's fault-tolerant capabilities to create robust client applications.
Table of Contents (7 chapters)

Using Virtual Destinations (Advanced)


In this recipe we are going to look at ActiveMQ's Virtual Destinations feature and learn how it can save us from the many limitations that come with using durable topic subscriptions.

Getting ready

For this recipe we will use the sample application virtual-destinations to demonstrate the use of Virtual Destinations.

How to do it...

To run the sample for this recipe, open a terminal, change the path to point to the directory where virtual-destinations is located, and run it by typing mvn compile exec:java.

In the terminal where you started the example, you will see output similar to the following snippet, indicating that the application is running:

Starting Virtual Destination example now...
Queue A Consumer 1 processed 500 Messages
Queue A Consumer 2 processed 500 Messages
Queue B Consumer processed 1000 Messages
Finished running the Virtual Destination example.

How it works...

Our example takes advantage of ActiveMQ's Virtual Destination feature to allow a JMS Producer to send messages to a topic and have those messages be received by a number of queue consumers. Let's take a look at the sent code first:

    private void sendMessages() throws Exception {
        Connection connection = 
          connectionFactory.createConnection();
        Session session = connection.createSession(false, 
          Session.AUTO_ACKNOWLEDGE);
        Destination destination = 
          session.createTopic("VirtualTopic.Foo");
        MessageProducer producer = 
          session.createProducer(destination);
        for (int i = 0; i < 1000; ++i) {
            producer.send(session.createMessage());
        }
        connection.close();
    }

As we can see, there's not much new here; we are just using standard JMS API code to send our messages. The important part is in the name of the topic destination VirtualTopic.Foo, which informs ActiveMQ Broker we want this topic to be one of those special Virtual Destinations.

Now let's take a look at the consumer code, and then we'll try and make sense of how this works:

        Queue queueA = 
          receiverSession.createQueue("Consumer.A.
          VirtualTopic.Foo");
        VirtualMessageListener listenerA1 = new 
          VirtualMessageListener(done);
        MessageConsumer consumerA1 = 
          receiverSession.createConsumer(queueA);
        consumerA1.setMessageListener(listenerA1);
        VirtualMessageListener listenerA2 = new 
          VirtualMessageListener(done);
        MessageConsumer consumerA2 = 
          receiverSession.createConsumer(queueA);
        consumerA2.setMessageListener(listenerA2);

        Queue queueB = 
          receiverSession.createQueue("Consumer.B.
            VirtualTopic.Foo");
        VirtualMessageListener listenerB = new 
          VirtualMessageListener(done);
        MessageConsumer consumerB = 
          receiverSession.createConsumer(queueB);
        consumerB.setMessageListener(listenerB);

As we can see, the consumer code is also not very mysterious; we create two consumers on the Consumer.A.VirtualTopic.Foo queue and one on the Consumer.B.VirtualTopic.Foo queue, and yet when we run the example, the two consumers on queue A split 500 of the topic message and the consumer on queue B gets its own copy of the 1,000 messages. So what's happening on the broker then to make this happen?

By default, whenever a topic is created with a name matching the pattern VirtualTopic.<TopicName>, we gain access to the feature known as Virtual Destinations. These Virtual Destinations allow us to send a message to a topic but create consumers that have all the benefits of queue consumers, namely, those of load balancing and message persistence. Our queue consumers just need to use their own naming convention to access the Virtual Destination functionality. Each queue that we want to create must be named using the pattern Consumer.<Name>.VirtualTopic.<TopicName>.

In the following figure we can see a visual representation of the message flow in our example:

As messages are sent to our example's topic, they are distributed to both the queues we created. Two of our consumers split the work of processing messages from queue A, while the other consumer gets all the messages from queue B. In our example we didn't attach a listener to the topic itself, but we could have done so and it would also have received all the messages we sent. It's easy to imagine using the topic as a way to monitor the messages that are being distributed to the queue consumers in this scenario; this pattern is often referred to as a wiretap.

If it isn't already apparent, Virtual Destinations are a very powerful feature for your messaging applications. Topics are great for broadcasting events but when we need to be able to consume messages that were sent while a client was offline, the only recourse is to use a durable topic subscription. Unfortunately, durable subscriptions have a number of limitations, the least of which is that only one JMS connection can be actively subscribed to a logical topic subscription. This means that we can't load balance messages and we can't have fast failover if a subscriber goes down. Virtual Destinations solve these problems since all of our consumers subscribe to a queue so their messages are persistent, and the work of processing the messages on the queue can be shared by more than one active subscription.

There's more...

The naming pattern for Virtual Destinations is not set in stone. By default, ActiveMQ is configured to use the pattern we used in our sample application, but you can easily change this. In the following XML snippet, we configured our broker to all topics on our broker into virtual topics. We use the wildcard syntax here, which matches every topic name a client sends messages to:

<broker>
  <destinationInterceptors>
    <virtualDestinationInterceptor>
      <virtualDestinations><virtualTopic name=">" prefix="VirtualTopicConsumers.*."/>
    </virtualDestinations></virtualDestinationInterceptor>
  </destinationInterceptors>
</broker>

More information on Virtual Destinations can be found on the ActiveMQ website, http://activemq.apache.org/virtual-destinations.html.