JMS: Создание приложения JMS. Queue.Topic.
Поиск по сайту:
О разработчеке сайта
Header image

Новые статьи и уроки JAVA

JMS: Создание приложения JMS. Queue.Topic.

Продолжаем разговор о JMS. В первой статье мы познакомились с технологией JMS, узнали для чего она применяется и каким образом происходит ее функционирование. В этой статье мы перейдем к практическому занятию и испытаем возможность асинхронной отправки и получения сообщений с использованием моделей "точка-точка" и "подписчик/издатель".

Для лучшего понимания статьи рекомендую прочесть ее первую часть.

Для реализации на практике функционала отправки и получения сообщений мы напишем клиентское приложение. Выглядеть оно будет примерно так:

Окно приложения JMS

 В верхней панели осуществляется выбор модели подключения и отправка сообщений. В нижней панели происходит подключение к выбранной модели и устанавливается слушатель, все принятые сообщения отображаются в текстовом окне.

Для тех, кто впервые читает мои статьи: для работы используется IDE NetBeans, в качестве сервера приложения GlassFish. В данном уроке он не понадобится, но нам нужна будет одна библиотека, которая поставляется вместе с ним.

Создание JMS приложения.

Создайте новый проект "приложение Java", назовите его "JMSApplication".

Создание приложения JMS

 Автоматически создастся класс JMSApplication с методом main().

 Все действия по работе с JMS будут происходить из него. Отдельно создадим класс для графического окна. Чтобы не тратить время на настройку дизайна и перечисление имен компонентов, предлагаю просто скопировать и встать содержимое класса, отвечающего за отображение окна- JMSWindow. В нем так же добавлены методы для получения значения текстовых компонентов.

package view;

import java.awt.Color;

/**
 *
 * @author Egorov A.
 */
public class JMSWindow extends javax.swing.JFrame {

    public JMSWindow() {
        initComponents();
    }

    @SuppressWarnings("unchecked")
    // //GEN-BEGIN:initComponents
    private void initComponents() {

        buttonGroup1 = new javax.swing.ButtonGroup();
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        jTFNameModel = new javax.swing.JTextField();
        jLabel3 = new javax.swing.JLabel();
        jRBPtP = new javax.swing.JRadioButton();
        jRBPubSub = new javax.swing.JRadioButton();
        jSeparator1 = new javax.swing.JSeparator();
        jLabel4 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTPTextMessage = new javax.swing.JTextPane();
        jBSendMessage = new javax.swing.JButton();
        jLConnected = new javax.swing.JLabel();
        jLInfSend = new javax.swing.JLabel();
        jPanel2 = new javax.swing.JPanel();
        jLabel5 = new javax.swing.JLabel();
        jBConnectedListener = new javax.swing.JButton();
        jLConnected1 = new javax.swing.JLabel();
        jLabel7 = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        jTPReceivedMess = new javax.swing.JTextPane();
        jSeparator3 = new javax.swing.JSeparator();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jPanel1.setBorder(javax.swing.BorderFactory.createEtchedBorder());

        jLabel1.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setText("Отправка сообщения JMS провайдеру");
        jLabel1.setToolTipText("");

        jLabel2.setText("Имя очереди/подписки");

        jTFNameModel.setText("SimpleQueue");
        jTFNameModel.setToolTipText("");
        jTFNameModel.setNextFocusableComponent(jRBPtP);

        jLabel3.setText("Вид модели");

        buttonGroup1.add(jRBPtP);
        jRBPtP.setSelected(true);
        jRBPtP.setText("точка-точка");
        jRBPtP.setToolTipText("");
        jRBPtP.setNextFocusableComponent(jRBPubSub);

        buttonGroup1.add(jRBPubSub);
        jRBPubSub.setText("подписчик/издатель");
        jRBPubSub.setToolTipText("");
        jRBPubSub.setNextFocusableComponent(jTPTextMessage);

        jLabel4.setText("Текст сообщения");
        jLabel4.setToolTipText("");

        jTPTextMessage.setNextFocusableComponent(jBSendMessage);
        jScrollPane1.setViewportView(jTPTextMessage);

        jBSendMessage.setText("Отправить сообщение");

        jLConnected.setText("Соединение не установлено");

        jLInfSend.setToolTipText("");

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.TRAILING,
javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
Short.MAX_VALUE)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jSeparator1)
                    .addComponent(jScrollPane1)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.
GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel2)
                            .addComponent(jLabel3)
                            .addComponent(jLabel4)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addComponent(jBSendMessage)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(jLInfSend))
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.
GroupLayout.Alignment.TRAILING, false)
                                    .addComponent(jTFNameModel, javax.swing.GroupLayout.
Alignment.LEADING)
                                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING,
jPanel1Layout.createSequentialGroup()
                                        .addComponent(jRBPtP)
                                        .addGap(14, 14, 14)
                                        .addComponent(jRBPubSub)))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(jLConnected)))
                        .addGap(0, 0, Short.MAX_VALUE)))
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.
GroupLayout.Alignment.BASELINE)
                    .addComponent(jTFNameModel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLConnected))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel3)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jRBPtP)
                    .addComponent(jRBPubSub))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel4)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 87, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jBSendMessage)
                    .addComponent(jLInfSend))
                .addGap(0, 13, Short.MAX_VALUE))
        );

        jPanel2.setBorder(javax.swing.BorderFactory.createEtchedBorder());

        jLabel5.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
        jLabel5.setText("Получение сообщений от JMS провайдера");

        jBConnectedListener.setText("Подключить слушатель");

        jLConnected1.setText("Соединение не установлено");

        jLabel7.setText("Полученные сообщения:");
        jLabel7.setToolTipText("");

        jTPReceivedMess.setEditable(false);
        jScrollPane2.setViewportView(jTPReceivedMess);

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel2Layout.createSequentialGroup()
                                .addGap(168, 168, 168)
                                .addComponent(jLabel5))
                            .addGroup(jPanel2Layout.createSequentialGroup()
                                .addContainerGap()
                                .addComponent(jBConnectedListener)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(jLConnected1))
                            .addGroup(jPanel2Layout.createSequentialGroup()
                                .addContainerGap()
                                .addComponent(jLabel7)))
                        .addGap(0, 144, Short.MAX_VALUE))
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(jSeparator3, javax.swing.GroupLayout.Alignment.TRAILING))))
                .addContainerGap())
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGap(4, 4, 4)
                .addComponent(jLabel5)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jBConnectedListener)
                    .addComponent(jLConnected1))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel7)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 245, Short.MAX_VALUE)
                .addContainerGap())
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );

        pack();
    }// //GEN-END:initComponents


    public void toggleSendConnected(){
        if (this.jLConnected.getText().equals("Соединение не установлено")){
            this.jLConnected.setText("Соединение установлено");
            this.jLConnected.setForeground(Color.green);
        }else{
            this.jLConnected.setText("Соединение не установлено");
            this.jLConnected.setForeground(Color.black);
        }
    }
   
    public void SendConnectedSucces(){
        this.jLConnected.setText("Соединение установлено");
        this.jLConnected.setForeground(Color.green);
    }
   
    public void toggleReceivedConnected(){
        if (this.jLConnected1.getText().equals("Соединение не установлено")){
            this.jLConnected1.setText("Соединение установлено");
            this.jLConnected1.setForeground(Color.green);
        }else{
            this.jLConnected1.setText("Соединение не установлено");
            this.jLConnected1.setForeground(Color.black);
        }
    }
    public void ReceivedConnectedSucces(){
        this.jLConnected1.setText("Соединение установлено");
        this.jLConnected1.setForeground(Color.green);
    }
    public void ReceivedConnectedClose(){
        this.jLConnected1.setText("Соединение не установлено");
        this.jLConnected1.setForeground(Color.black);
    }
    /**
     * Возвращает имя очереди или подписки, которой необходимо отправить сообщение.
     * @return
     */
    public String getQueueSendName(){
        return this.jTFNameModel.getText();
    }
    public void setTextReceiver(String text){
        this.jTPReceivedMess.setText(this.jTPReceivedMess.getText()+"\n"+text);
       
    }
    /**
     * Возвращает текст для отправки.
     * @return
     */
    public String getMessageSendText(){
        return this.jTPTextMessage.getText();
    }
    /**
     * Выбрана ли модель подключения точка-точка?
     * @return
     */
    public Boolean isPtP(){
        return jRBPtP.isSelected();
    }
    /**
     * Выбрана ли модель подключения подписчик\издатель?
     * @return
     */
    public Boolean isPupSub(){
        return jRBPubSub.isSelected();
    }
    public void SendSuccess(){
        this.jLInfSend.setText("Сообщение успешно отправлено");
        this.jLInfSend.setForeground(Color.green);
    }
    public void SendError(){
        this.jLInfSend.setText("Сообщение не удалось отправить");
        this.jLInfSend.setForeground(Color.red);
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.ButtonGroup buttonGroup1;
    public javax.swing.JButton jBConnectedListener;
    public javax.swing.JButton jBSendMessage;
    private javax.swing.JLabel jLConnected;
    private javax.swing.JLabel jLConnected1;
    private javax.swing.JLabel jLInfSend;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JRadioButton jRBPtP;
    private javax.swing.JRadioButton jRBPubSub;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator3;
    private javax.swing.JTextField jTFNameModel;
    private javax.swing.JTextPane jTPReceivedMess;
    private javax.swing.JTextPane jTPTextMessage;
    // End of variables declaration//GEN-END:variables
}

