Enterprise Integration Zone is brought to you in partnership with:

Adrian is a freelance consultant Java Enterprise developer with nearly 20 years experience of software development across a wide range of companies, sectors and projects. In recent years he has formed his own company and dabbled with mobile app development alongside his consultancy work. Adrian is a DZone MVB and is not an employee of DZone and has posted 9 posts at DZone. You can read more from them at their website. View Full User Profile

CometD and Camel in the Enterprise - A Working Example

04.19.2013
| 4332 views |
  • submit to reddit


Full code is available on GitHub

All the Java code for the project is available in Github - requires Maven to run. See the README for more details - link here.

The Key Tech Players

The demo shows these various pieces of kit working (hopefully) harmoniously together:

What's the Scenario?

  • Imagine a complex enterprise infrastructure, running a bunch of different systems, servers and technologies, with data flowing between them all.
  • Commonly there will be some sort of Messaging system in play - handling routing and transformation of the various message flows. In our example we have ApacheMQ as the Messaging Server.
  • The endpoints of some of these flows may be to send data to multiple clients. One way to do this is to route messages to a Topic, and have many clients subscribed to that topic - this is easy of the clients are Java, but not so easy if the clients are Browsers.
  • Typically browser clients will have to use a hand rolled polling approach to check for new data being available.
  • Using CometD - the Browser can use some javascript to subscribe to a CometD channel, keeping a long running connection open - and the endpoint of that channel can push data down directly to all its subscribers. Handily, Apache Camel comes with a CometD plugin that can handle all this on the server side for us.

The CometD and Camel Demo

The demo shows HTML messages being sent to an ActiveMQ JMS Queue, from where they are picked up by Camel and then routed to a CometD channel endpoint. A HTML page consumes messages from the CometD channel - and as they are received, adds them to a list on the web page. An example of the HTML page is shown below (I've added some JQuery to initially flash the images in red, and then fade them out to black over time - just to make it obvious as new messages arrive). The messages are just simple, generated automatically from a Java client app, which pushes them to ActiveMQ using a Spring JMSTemplate.



This flow is shown in the diagram below. All three constituent parts can be run from the same project (but they must be started in the sequence shown - ActiveMQ/Camel server first, then web browser, then Java client)


Running the Demo

  • See the README file in Github for full details on how to run the demo (just remember they need to be started in the sequence above - ActiveMQ\Camel server needs to be running first for the browser to consume the cometd channel and the client to send JMS message)

The Camel Route

  • Properties are set in application.properties
broker.url=tcp://localhost:61616
broker.queue=corsoft.BroadcastMessageQueue

cometd.channel=cometd://0.0.0.0:9099/broadcastMessageChannel
  • The Camel Route - listens on a Queue and outputs to a CometD channel
  <!-- 
		Server Camel Context (running inside ActiveMQ) 
	-->
	<camelContext xmlns="http://camel.apache.org/schema/spring">
	
		<!-- Load properties to Camel Context -->
		<propertyPlaceholder id="properties" location="application.properties" />
	
		<!-- Camel Broadcast Message Route -->
		<route id="processIncomingFilesRoute" trace="true" xmlns="http://camel.apache.org/schema/spring">

			<!-- Listen on this Queue for incoming Messages -->
			<from uri="activemq://queue:{{broker.queue}}" />

			<!-- Log to console -->
			<log message="Incoming Message - distribute via Cometd" loggingLevel="INFO" />

			<!-- 
				Creates a Cometd channel endpoint
				Broadcast to all Cometd registered subscribers 
			-->
			<to uri="{{cometd.channel}}" />

		</route>
		
	</camelContext>

The Javascript Consumer


google.load("jquery", "1");

/**
 * Callback function - Cometd consumer.
 */
google.setOnLoadCallback(function() {
    $.getScript("http://jquerycomet.googlecode.com/svn/trunk/jquery.comet.js", function(){
    console.log("done loading js");
    $.comet.init("http://localhost:9099/cometd");
    $.comet.subscribe("/broadcastMessageChannel", broadcastListener);
  });
  
});

/**
 * Listener function called on receipt of broadcast message.
 */
function broadcastListener(msg) {
  console.log("received broadcast: " + msg + ", " + msg.data); 
  $('<li>').html(msg.data).prependTo('#contentList').animate({color: "#000000"}, 6000);
  $('html, body').animate({ scrollTop: 0 }, 0);
}

The Java Client Message Dispatcher


package com.cor.demo;

import java.io.Serializable;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Session;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;

/**
 * Delegate for sending messages to ActiveMQ Broker via the Spring JMSTemplate.
 */
@Component
public class MessageDispatcher {

    /** Logger. */
    private static Logger LOG = LoggerFactory.getLogger(MessageDispatcher.class);

    /** JMS Template. */
    @Autowired
    protected JmsTemplate jmsTemplate;

    /**
     * Send the objectMessage to the Broker and Queue defined in application.properties.
     * @param objectMessage Object Message
     */
    public void sendMessageObject(final Serializable objectMessage) {

        LOG.info("Sending message " + objectMessage);

        jmsTemplate.send(new MessageCreator() {

            public Message createMessage(Session session) throws JMSException {
                ObjectMessage message = session.createObjectMessage(objectMessage);
                return message;
            }
        });

        LOG.info("Message Sent!");

    }

}

Future Extensions


  • Obviously this is a pretty simple demo - in a real world situation you may not want to be sending raw HTML down the channel. A better solution would be JSON, allowing the client to extract and format how it wanted to.
  • (And if you're using Camel - then you're probably doing a bunch of other conversions and processing in the space between receiving and publishing the data.)


Published at DZone with permission of Adrian Milne, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)