Статьи

Новая функция Defne Platform: платформа асинхронного обмена сообщениями

Defne — это легкая платформа для разработки веб-приложений Java EE. Он предоставляет удобные библиотеки для простой и мощной разработки веб-приложений Java EE на основе технологий Java EE. Каждая библиотека компонентов инфраструктуры Defne позволяет разработчикам использовать их через Dependency Injection, CDI. В будущем выпуске 1.0.3 мы предоставим встроенный контейнер IoC, который будет основан на Apache Tomcat и Apache OpenWebBeans.

В этой статье мы собираемся углубиться в новый компонент Defne, « Defne Asynchronous Messaging », то есть « Defne Channels ».

Вы можете скачать и развернуть этот пример на сервере приложений SIwpas ( http://code.google.com/p/siwpas/ ), который предоставляет все необходимые библиотеки для этого примера. 

Defne Asynchronous Messaging Framework

Если вы исследуете веб на асинхронном обмене сообщениями Java, вы, вероятно, поразите миллионы документов о Java Messaging Service. Это стандарт для разработки приложений асинхронного обмена сообщениями в Java. Чтобы использовать JMS, вы должны быть экспертом по некоторым их внутренним API, таким как «Сеансы», «Соединения», «Имена JNDI», «Темы», «Очереди» и т. Д. Существуют также некоторые асинхронные среды обмена сообщениями, такие как асинхронный Веб-сервисы , модель асинхронной связи CORBA , Служба распространения данных и т. Д. Каждый из них использует свой собственный API и модели программирования. Поэтому разработчики должны изучить эти технологии и их API, прежде чем успешно использовать их в любом корпоративном проекте.

Наша цель с Defne — предоставить простой и общий уровень API обмена сообщениями, чтобы устранить сложность и конфигурацию этих технологий. Давайте посмотрим на высокоуровневую архитектуру асинхронной структуры Defne , т.е. каналы Defne

Вот некоторая терминология о библиотеке каналов Defne

  • Канал : Канал — это абстрактный термин, который отправляет / получает абстрактные сообщения откуда угодно. Реализации каналов знают, как отправлять / получать сообщения от определенных технологий обмена сообщениями.
  • Менеджеры каналов. Менеджеры каналов управляют жизненным циклом зарегистрированных каналов.
  • Channel Manager Factory : Фабрика для получения Channel Manager
  • Прослушиватели каналов : модель событий / прослушивателей для событий, связанных с каналами (инициализация, запуск, остановка каналов)
  • Слушатели менеджера каналов : модель событий / слушателей для событий, связанных с менеджером каналов, (инициализация, запуск, остановка менеджеров каналов)
  • Defne Runtime Platform : предоставляет компоненты CDI, которые используются разработчиками для внедрения объектов, связанных с каналом
  • Канальные клиенты: пользователи Defne Channel Framework

Модули библиотеки каналов В библиотеке каналов Defne
есть два модуля maven:

  • Channel Java API Module: предоставляет общие API для общих операций обмена сообщениями. Одним из важных интерфейсов являетсяинтерфейс IChannel . Части этого интерфейса представлены ниже. Вы также можете посмотреть другие интерфейсы из svn, http://defne.googlecode.com/svn/trunk/defne-channel-api/ .
    Другими важными интерфейсами являются IChannelManager, IChannelManagerFactory.
    /**
* Initialize the channel. Generally initialization
* will be done by channel managers.
* @param properties properties for proper initialization
* @throws ChannelException for any exception
*/
public void init(Properties properties) throws ChannelException;

/**
* Starts the channel.
* @throws ChannelException for exception occurs
*/
public void start() throws ChannelException;

/**
* Stops the channel.
* <p>
* Any exception is logged and swallowed.
* </p>
*/
public void stop();

/**
* Gets channel state.
* @return the state of the channel.
*/
public ChannelState getState();

  • Модуль реализации API канала: Реализация API канала с помощью специальных технологий. В настоящее время платформа Defne обеспечивает реализацию Channel API для JMS . Вы можете посмотреть на реализацию из SVN, http://defne.googlecode.com/svn/trunk/defne-channel-jms/

Пример JSF использует библиотеку каналов Defne
В этой статье мы рассмотрим приложение JSF, использующее компоненты каналов Defne. В этом примере JMS используется в качестве реализации API канала. Есть две страницы этого приложения

  • Страница отправителя и реализация: создание канала и отправка сообщения на канал (на основе темы JMS) 
  • Страница получателя и реализация: Подписаться на канал, чтобы получать сообщения от этого канала

Вы можете посмотреть полный исходный код проекта из SVN, http://defne.googlecode.com/svn/trunk/defne-samples/channel-sample/

Вот класс Sender.java,

@SessionScoped
@Named
public class Sender implements Serializable
{
private static final long serialVersionUID = 1L;

/**Message that will be sent*/
private String message;

/**Channel manager factory*/
private transient @Inject @JmsFactory IChannelManagerFactory channelManagerFactory;

/**Channel manager*/
private IChannelManager channelManager;

/**Our channel that we will send message*/
private IChannel channel;

/**
* Initialize our channel manager and start.
*/
@PostConstruct
public void init()
{
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
properties.put(Context.PROVIDER_URL, "tcp://localhost:61616?connectionTimeout=0");

properties.put(IJmsChannelManager.CONNECTION_FACTORY_JNDI_NAME, "ConnectionFactory");

try
{
//Our JMS Channel Manager
this.channelManager = channelManagerFactory.getChannelManager(properties);

JmsChannelConfig jmsChannelConfig = new JmsChannelConfig(JmsChannelType.TOPIC);
this.channel = this.channelManager.createChannel(jmsChannelConfig);

//Setting channel JNDI Name, using ActiveMQ dynamic topic
properties.put(IJmsChannel.JMS_CHANNEL_DESTINATION_JNDI_NAME, "dynamicTopics/A");

//Register our channel with manager, pass null that
//Manager creates unique id for our channel
this.channelManager.registerChannel(null, channel);

//Initialize and start our channels in manager
this.channelManager.init(properties);
this.channelManager.start();
}
catch (ChannelException e)
{
throw new RuntimeException(e);
}
}

/**
* Stop our channel manager.
*/
@PreDestroy
public void preDestroy()
{
this.channelManager.stop();
}

/**
* Send a message.
* @return null for same page
*/
public String sendMessage()
{
try
{
this.channel.sendMessage(message);
}
catch (ChannelException e)
{
e.printStackTrace();
}

return null;
}

public String getMessage()
{
return message;
}

public void setMessage(String message)
{
this.message = message;
}

}

 важные части этого класса,

  • Он внедряет « IChannelManagerFactory »: он использует квалификатор « @JmsFactory ». Поэтому Defne находит фабричный класс, способный создавать JMS Channel Manager. 
  • Настройка канала, менеджера каналов и запуска менеджера каналов : В методе @PostConstruct мы создаем и регистрируем наш канал, инициализируем и запускаем менеджер каналов. Каждый канал имеет уникальный идентификатор. Если идентификатор не указан во время создания, менеджер канала создаст уникальный идентификатор для канала. Здесь мы используем «this.channelManager. CreateChannel (jmsChannelConfig)» для создания канала на основе темы JMS. Вы можете дать больше свойств для настройки вашего канала jms, посмотрите на интерфейс » IJmsChannel » для других свойств. Например, он использует «IJmsChannel. JMS_CHANNEL_DESTINATION_JNDI_NAME» , « dynamicTopics / A » подразумевает, что имя JNDI этого канала — «dynamicTopics / A».
  • Отправка сообщения: сообщение отправляется простым вызовом «this.channel. SendMessage (message)»
  • Остановка менеджера каналов: «this.channelManager. Stop ()» останавливает все зарегистрированные каналы и выполняет операции очистки.

Вот графический интерфейс для отправителя,

Когда пользователь нажимает кнопку «Отправить», он отправляет входное сообщение на канал.

Вот класс Receiver.java,

@SessionScoped
@Named
public class Receiver implements Serializable, IChannelMsgListener
{
private static final long serialVersionUID = 1L;

/**Will be uSed for getting JMS Channel Manager*/
private transient @Inject @JmsFactory IChannelManagerFactory channelManagerFactory;

/**Our channel manager*/
private IChannelManager channelManager;

/**Incoming message*/
private String message;

/**Notification for user*/
private String result = "";

/**
* Initialize our manager and start.
*/
protected void init()
{
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
properties.put(Context.PROVIDER_URL, "tcp://localhost:61616?connectionTimeout=0");

properties.put(IJmsChannelManager.CONNECTION_FACTORY_JNDI_NAME, "ConnectionFactory");

try
{
//Our JMS Channel Manager
this.channelManager = channelManagerFactory.getChannelManager(properties);

JmsChannelConfig jmsChannelConfig = new JmsChannelConfig(JmsChannelType.TOPIC);
IChannel topicChannel = this.channelManager.createChannel(jmsChannelConfig, this);

//Setting channel JNDI Name, using ActiveMQ dynamic topic
properties.put(IJmsChannel.JMS_CHANNEL_DESTINATION_JNDI_NAME, "dynamicTopics/A");

//Register our channel with manager, pass null that
//Manager creates unique id for our channel
this.channelManager.registerChannel("MyChannel", topicChannel);

//Initialize and start our channels in manager
this.channelManager.init(properties);
}
catch (ChannelException e)
{
throw new RuntimeException(e);
}
}

/**
* Start to receive.
* @return null
*/
public String start()
{
try
{
init();
this.channelManager.start();
this.result = "Channel has opened";
}
catch (ChannelException e)
{
e.printStackTrace();
}

return null;
}

/**
* Destroy and stops our manager.
*/
public String stop()
{
this.channelManager.stop();
this.result = "Channel has closed";
return null;
}

public String getMessage()
{
return this.message;
}

/**
* New message arrives.
*/
@Override
public void onChannelMessage(ChannelMsgEvent message)
{
ChannelJmsMsgEvent jmsEvent = (ChannelJmsMsgEvent)message;

try
{
this.message = jmsEvent.readTextMessagePayload();
}
catch (ChannelException e)
{
e.printStackTrace();
}
}

public String getResult()
{
return result;
}

public void setResult(String result)
{
this.result = result;
}

}

Receiver configures its channel like Sender. But it also subscribes to channel with implementing «IChannelMsgListener«. Whenever a new message comes to «channel», it receives the message. » public void onChannelMessage(ChannelMsgEvent message)» is called by Defne framrwork at runtime when a new message is ready.

Here is the GUI for receiver.

  • When user clicks «Open Channel» button, channel is started and subscription will be done
  • When user clicks «Close Channel» button, channel manager is stopped
  • When user clicks, «Receive Last Message», user gets latest message that has been sent by the sender.

All of those buttons use JSF 2 Ajax communication ? 

Future of the Framework

We will add some more features to our JMS implementation, like adding interceptors, executing Defne services etc. We will also look for other messaging techonlogy implementations. We will also provide COMET implementation based on Channel Library using Servlet 3.0 Asynch features using Bayeux Protocol. Stay tune!

Standalone Usage

You can also use Defne Channel Component library in your standalone projects. If you want to use Defne Channel library in an environments where dependency injection is not available, you will instantiate the objects yourself. For example, here is the test for Defne Channel code,

        Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
properties.put(Context.PROVIDER_URL, "vm://localhost?broker.persistent=false");

JmsChannelManagerFactory factory = new JmsChannelManagerFactory();
IJmsChannelManager channelManager = factory.getChannelManager(properties);

//Create channel
IChannel channel = channelManager.createChannel(new JmsChannelConfig(JmsChannelType.TOPIC), this, this);

//Register our channel
channelManager.registerChannel(channelManager.producerChannelId(), channel);

//Adding Topic Jndi Name
properties.put(IJmsChannel.JMS_CHANNEL_DESTINATION_JNDI_NAME, "dynamicTopics/A");

//add listener to channel manager
channelManager.addChannelManagerListener(this);

//Initialize our manager
channelManager.init(properties);

//Lets start'er channel manager
channelManager.start();

JmsUtil.sendTextMessage("dynamicTopics/A", new InitialContext(properties), "Hello World");

Thread.sleep(5000);

//Stop manager
channelManager.stop();

 

Enjoy!

Defne URLs

Web Site : http://code.google.com/p/defne/

SVN Site : http://code.google.com/p/defne/source/browse/

Maven Snapshot : https://oss.sonatype.org/content/repositories/snapshots/org/defne/

Maven : http://repo1.maven.org/maven2/org/defne/

Defne Discussion : http://groups.google.com/group/defnedev

 

Gurkan Erdogdu

ASF Member,http://apache.org

PMC Chair, Apache OpenWebBeans

CTO, MechSoft Mechanical and Software Solutions, http://www.mechsoft.com.tr