Также можете взять исходник с gitHub, ссылка на который приведена в конце статьи.
Сам класс должен лежать в пакете view.

Для продолжения работы нам необходимо импортировать несколько библиотек. В первую очередь это библиотека javax.jms.*; В наборе Java 6/7 SE этой библиотеки нет, она поставляется вместе с Java 6 EE. Поэтому Вам необходимо ее поискать в папке сервера. На своем сервере GlassFish необходимый мне jar файл лежал по адресу ~/glassfish/mq/lib/jms.jar.

Далее необходима библиотека для работы с апачевским ConnectionFactory. Для этого необходимо отправиться в папку установки ApacheMQ и там найти файл activemq-core-5.7.0.jar (последние цифры в названии файла могут различаться от версии к версии). Вероятнее всего Вы найдете его по адресу ~/apache-activemq/lib/activemq-core-5.7.0.jar.

При создании программы выяснилось что ApacheMQ использует в своей работе еще несколько классов, которые непосредственного отношения к JMS не имеют, но без них программа не скомпилируется. Чтобы избежать ошибок добавьте еще библиотеку ~/apache-activemq/lib/slf4j-api-1.6.6.jar и библиотеку ~/glassfish/glassfish/modules/javax.management.j2ee.jar.

Можем приступать к программированию.

Перейдем к классу JMSApplication. В самом начале класса объявим необходимые нам переменные:

    private static JMSWindow windowjms; // экземпляр нашего JFrame окна.
   
    private static ActiveMQConnectionFactory connectionFactory=null; //управляемый объект от ApacheMQ
//служащий для создания объекта Connection.
   
    private static Connection connection=null; //сам Connection.
   
    private static Session session; //контекст для посылки и приема сообщений.
   
    private static Destination destination; //буфер отправки и получения сообщений.
   
    private static String queue=null; //имя очереди или топика.

В функции main() перво-наперво необходимо создать экземпляр класса JMSWindow:

windowjms = new JMSWindow();
windowjms.setVisible(true);

Далее прикрутить обработчик события на нажатие кнопки отправки сообщения jBSendMessage и кнопки получения сообщений jBConnectedListener.

 windowjms.jBSendMessage.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        clickSendButton();
                    }
                });
windowjms.jBConnectedListener.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        clickReceivedButton();
                    }
                });

Так же важно отключать соединение в случае выхода пользователя из программы, для этого создадим обработчик закрытия окна программы:

