(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Построение "толстого" Java -клиента, который полностью интегрирован с Google Talk

Источник: oracle
Лукас Джеллема

Как стало совершенно ясно на выставке Oracle OpenWorld 2007, концепции и тенденции интеграции Web 2.0 с приложениями уровня предприятия являются сегодня главным направлением в разработке приложений. Приложения Oracle Fusion Applications предлагают хороший пример того, как объединение очень привлекательных, визуально богатых пользовательских интерфейсов с популярными возможностями Интернета, например, социальные закладки ( social bookmarking ) и мгновенный обмен сообщениями ( IM - instant messaging), приводит к эффективным и продуктивным приложениям. Объединенное в пользовательском интерфейсе приложения взаимодействие является важным фактором при совместной работе, которую продвигает этот новый стиль приложений. Электронная почта ( e - mail ), голосовая связь по IP ( VoIP ) и служба коротких сообщений ( SMS ) - все это входит в число потенциально рассматриваемых каналов коммуникации, но IM (чат) вполне может быть самым мощным среди них.

Рассмотриваемая в статье обучающая программа предначена для демонстрации разработки полнофункционального Web -приложения, которое полностью интегрировано с Google Talk (http://www.google.com/talk/) , одним из главных сервисов IM . Проект с открытым исходным текстом Smack предлагает библиотеку API Java , чтобы подключиться к протоколу Extensible Messaging and Presence Protocol ( XMPP ) - коммуникационным протоколам IM . Используя Smack , можно очень быстро создать Java -приложение, которое разговаривает с Google Talk (и слушает его), или с любым другим сервисом IM , который соответствует техническим требованиям XMPP . Затем можно использовать Oracle ADF Faces Rich Client (который на момент написания этой статьи являлся частью Oracle JDeveloper 11 g Technical Preview ), чтобы создать пользовательский интерфейс и, в частности, Active Data Service (Обслуживание активных данных), который делает возможным мгновенные обновления Web -клиента ("проталкивание" с сервера на браузер) при получении сообщения. И, наконец, возможность перетаскивания "толстого" клиента Oracle ADF Faces используется для быстрого сбрасывания записей данных в сообщения чата.

Полностью файлы проекта и программы-примеры для каждой части обучающей программы доступны по адресу http://www.oracle.com/technology/pub/files/jellema-googtalk-project.zip .

Подготовка

  • Загрузите из OTN и установите Oracle JDeveloper 11 g TP . Перейдите к www. oracle.com/technology/products/jdev/11/index.html , загрузите архивный ( ZIP ) файл объемом 500 Мбайт, разархивируйте его на вашей машине, и вы готовы к работе.
  • Получите учетную запись Google Talk . Перейдите к https ://www.google.com/accounts/NewAccount?service=talk и создайте свою бесплатную учетную запись (account - аккаунт) Google Talk . Примечание: вы можете также добавить Google Talk как дополнительный компонент к существующему аккаунту Google .
  • Загрузите клиента Google Talk . Хотя, строго говоря, это и не является необходимым для рассматриваемой обучающей программы - ведь, в конце концов, мы будем разрабатывать наш собственный клиент Google Talk , - все-таки полезно загрузить с http://www.google.com/talk/ клиента Google Talk . Таким путем вы получите возможность организовать "разговор" этих двух клиентов друг с другом.
  • Загрузите библиотеку Java проекта Smack для протокола XMPP . Перейдите к http ://www.igniterealtime.org/downloads/index.jsp и найдите библиотеку Smack . Выберите файл ZIP (размер 2.4 Мбайт) или файл tar . gz (размер 1.6 Мбайт) и загрузите его на вашу машину. Разархивируйте его. Пока нас интересуют только файлы smack . jar и smackx . jar .

Часть 1: Создание Java -приложения, которое разговаривает с Google Talk

Настройка Smack и подключение к Google Talk для программируемых чатов (чтение и отправление сообщений)

Запустите Oracle JDeveloper 11 g . Создайте новое приложение - и назовите его, например, GoogleTalk . Также создайте новый проект; например, GoogleTalkJavaClient .

Выберите из меню Application Template No Template [ All Technologies ] . Из меню, вызываемого нажатием правой кнопки мыши, или из меню Tools откройте окно диалога Project Properties для узла Project . Перейдите к узлу Libraries and Classpath .

Добавьте к проекту архивные файлы smack . jar и smackx . jar : кликните по кнопке Add JAR / Directory . Просмотрите библиотеки и файлы Smack , выберите оба файла (и smack . jar , и smackx . jar ) и кликните по кнопке Select .

Файл JAR будет добавлен к проекту.

Кликните по кнопке OK .

Теперь мы создадим класс, который будет в состоянии через Google Talk посылать сообщения IM . Создайте в пакете otn . adf . googletalk класс MessageSender . Дайте Oracle JDeveloper указание добавить основной ( main ) метод.

package otn.adf.googletalk;

import org.jivesoftware.smack.ConnectionConfiguration;

import org.jivesoftware.smack.XMPPConnection;

import org.jivesoftware.smack.XMPPException;

import  org.jivesoftware.smack.packet.Message;

public class  MessageSender {

    private static String username =  "YOUR_GOOGLE_TALK_USERNAME";

    private static String password =  "YOUR_GOOGLE_TALK_PASSWORD";

    ConnectionConfiguration connConfig;

    XMPPConnection connection;

                      

    public MessageSender() throws  XMPPException {

        connConfig = new  ConnectionConfiguration("talk.google.com", 5222,  "gmail.com");

        connection = new XMPPConnection(connConfig);

        connection.connect();

        connection.login(username, password);

    }

   

    public void sendMessage(String to, String  message ) {

        Message msg = new Message(to,  Message.Type.chat);

        msg.setBody(message);

       connection.sendPacket(msg);

    }

   

    public void disconnect() {

        connection.disconnect();

    }

   

    public static void main(String[] args)  throws XMPPException {

       MessageSender messageSender = new  MessageSender();

       messageSender.sendMessage("youraccount@gmail.com", 

             "Hello You. This is my first message sent programmatically using Smack API  and Google Talk.");

       messageSender.disconnect();

   }

}

Удостоверьтесь, что в строках 10 и 11 вы вставили имя и пароль для своего собственного аккаунта Google Talk . Также вставьте свой аккаунт (или аккаунт вашего друга) в строку 36, как пункт назначения (адресат) этого сообщения: " Hello , world of instant messaging ".

Конструктор класса MessageSender создает подключение к серверу Google Talk и регистрируется на нем (строки 17-21). После создания экземпляра MessageSender вызывается метод sendMessage с адресатом (кому посылается сообщение) и с самим текстом сообщения. И, наконец, подключение закрывается с помощью метода разъединения.

Когда вы выполните приложение, то быстро получите свое первое сообщение Google Talk , посланное вашим собственным приложением через сервер Google Talk :

 
 

Присутствие

Одной из хороших возможностей мгновенного обмена сообщениями является присутствие ( presence ), то есть индикация того, кто из друзей и контактов доступны в данный момент. И Google , и API Smack поддерживают присутствие.

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

// сказать миру (или хотя бы нашим друзьям), что мы доступны

Presence presence = new  Presence(Presence.Type.available);

presence.setMode(Presence.Mode.chat);

connection.sendPacket(presence);

Примечание : мы можем выбирать из нескольких режимов присутствия: available (доступен), chat (в чате), away (отошел), xa ( extended away - расширенное отсутствие) и dnd ( do not disturb - просьба не беспокоить).

Еще более интересен для нас тот факт, что наша программа может узнать о присутствии всех наших контактов - в терминах IM , поименный список ( roster ) - или о присутствии определенного контакта. Вот так определяется список всех наших контактов:

Roster roster =  connection.getRoster();

Collection iter =  roster.getEntries();

for (RosterEntry entry : iter) {

     System.out.println(entry.getName()  + " (" + entry.getUser() + ")");

}

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

Если бы мы могли бы только посылать сообщения, то наш разговор (то есть, сеанс связи) был бы весьма унылым. Следующий шаг, который мы собираемся предпринять, добавляет нашему "приложению" возможности прослушивания. Мы создадим класс MessageListener , который будет выглядеть в высшей степени похожим на класс MessageSender. Фактически, для его создания достаточно сначала сохранить файл MessageSender . Java как MessageListener . Java , а затем использовать поиск и замену, чтобы заменить все вхождения слова MessageSender на MessageListener .

Затем сделаем так, чтобы класс реализовывал интерфейс PacketListener , добавляя к спецификации класса implements PacketListener . Единственное требование, предъявляемое нам этим интерфейсом, это реализация метода processPacket , как показано в этом примере:

public void processPacket(Packet packet) {

    Message message = (Message)packet;

    System.out.println("Message  (from: "+message.getFrom()+"): "+message.getBody());

}

После того, как мы зарегистрировали наш класс как прослушиватель для сообщений с подключением, этот метод будут вызывать всякий раз, когда сервер Google Talk посылает сообщение нашему подключению. Регистрация нашего класса как "прослушивателя" для сообщений из чата на наш акаунт делается путем добавления этих строк программы в конце конструктора для MessageListener ():

// прослушивать поступающие сообщения для этого подключения

PacketFilter filter = new  MessageTypeFilter(Message.Type.chat);

connection.addPacketListener((PacketListener)this,  filter);

Примечание: Мы должны добавить к нашему классу следующие операторы импорта; однако, если мы добавим код, описанный выше, то Oracle JDeveloper , вообще говоря, сделает это за нас.

import org.jivesoftware.smack.filter.PacketFilter;

import org.jivesoftware.smack.filter.MessageTypeFilter;

import org.jivesoftware.smack.PacketListener;

import org.jivesoftware.smack.packet.Packet;

Теперь мы готовы получать сообщения. Если мы изменим основной метод нашего класса MessageReceiver следующим образом, то получим наше собственное (посланное нами же) сообщение:

public static void main(String[] args) throws XMPPException,

                                                     InterruptedException {

    MessageListener messageListener = new  MessageListener();

    messageListener.sendMessage("youraccount@gmail.com",

                    "Hello You. This is my second message sent programmatically using Smack API and Google Talk.");

    // listen for 3 seconds

    Thread.sleep(3000);

    messageListener.disconnect();

}

Конечно, вместо того, чтобы говорить с самим собой, было бы намного лучше слушать сообщения из чата, посланные нашими друзьями. Если ни один из них в настоящее время не доступен, Google Talk предлагает вам ряд "друзей", с которыми можно разговаривать. Эти так называемые боты являются программируемыми аккаунтами Google Talk , которые предлагают перевод с одного языка на другой. Боты имеют аккаунты типа en2zh@bot.talk.google.com и nl2en@bot.talk.google.com, составленные из двухбуквенных сокращений языка-источника и выходного языка. (Уведомление о ботах перевода Google Talk можно найти, например, на http://googletalk.blogspot.com/2007/12/merry-christmas-god-jul-and.html )

Мы можем просто послать сообщение из чата боту Google , и он пошлет нам возвращаемое сообщение, что попросту говоря, просто великолепно для быстрого нахождения перевода простых слов или фраз. Мы можем изменить основной метод еще раз и сделать так, чтобы он считал на французском языке от 1 до 10 (хотя, конечно, для того чтобы сделать это, вы не нуждаетесь в боте перевода):

MessageListener messageListener = new  MessageListener();

    String[] englishCounting = new String  [] {"one", "two", "three", "four",  "five", "six",  "seven", "eight", "nine", "ten"};

    for (int  i=0;i< messageListener.disconnect(); } Thread.sleep(500); order right the in replies receiving of chances increase to pause slight add englishCounting[i]); messageListener.sendMessage(?en2fr@bot.talk.google.com?, { i++)>

Результат выполнения приложения на этот раз - счет на французском языке:

Примечание: на своем сервере боты Google Talk выполняются многопоточно (то есть, несколькими потоками). Это означает, что если задержка между посланными боту сообщениями достаточно мала, ответы могут быть возвращены в другом порядке, поскольку, например, поток, обрабатывающий слово "пять", может фактически ответить быстрее, чем поток, имеющий дело со словом "два". Если же перед посылкой следующего сообщения мы будем ожидать 500 мс (или около того), то у нас будут неплохие шансы получить все ответы в надлежащем порядке.

Часть 2: построение Oracle ADF Faces Rich Client

Теперь, когда у нас имеется наше базовое приложение Java , которое может и посылать сообщения в чат, и принимать их, пришло время узнавать, как можно создать Web -приложение, которое сможет делать те же самые вещи. Мы будем использовать Oracle ADF Faces Rich для создания пользовательского интерфейса поверх уровня связывания данных Oracle ADF , чтобы подключить Web -уровень к сервисам данных, которые обеспечивают доступ к контенту и операциям.

Мы добавим к MessageSender небольшую дополнительную функциональную возможность: свойство под названием roster (именной список) - список наших "приятелей по чату" - друзей, которых мы добавили в Google Talk .

Сначала создадим новый класс по имени TalkMate , bean -компонент с двумя свойствами: toName и displayName .

package  otn.adf.googletalk;

public class  TalkMate {

     String toName;

     String displayName;

     public TalkMate() {

     }

     public void setToName(String toName) {

         this.toName = toName;

     }

     public String getToName() {

         return toName;

     }

     public void setDisplayName(String  displayName) {

         this.displayName = displayName;

     }

     public String getDisplayName() {

         return displayName;

     }

}

Добавим к классу MessageSender следующее приватное свойство:

private Collection<TalkMate> roster = new ArrayList();

и создадиме для этого свойства методы средств доступа (получатель ( getter ) и посылающий ( setter )).

Затем добавим к методу конструктора MessageSender () следующие строки программы:

Roster friendsRoster = connection.getRoster();

Collection  rosterIter = friendsRoster.getEntries();

for (RosterEntry entry : rosterIter) {

   TalkMate friend = new TalkMate();

   friend.setDisplayName(entry.getName()!=null?entry.getName():entry.getUser());

   friend.setToName(  entry.getUser());

   this.roster.add(friend);

} rosterIter //

// также, в проверочных целях, добавьте к чату с самим собой

// ваш собственный аккаунт

TalkMate veryBestFriend = new TalkMate();

veryBestFriend.setDisplayName("Your  Own Display Name");

veryBestFriend.setToName(  "YOUR_OWN_GOOGLE_TALK_ACCOUNTNAME");

this.roster.add(veryBestFriend);

 

Теперь мы создадим bean -компонент MessageReceiver , который показывает возможности прослушивания чата способом, дружественным к потенциальным потребителям. Сначала создадим следующий bean -компонент:

package  otn.adf.googletalk;

import  Java.util.Date;

public class  ChatMessage {

     private Date timestamp;

     private String from;

     private String body;

    

     public ChatMessage() {

     }

     public ChatMessage(String from, String  body) {

          this.timestamp = new Date();

          this.from = from;

          this.body = body;

     }

     public void setTimestamp(Date timestamp) {

         this.timestamp = timestamp;

     }

     public Date getTimestamp() {

         return timestamp;

     }

     public void setFrom(String from) {

         this.from = from;

     }

     public String getFrom() {

         return from;

     }

     public void setBody(String body) {

         this.body = body;

     }

     public String getBody() {

         return body;

     }

}

Затем - класс MessageReceiver, что-то вроде этого :

package otn.adf.googletalk;

import Java.util.ArrayList;

import Java.util.List;

public class  MessageReceiver {

    private List messages =  new ArrayList();

    public MessageReceiver() {

        try {

            MessageListener messageListener =  new MessageListener();

            messageListener.setReceiver(this);

        } catch (Exception e) {

        }

    }

    public void processMessage(String from,  String body) {

        ChatMessage message = new  ChatMessage(from, body);

        messages.add(0, message);

        for (ChatMessageListener  listener:messageListeners) {

            listener.processChatMessage(message);

        }

    }

    public void  setMessages(List messages) {

        this.messages = messages;

    }

    public List  getMessages() {

        return messages;

    }

}

Чтобы заставить все это работать вместе, мы должны внести в класс MessageListener небольшое изменение. Добавим получателя приватного ( private ) свойства к классу MessageListener , и создадим для него получателя и посылающего:

MessageReceiver receiver;

Затем добавьте в метод processPacket() следующую строку:

if (this.receiver != null) {

      receiver.processMessage(message.getFrom(), message.getBody());

}

Это заставит MessageListener вызывать processMessage из MessageReceiver, что , в свою очередь , добавит новый ChatMessage к коллекции сообщений в bean- компоненте MessageReceiver.

Чтобы показать MessageSender и bean- компоненты MessageReceiver в палитре управляющих элементов данных Oracle ADF (Oracle ADF Data Control Palette), мы должны опубликовать оба bean- компонента как элементы управления данными . Давайте сначала сосредоточимся на MessageSender : Создайте и опубликуем управление данными из меню, вызываемого щелчком по правой кнопке мыши, из узла bean -компонента:

 

После того как Oracle JDeveloper закончит создание элемента управления данными, мы найдем MessageSender в палитре элементов управления данными, доступной для использования любым клиентом Oracle ADF:

 

Также опубликуйте элемент управления данными для MessageReceiver тем же способом, что и MessageSender - из меню, вызываемого правой кнопкой мыши.

Теперь в приложении Google Talk создайте новый проект; назовите его GoogleTalkWebClient . Этот проект будет содержать наше Web -приложение, страницу JavaServer Faces ( JSF ), и связанные с ними конфигурационные файлы.

После создания Web-проекта выберите в навигаторе узел GoogleTalkWebClient , перейдите к New Gallery и выберите создание страницы JSF .

Назовите страницу, например, ChatClient . jspx :

 

Кликните по OK , и страница будет создана.

На этой странице мы хотели бы иметь два раздела: один для того, чтобы писать и посылать сообщения в чат, и второй, в котором перечисляются поступающие сообщения. В этой статье мы не будем уделять слишком много внимания проведению сеансов связи (разговоров) в чате с многочисленными реципиентами (получателями) - мы оставим это, как упражнение для читателя (Вас, скорее всего, просто бесит, когда автор пытается выйти сухим из воды, отделываясь выражениями типа этого).

С созданием двух разделов на странице очень удачно справляется компонент Oracle ADF 11 g Faces Rich Panel Splitter . Перетащите этот компонент из палитры компонентов и опустите его на страницу. Это даст нам панель с двумя разделами для посылки и получения сообщений. Установите ширину разделителя панелей на 100%.

Перетащите sendMessage () в первый фасет. Опустите его как ADF Parameter Form .

 
 

Задайте в следующем диалоговом окне осмысленные подсказки:

 
 

Отображается следующее диалоговое окно и позволяет нам установить значения по умолчанию входных параметров операции sendMessage (). Кликните по OK , чтобы принять параметры настройки.

Oracle JDeveloper создаст на странице два элемента inputText и кнопку управления, а также файл PageDefinition с итератором variables , содержащим две переменные, два элемента attributeValues и элемент operationBinding для операции sendMessage ().

 
 

Измените размеры элемента messageBody - установите rows = 15 и columns = 60.

Удалите message_to элемента inputText. Мы заменим его списком всех наших контактов, из которого может быть выбран требующийся контакт.

Перетащите атрибут displayName из коллекции списка в MessageSender Data Control на нашу страницу и опустите его непосредственно перед Message inputText , как ADF Select One Choice .

 
 

Появится диалоговое окно Edit List Binding . Как источник базовых данных (Base Data Source) выберите variables iterator . Как источник списка данных (List Data Source) выберите MessageSender.root.roster . Отобразите Data Value sendMessage_to на List Attribute toName и выберите displayName как Display Attribute ( атрибут элемента изображения ). Затем кликните по OK .

 

Когда вы теперь будете выполнять страницу ChatClient , можно послать сообщения в чат вашим друзьям по Google Talk .

Наш следующий шаг должен расширить ChatClient , чтобы также и получать посланные нам из чата сообщения. Перетащите коллекцию Messages на элемент управления данными MessageReceiver Data Control второго фасета Panel Splitter на странице ChatClient . Опустите эту коллекцию как ADF Read - Only Table .

 
 

В появляющемся окне диалога Edit Table Columns сохраните только столбцы from и body .

Также перетащите на страницу операцию Execute в Messages collection и опустите ее как командную кнопку под таблицей Messages , которую мы создали выше.

Измените текст на кнопке с Execute на Refresh .

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

Архитектура этого небольшого приложения может быть изображена так, как на этом рисунке:

 

Бизнес-сервис в нашем приложении составлен из классов MessageSender и MessageReceiver , которые - благодаря помощи библиотеки Smack - взаимодействуют с сервером Google Talk . Оба этих класса были опубликованы, как ADF Data Controls . Страница JSF связала эти элементы управления данными: связывание операций для операции SendMessage в MessageSender Data Control и связывание таблицы для коллекции Message элемента MessageReceiver Data Control . У ADF Collections имеется множество связанных с ними действий, одно из которых - это действие Execute , которое обновит коллекцию; оно привязано к кнопке Refresh .

Отметьте, что можно заставить страницу работать немного более гладко, если установим partialSubmit на истину ( TRUE ) для обеих кнопок и добавим значение ID кнопки Refresh атрибуту partialTriggers таблицы Messages :

<af:commandButton actionListener="#{bindings.Execute.execute}"

text="Refresh"

disabled="#{!bindings.Execute.enabled}"

partialSubmit="true" id="refreshReceived" />

<af:table value="#{bindings.messages.collectionModel}" var="row"

rows="#{bindings.messages.rangeSize}"

emptyText="#{bindings.messages.viewable ? 'No rows yet.' : 'Access Denied.'}"

fetchSize="#{bindings.messages.rangeSize}"

partialTriggers="refreshReceived" >

Я послал одно сообщение самому себе - и получил некоторое число сообщений от моего старшего сына, пытающегося привлечь мое внимание:

 

Не стесняйтесь и далее украшать эту страницу, она уже сейчас справляется с порученной ей работой, но все здесь можно немножко "причесать". Например, установите на ложь ( false ) атрибут noWrap для столбца Body , который отображает тело сообщения чата; при этом будет показано все тело сообщения (в нескольких строках, если это необходимо). Использование контейнеров PanelBox - это простой путь к добавлению некоторого контекстного фрейма и заголовка к различным компонентам нашей страницы.

Часть 3: использование функциональных возможностей Oracle ADF Active Data Service для "активизации" Web -клиента

Хорошо, теперь наш Web -клиент "разговаривает" с Google Talk . Отправка сообщений, получение сообщений …, о чем еще, казалось бы, можно мечтать? Но есть одна вещь, которая далека от идеала - мы должны кликнуть по кнопке Refresh , чтобы увидеть недавно полученные сообщения. Мы хотели бы, чтобы наш клиент чата автоматически сообщал о получаемых им сообщениях. И это именно та функциональная возможность, которую мы собираемся добавить к Web -приложению, используя Oracle ADF Active Data Service ( ADS ).

В стек технологий Oracle Fusion включен ADS , который позволяет связывать некоторые компоненты Oracle ADF Faces с активными источниками данных, используя уровень моделирования Oracle ADF или управляемые bean -компоненты. Компоненты, включая таблицу, дерево и все типы графов и диаграмм, могут поддерживать ADS - что означает, что они обновляются почти в реальном времени, в то время как входят в силу изменения в основном источнике данных.

Чтобы использовать ADS , нужно иметь склад данных, который сообщает о событиях изменения данных, и вы должны создать бизнес-сервисы, которые реагируют на эти события, а также связанные элементы управления данными для представления этих сервисов. Альтернативным способом использования функциональных возможностей ADS наших компонентов является использование управляемого bean -компонента для атрибута числовой величины, и наличие bean -компонента реализует интерфейс ActiveDataModel .

Именно это мы затем сделаем: мы базируем таблицу Messages на новом управляемом bean -компоненте, который реализует ActiveDataModel и регистрирует себя с нашим классом MessageReceiver для новых событий ChatMessage .

Сначала внесем некоторые изменения в наш бизнес-сервис.

Создадим интерфейс ChatMessageListener:

package otn.adf.googletalk;

public interface ChatMessageListener {

   public void  processChatMessage(ChatMessage message);

}

Затем применим к классу MessageReceiver некоторые изменения.

Вставим строки, которые добавляют приватный список ChatMessageListeners и метод, позволяющий внешним партнерам регистрировать программы прослушивания:

private  List messageListeners = new ArrayList();

public void  registerChatMessageListener(ChatMessageListener listener) {

    messageListeners.add(listener);

}

Добавим эти строки к методу processMessage:

for (ChatMessageListener listener:messageListeners) {

    listener.processChatMessage(message);

}

Они позаботятся о вызове каждого зарегистрированного слушателя всякий раз, когда будет получено новое сообщение ChatMessage .

 

Теперь мы создадим в проекте GoogleTalkWebClient новый класс: GoogleTalkActiveListener . Этот класс реализует интерфейс ChatMessageListener и регистрируется с MessageReceiver . Он также расширяет CollectionModel ADF , чтобы заставить его действовать как источник данных для компонента таблицы. Это необходимо для реализации таких методов как getRowData (), getRowCount (), getRowIndex (), getRowKey () и setRowKey ().

Однако реальный интерес в этом классе представляет та его часть, которая реализует интерфейс ActiveDataModel . Он указывает на компонент таблицы, который может регистрировать с этим классом как ActiveDataListener для ActiveDataUpdateEvents . Всякий раз, когда наш класс GoogleTalkActiveListener получает новое сообщение, он посылает новое ActiveDataUpdateEvent всем программам прослушивания; в нашем случае только таблице. Таблица использует проталкивание с сервера на клиент для обновления списка сообщений, отображенных в браузере.

Мы должны пройти следующие шаги:

1. Создание класса GoogleTalkActiveListener .

Некоторые из ключевых разделов этого класса упомянуты ниже; полный листинг содержится в каталоге /Part3/ в project files download .

В конструкторе мы имеем экземпляр MessageReceiver , связанный с текущей страницей. Затем мы регистрируем новый экземпляр GoogleTalkActiveListener с MessageReceiver как ChatMessageListener .

public GoogleTalkActiveListener() {

   DCBindingContainer bc =

     (DCBindingContainer)FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet

                                                              (FacesContext.getCurrentInstance(),

                                                               "#{bindings}",

                                                               Object.class);

      MessageReceiver messageReceiver =

              (MessageReceiver)bc.findDataControl("MessageReceiver").getDataProvider();

          messageReceiver.registerChatMessageListener(this);

  …

processChatMessage () вызывается MessageReceiver всякий раз, когда бывает получено GoogleTalkChatMessage. В свою очередь он создает ActiveDataUpdateEvent с единственным ActiveDateEntry для нового сообщения. Это событие посылают всем зарегистрированным ActiveDataListeners:

public synchronized void  processChatMessage(ChatMessage message) {

    Map values = new HashMap();

    values.put("body", message.getBody());

    values.put("from",  message.getFrom());

    ActiveDataEntry newEntry = new  ChatActiveInsertDataEntry(values, "" + ++rowCount);

    List updateList  = new ArrayList();

    updateList.add(newEntry);

    ActiveDataUpdateEvent event =

              new  ChatActiveDataUpdateEvent(this, rowCount, updateList);

    for (ActiveDataListener listener :  adsListeners) {

        try {

              listener.dataChanged(event);

        } catch (Throwable e) {

        }

    } //конец цикла for

}

2. Конфигурирование управляемого bean- компонента googleTalkActiveListener.

    googleTalkActiveListener

    googletalkwebclient.GoogleTalkActiveListener

    session

3. Изменение атрибута величины в компоненте af:table для того, чтобы он ссылался на управляемый bean -компонент вместо связывания таблицы.

<af:table value="#{googleTalkActiveListener}" var="message">

4. Удаление кнопки Refresh со страницы ChatClient . Дело не только в том, что ее обновление - это неправильная вещь (связывание таблицы, которую таблица больше не использует); мы также не испытываем необходимости в опции обновления ( refresh ), благодаря инфраструктуре ADS .

Здесь мы видим ADS в действии: я кликнул по сообщению в чат в левой стороне страницы.

Сообщение, которое я послал, меньше чем через секунду было получено и моим клиентом Google Talk , и таблицей сообщений с поддержкой ADS в правой стороне экрана. Благодаря проталкиванию с сервера на клиент, без какого бы то ни было взаимодействия пользователя с системой сообщение из чата появляется в браузере.

 
 

Часть 4: метод буксировки для перетаскивания записей данных в чат

В этой последней части мы рассмотрим, как функциональные возможности чата, созданные нами к настоящему времени, могут быть объединены в реальную информационно-ориентированную страницу нашего приложения. Мы увидим, как можно использовать функциональные возможности метода буксировки ("перетащил и оставил"), доступные в Oracle ADF 11 g Faces Rich , чтобы позволить пользователям перетаскивать записи, отображенные на странице, и опускать их в компоненте чата, чтобы добавить суть записи в сообщение чата, которое можно послать коллеге или другу.

Шаги для достижения этих очень привлекательных расширенных функциональных возможностей являются на удивление простыми и требуют всего лишь небольшого кодирования на третьем шаге:

•  Предложите данные для отображения.

  1. Сделайте макет страницы, включая таблицу данных.
  2. Добавьте функциональные возможности перетаскивания .

Предложите данные для отображения

Давайте сначала обеспечим некоторые данные для этого приложения. Чтобы избавить вас от проблем, связанных с необходимостью получения доступа к базе данных, для подачи некоторых данных мы используем несколько bean -компонентов. Источники этих классов вы найдете в числе ресурсов для этой обучающей программы.

Класс LibraryManager расширяет ArrayList . Он создает множество экземпляров Book Bean и делает их доступными потенциальным потребителям. Класс LibraryManager сконфигурирован как управляемый bean- компонент :

    libraryManager

    otn.adf.googletalk.model.LibraryManager

    session

Сделайте макет страницы, включая таблицу данных

Страница ChatClient . jspx готова к некоторому "косметическому ремонту". Ниже приводятся требующиеся для этого шаги:

  1. Добавьте к узлу af:form компонент panelSplitter . Задайте горизонтальную ориентацию этого panelSplitter . Установите SplitterPosition на 400, а Inline Style на width:100%; height:800px.
  2. Перетащите существующий panelSplitter в первый фасет только что добавленного panelSplitter . Задайте ему вертикальную ориентацию, а SplitterPosition установите на 320.
  3. Если вы не сделали этого раньше, установите атрибут noWrap для столбца Body в таблице Messages на FALSE , чтобы можно было организовать многострочный показ полученных сообщений.
  4. Перетащите компонент управляющего поля из палитры компонентов во второй фасет в новом PanelSplitter . Установите текст на Books .
  5. Перетащите компонент таблицы из палитры компонентов во второй фасет в новом PanelSplitter . Свяжите таблицу с bean -компонентом # { libraryManager }. Установите тип элемента на класс otn . adf . googletalk . model . Book ; это поможет Oracle JDeveloper заполнить список столбцов. Перестройте их в указанном порядке; удалите столбец ключевых слов. Измените тип компонента для столбца Thumbnail на af:image. Кликните по кнопке OK , чтобы добавить компонент таблицы к странице.

Затем установите Inline Style для компонента Thumbnail af:image на width:60px.

 
 

Окно структуры для страницы должно теперь выглядеть как-то вроде этого:

 
 

В этот момент можно выполнить страницу, и вы увидите таблицу с некоторыми деталями книги справа от интегрированного средства чата в левой стороне страницы. Однако, интеграция перетаскивания все еще не доступна.

Добавьте функциональные возможности перетаскивания

Чтобы указать инфраструктуре Oracle ADF 11 g Faces Rich , что записи в таблице являются перетаскиваемыми (источники перетаскивания), мы должны добавить в таблицу элемент Collection Drag Source :

 

Определите в этом элементе атрибут modelName :

<af:collectionDragSource actions="COPY"

modelName="libraryModel"/>

Аналогично мы должны определить, что должно быть целевым пунктом перемещения для этой операции перетаскивания. Нашим целевым пунктом перемещения является элемент inputText записи Message , который мы используем для печати сообщения из чата. Мы должны добавить к этому inputText элемент DropTarget :

 
 

Мы специфицируем af:dataFlavor, как принимающий экземпляры класса org.apache.myfaces.trinidad.model.RowKeySet, которые являются тем же, что и полезная нагрузка для операций перетаскивания в записях таблицы; также установите дискриминантный (отличительный) атрибут на libraryModel . Примечание: чтобы сделать элемент inputText регенерируемым через частичную визуализацию страницы ( partial page rendering - PPR), мы должны назначить ему ID - подойдет любое уникальное значение ID .

Поскольку мы должны проделать некоторые манипуляции с текстом сообщения, мы будем использовать свойство управляемого bean-компонента, чтобы связать значение inputText с переменной из pageDefinition; установите атрибут величины на #{googleTalkActiveListener.messageBody}. Наконец, мы должны определить, как будет обработано событие опускания. Для этого установите атрибут dropListener элемента dropTarget на #{ googleTalkActiveListener . handleDrop }.

 <af:inputText id="msgbody"

       value="#{googleTalkActiveListener.messageBody}"

       label="Message"  columns="60"

       rows="10">

       <f:validator  binding="#{bindings.message.validator}"/>

       <af:dropTarget  actions="COPY"

                   dropListener="#{googleTalkActiveListener.handleDrop}">

       <af:dataFlavor  flavorClass="org.apache.myfaces.trinidad.model.RowKeySet"

                                                        discriminant="libraryModel"/>

       </af:dropTarget>

</af:inputText>

Теперь мы добавили две ссылки на элементы в bean -компоненте googleTalkActiveListener , которого пока еще не существует. Таким образом, заключительный шаг для того, чтобы заставить "перетаскивание" работать, будет сделан в классе GoogleTalkActiveListener . Сначала добавим свойства messageBody и messageAddition (оба типа String ) и handlingDrop (типа Boolean ). Сгенерируем аксессоры ( accessors ) для свойства messageBody .

Метод handleDrop вызывается всякий раз, когда элемент msgBody обнаруживает событие опускания ( drop event ). Он получает экземпляр класса DropEvent и возвращает экземпляр DnDAction . В нашем случае обработка события опускания означает выяснение, какая книга была опущена в области сообщения чата, и добавление описания этой книги к текущему сообщению чата.

public DnDAction handleDrop(DropEvent  dropEvent) {

     Transferable dropTransferable =  dropEvent.getTransferable();

     DataFlavor  rowKeySetFlavor =

     DataFlavor.getDataFlavor(RowKeySet.class);

     RowKeySet tableDrop =  dropTransferable.getData(rowKeySetFlavor);

     if (tableDrop != null) {

           // получить данные для опущенных строк

           CollectionModel dragModel =

                  dropTransferable.getData(CollectionModel.class);

           StringBuilder rowOutput = new  StringBuilder();

           if (dragModel != null) {

               for (Object currKey :  tableDrop) {

                    dragModel.setRowKey(currKey);

                    Object rowValue = dragModel.getRowData();

                    rowOutput.append(rowValue);

               }

           }     

           messageAddition=  rowOutput.toString();

           handlingDrop=true;

           return DnDAction.COPY;

      } else {

           return DnDAction.NONE;

      }

}

Из события опускания мы отыскиваем объект Transferable. Мы создаем экземпляр DataFlavor для класса, про который мы знаем, что именно он ожидается в этом конкретном событии опускания. Из объекта Transferable мы отыскиваем RowKeySet с ключами строки для записей Book в коллекции таблицы, которая была опущена в этом событии. Затем в цикле for мы извлекаем каждый из RowValues - экземпляров Book - и добавляем их (точнее, результат применения к ним метода toString ())в конец StringBuilder . В этом случае мы реализуем метод toString () для класса Book следующим образом:

@Override

public String toString() {

    return this.getTitle()+" by  "+this.getAuthor()+", published in "+this.getYear()+" by  "+this.getPublisher();

}

Итог всех опущенных записей затем сохраняется в свойстве messageAddition , а свойство handlingDrop устанавливается на истину ( TRUE ).

В методе setMessageBody (), который вызывается в течение фазы applyRequestValues , после того как выполняется метод handleDrop , мы объединяем текущее значение тела сообщения, посланного от клиента, с добавлением, извлеченным из опущенных записей:

public void setMessageBody(String  messageBody) {

      if (handlingDrop) {

           handlingDrop = false;>

           this.messageBody= messageBody  +" "+ messageAddition;

      } else {

           this.messageBody = messageBody;

      }

}

Когда вы теперь выполняете страницу ChatClient , вы перетаскиваете любые записи Book и опускаете их на область Message (и никуда больше).

 

Когда вы опускаете запись, детали книги добавляются к сообщению, как будто вы ввели их сами:

 
  Конечно, после удаления одной или большего количества книг, вы можете послать сообщение в чат; и снова, это будет точно так же, как если бы вы ввели детали книги сами.
 
 
 
 

Примите мои поздравления, вы только что построили "активное" приложение с толстым клиентом!

 
 

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 12.12.2008 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Oracle Database Standard Edition 2 Named User Plus License
Oracle Database Standard Edition 2 Processor License
Oracle Database Personal Edition Named User Plus Software Update License & Support
Oracle Database Personal Edition Named User Plus License
Oracle Database Standard Edition 2 Named User Plus License
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
Новые материалы
Все о PHP и даже больше
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100