Статьи

CometD и Camel на предприятии — рабочий пример

Полный код доступен на GitHub


Весь код Java для проекта доступен на Github — требуется Maven для запуска.
Смотрите README для более подробной информации —
ссылка здесь .

Ключевые технические игроки

Демонстрация демонстрирует гармоничное взаимодействие этих различных частей набора:

  • CometD Bayeux Ajax Push — технология push-взаимодействия между сервером Camel и веб-браузером [ http://cometd.org/ ]
  • Apache Camel — инфраструктура корпоративной интеграции — предоставляет канал производителя корпоративной маршрутизации и CometD [ http://camel.apache.org/ ]
  • Apache ActiveMQ — брокер обмена сообщениями JMS [ http://activemq.apache.org/ ]
  • Плагин Apache Camel CometD — плагин CometD для Camel [ http://camel.apache.org/cometd.html ]
  • И обычные подозреваемые — Java, Spring, Maven, Git

Какой сценарий?

  • Представьте себе сложную корпоративную инфраструктуру, в которой используется множество различных систем, серверов и технологий, и между ними передаются данные.
  • Обычно в игре будет какая-то система обмена сообщениями — маршрутизация и трансформация различных потоков сообщений. В нашем примере мы используем ApacheMQ в качестве сервера обмена сообщениями.
  • Конечные точки некоторых из этих потоков могут отправлять данные нескольким клиентам. Один из способов сделать это — направить сообщения в тему, и многие клиенты подписались на эту тему — это просто для клиентов Java, но не так просто, если клиенты являются браузерами.
  • Как правило, браузерные клиенты должны использовать метод опроса вручную, чтобы проверить наличие новых данных.
  • Использование CometD — браузер может использовать некоторый javascript для подписки на канал CometD, сохраняя открытое долго работающее соединение — и конечная точка этого канала может передавать данные напрямую всем своим подписчикам. Удобно, Apache Camel поставляется с плагином CometD, который может обрабатывать все это на стороне сервера для нас.

CometD и Camel Demo


Демонстрация показывает сообщения HTML, отправляемые в очередь JMS ActiveMQ, откуда они отбираются Camel и затем направляются в конечную точку канала CometD.

HTML-страница потребляет сообщения из канала CometD — и по мере их поступления добавляет их в список на веб-странице.
Пример HTML-страницы показан ниже (я добавил JQuery, чтобы сначала перетаскивать изображения в красный цвет, а затем постепенно затушевывать их — только для того, чтобы это было очевидно по мере поступления новых сообщений).

Сообщения являются простыми и генерируются автоматически из клиентского приложения Java, которое отправляет их в ActiveMQ с помощью Spring JMSTemplate.


Этот поток показан на диаграмме ниже. Все три составные части могут быть запущены из одного проекта (но они должны быть запущены в указанной последовательности — сначала ActiveMQ / Camel-сервер, затем веб-браузер, затем Java-клиент)

Запуск демо

  • Посмотрите файл README в Github для получения полной информации о том, как запустить демонстрацию (только помните, что они должны быть запущены в последовательности выше — сервер ActiveMQ \ Camel должен быть запущен первым, чтобы браузер использовал канал cometd и клиент отправил JMS сообщение)

Верблюжий путь

  • Свойства устанавливаются в application.properties
broker.url=tcp://localhost:61616
broker.queue=corsoft.BroadcastMessageQueue

cometd.channel=cometd://0.0.0.0:9099/broadcastMessageChannel
  • The Camel Route — прослушивает очередь и выводит на канал CometD
  <!-- 
		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>

Потребитель Javascript

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);
}

Диспетчер сообщений клиента Java

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!");

    }

}

Будущие расширения

  • Очевидно, что это довольно простая демонстрация — в реальной ситуации вы можете не захотеть отправлять необработанный HTML по каналу. Лучшим решением будет JSON, позволяющий клиенту извлекать и форматировать, как он хочет.
  • (И если вы используете Camel — тогда вы, вероятно, делаете кучу других преобразований и обработки в промежутке между получением и публикацией данных.)