windowjms.addWindowListener(new WindowAdapter() {
                    @Override
                    public void windowClosing(WindowEvent e) {
                        if (connection!=null){
                            try {
                                connection.close();
                            } catch (JMSException ex) {
                                Logger.getLogger(JMSApplication.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                    }
                   
                });

С методом main() покончено. Чтобы компилятор не выдавал ошибку, создайте функции заглушки:

public static void clickSendButton(){}
public static void clickReceivedButton(){}

В данный момент можно скомпилировать и запустить проект, перед вами откроется безжизненное окно программы. Разумеется, реагировать на ваши действия оно не будет.

Окно приложения JMS

Перед дальнейшей работой не забудьте запустить ApacheMQ сервер.

Отправка сообщений JMS

Создадим метод Connected() ,который будет отвечать за подключение к серверу JMS и создание контекста session.

public static Boolean Connected(){
        try {
            if (connection==null){
                connectionFactory=getConnectionFactory();
                connection=connectionFactory.createConnection();
//получаем экзмпляр класса подключения
                connection.start(); //стартуем
                session =connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//создаем объект сессию без транзакций
                //параметром AUTO_ACKNOWLEDGE мы указали что отчет о доставке будет
                //отправляться автоматически при получении сообщения.           
            }else{
                connection.start();
            }
            return true;
        } catch (JMSException ex) {
            Logger.getLogger(JMSApplication.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
    }

В методе мы проверяем не создан ли ранее экземпляр connection, если создан, то просто стартуем его. Если его еще нет, то сначала создаем экземпляр класса ApacheMQConnectionFactory вызовом функции getConnectionFactory() (она ниже). Далее получаем из него Connection и стартуем подключение.

Методом connection.createSession(false, Session.AUTO_ACKNOWLEDGE); получаем контект отправки и получения сообщений. Первый параметр указывает, что в контексте не будет использоваться транзакция, а второй Session.AUTO_ACKNOWLEDGE говорит о том, что отчет о доставке сообщения будет отправлен автоматически после получения этого самого сообщения.

Функция создания ApacheMQConnectionFactory:

private static ActiveMQConnectionFactory getConnectionFactory(){
        return new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,
                                             ActiveMQConnection.DEFAULT_PASSWORD,
                                             "failover://tcp://localhost:61616");
}

Как видно, мы просто вызываем конструктор класса и передаем дефолтные имя пользователя и пароль. URL_BROKER тоже дефолтный, но я специально передал его не константой, а строкой, чтобы Вы могли видеть как он выглядит.

Теперь необходимо создать две функции получения экземпляра Destination в зависимости от выбранной модели связи: "точка-точка" или "подписчик/издатель".

/**
     * Подключаемся к модели точка-точка.
     * @return
     */
    private static Destination getDestinationQueue(){
        try {
            return session.createQueue(queue);
        } catch (JMSException ex) {
            Logger.getLogger(JMSApplication.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }
/**
     * Подключаемся к модели подписчик/издатель.
     * @return
     */
    private static Destination getDestinationTopic(){
        try {
            return session.createTopic(queue);
        } catch (JMSException ex) {
            Logger.getLogger(JMSApplication.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

Как видно из листинга различие лишь в концовке названия метода session.createXXX(queue); переменная queue содержит название очереди или топика которому будут отсылаться сообщения.

1Важно заметить, что даже если очереди или топика с таким название не существует на сервере JMS, то он будет создан автоматически.

 Теперь мы можем заняться методом clickSendButton():

/**
     * Нажатие кнопки отправки сообщения.
     */
    public static void clickSendButton(){
        //получаем имя очереди к которой необходимо подключитсья
        queue=windowjms.getQueueSendName().equals("")?"SimpleQueue":windowjms.getQueueSendName();
        if (Connected() && !windowjms.getMessageSendText().equals("")){
            windowjms.SendConnectedSucces();
            if (windowjms.isPtP()){
                destination=getDestinationQueue();
            }else{
                destination=getDestinationTopic();
            }
            if (destination!=null){
                try {
                    MessageProducer producer = session.createProducer(destination);
                    producer.setDeliveryMode(DeliveryMode.PERSISTENT);//парметром PERSISTENT указываем что сообщение
                    //будет хранится до тех пор пока не будет доставлено адресату.
                    //Создаем текстовое сообщение.
                    TextMessage message =session.createTextMessage(windowjms.getMessageSendText());
                    producer.send(message);
                    windowjms.SendSuccess();
                } catch (JMSException ex) {
                    windowjms.SendError();
                    Logger.getLogger(JMSApplication.class.getName()).log(Level.SEVERE, null, ex);
                }
            }else{ windowjms.SendError();}
        }else{windowjms.SendError();}
    }

В методе мы  сначала получаем имя очереди/топика, которому отправится сообщение. Далее производим подключение и, если оно прошло успешно, выясняем, к какой модели необходимо осуществить подключение, в зависимости от этого получаем тот или иной destination.

 Далее создаем MessageProducer для отправки сообщений:

MessageProducer producer = session.createProducer(destination);

Устанавливаем приоритет хранения сообщения:

producer.setDeliveryMode(DeliveryMode.PERSISTENT);

Создаем текстовое сообщение:

TextMessage message =session.createTextMessage(windowjms.getMessageSendText());

И отправляем его, используя созданный MessageProducer:

producer.send(message);

 Программа приобрела половину своего функционала. Вы можете уже отправлять сообщения как в очередь, так и в топик. Зайдя через веб-консоль ApacheMQ сервера, можно убедиться что они пришли.

Получение сообщений JMS

Для реализации функционала получения сообщений у нас почти все готово. Отличия будут лишь в том, что использоваться будет не объект MessageProducer, а MessageConsumer.

/**
     * Нажатие кнопки подключения слушателя.
     */
    public static void clickReceivedButton(){
        queue=windowjms.getQueueSendName().equals("")?"SimpleQueue":windowjms.getQueueSendName();
        if (Connected()){
           if (windowjms.isPtP()){
                destination=getDestinationQueue();
            }else{
                destination=getDestinationTopic();
            }
           if (destination!=null){
                try {
                    MessageConsumer consumer=session.createConsumer(destination);
                    consumer.setMessageListener(new MessageListener() {

                        @Override
                        public void onMessage(Message msg) {
                            TextMessage textmessage=(TextMessage)msg;
                            try {
                                windowjms.setTextReceiver(textmessage.getText());
                            } catch (JMSException ex) {
                                Logger.getLogger(JMSApplication.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                    });
                    windowjms.ReceivedConnectedSucces();
                } catch (JMSException ex) {
                    Logger.getLogger(JMSApplication.class.getName()).log(Level.SEVERE, null, ex);
                    windowjms.ReceivedConnectedClose();
                }
           }else{windowjms.ReceivedConnectedClose();}
        }else{windowjms.ReceivedConnectedClose();}
    }

Минуя знакомый Вам код, мы создаем MessageConsumer:

MessageConsumer consumer=session.createConsumer(destination);

Далее у нас множество вариантов получения сообщений. Самый правильный, как я считаю, это асинхронное прослушивание канала на наличие сообщений. Для этого мы создаем слушатель MessageListener и переопределяем событие onMessage(Message msg);.

В методе onMessage мы приводим сообщение к типу TextMessage и выводим его в текстовое поле.

Как Вы могли заметить, все достаточно просто.

Вы можете далее создавать свои приложения, работающие с JMS и использовать более сложный механизм отправки и получения данных: использовать транзакции, пароли, указывать адресата, время жизни сообщений и прочее.

1Исходники проекта можно взять на GitHub.

Очень просто подключить JMS для своего веб-приложения JavaEE и с его помощью создавать всевозможные сервисы требующие асинхронной обработки данных и днунавправленной связи (чаты, игры, магазины). Если к этому еще подключить технологию websocket то можно создавать шедевры. Каким образом на GlassFish сервере создать проект с использованием websocket - раскажу в следующей статье.

17.01.2013

Комментарии