Уровень сложности: средний Mark Talbot, Developer, Industry Solutions, IBM Kulvir Singh Bhogal, Consultant, Software Services for WebSphere, IBM
09.03.2007 Узнайте, как создать подключаемый модуль, воспроизводящий назначенный звуковой файл при поступлении мгновенного сообщения от указанного партнера системы Sametime.
Основанная на Eclipse архитектура IBM Lotus Sametime Connect V7.5 позволяет расширить ваше клиентское приложение на основное содержимое. В данной статье вы узнаете, как создать подключаемый модуль WAV Playback. Во время изучения вы узнаете, что происходит на программном уровне при получении мгновенного сообщения Sametime клиентским приложением Lotus Sametime. Вы также узнаете, как создать пользовательскую ответную реакцию на получаемое мгновенное сообщение. Следовательно, после прочтения данной статьи вы, основываясь на приобретенных знаниях, сможете начать свою собственную разработку клиентских подключаемых модулей для Sametime.
Данная статья предназначена для разработчиков приложений, интересующихся настройкой клиентских приложений Lotus Sametime Connect. Полезно, но необязательно, некоторое знакомство с Eclipse. Ожидается, что вы владеете языком программирования Java.
Предварительный осмотр подключаемого модуля WAV Playback
Подключаемый модуль WAV Playback для Lotus Sametime Connect V7.5 позволяет настроить клиентское приложение и назначить звуковой файл для выбранного Sametime-партнера. Вы управляете пользовательским интерфейсом Sametime для добавления элемента меню "Assign Audio file for IMs" в контекстное меню, появляющееся при нажатии правой кнопкой мыши на партнере (см. рисунок 1).
Рисунок 1. Элемент меню "Assign Audio File for IMs"
После выбора элемента контекстного меню "Assign Audio File for IMs" отображается окно, аналогичное изображенному на рисунке 2, в котором вы можете назначить звуковой файл, проигрываемый при получении мгновенных сообщений (IM) от выбранного Sametime-партнера. Подключаемый модуль хранит отображения Sametime-партнеров на звуковые файлы в отдельном файле свойств.
Рисунок 2. Выбор звукового файла
Получение и подготовка Eclipse 3.2 IDE
Для разработки подключаемого модуля WAV Playback мы использовали Eclipse 3.2 IDE, а потому предполагаем, что у вас Eclipse 3.2 IDE уже установлена. Если нет, перейдите на Web-сайт Eclipse [http://www.eclipse.org/downloads/] для получения программного обеспечения.
Мы также предполагаем, что вы знакомы с интегрированной средой разработки Eclipse IDE. Если нет, мы советуем вам перед прочтением данной статьи познакомиться с Eclipse IDE, изучив ресурсы, список которых приведен в разделе "Ресурсы".
Изменение целевой платформы Eclipse
Изменение целевой платформы с Eclipse на платформу Sametime позволяет вам расширить платформу Sametime, в противоположность расширению платформы Eclipse.
Для изменения целевой платформы на Lotus Sametime V7.5 в Eclipse выполните следующие действия:
- Выберите Window - Preferences для открытия диалогового окна Preferences.
- В панели слева разверните элемент Plug-in Development и выберите Target Platform.
- В панели справа появится страница Target Platform Preference Page. Нажмите кнопку Browse для изменения месторасположения.
- Измените вашу целевую платформу на месторасположение каталога, представляющего собой каталог с подключаемыми модулями Lotus Sametime V7.5 на вашей системе. Если вы установили Lotus Sametime V7.5 в каталог по умолчанию, месторасположением целевой платформы является каталог C:\Program Files\IBM\Sametime Connect 7.5\sametime.
- Нажмите кнопку Reload. Отобразятся подключаемые модули Sametime (см. рисунок 3).
- Нажмите кнопку OK для возврата в перспективу Plug-in Development.
Рисунок 3. Целевая платформа
Создание проекта подключаемого модуля
Для расширения Sametime UI функциональностью вашего проигрывателя звуковых файлов вы должны создать подключаемый модуль. Но перед созданием подключаемого модуля Sametime вам необходим проект подключаемого модуля, содержащий этот модуль на фазе разработки. Для создания такого проекта выполните следующие действия:
- В Eclipse выберите File - New - Project.
- В мастере New Project выберите Plug-in Development - Plug-in Project. Затем нажмите кнопку Next.
- Укажите com.devworks.example.sound в качестве имени проекта и нажмите кнопку Next.
- В панели Plug-in Content (как показано на рисунке 4) укажите WAV Playback в качестве названия подключаемого модуля. В поле plug-in provider укажите DeveloperWorks.
- Обратите внимание на то, что на рисунке 4 не отмечен флажок "This plug-in will make contributions to the UI". Sametime API предоставляют средства расширения Sametime UI. Поскольку вы расширяете только Sametime UI, делать добавление в Eclipse UI нет необходимости.
Рисунок 4. Мастер New Plug-in Project
- Подтвердите оставшиеся значения по умолчанию и нажмите Finish.
Настройка зависимостей подключаемого модуля
Для того чтобы позволить подключаемому модулю Sametime обнаружить классы графического интерфейса Sametime и системы обмена сообщениями, необходимые для разработки подключаемого модуля, отредактируйте его зависимости. Для этого выполните следующие действия:
- В Eclipse откройте ваш файл MANIFEST.MF из папки META-INF.
- Затем перейдите на закладку Dependencies, которая откроет вид Dependencies.
- В области Required Plug-ins нажмите кнопку Add. Появится диалоговое окно Plug-in Selection, как показано на рисунке 5.
- Выберите подключаемый модуль com.ibm.collaboration.realtime.people и нажмите кнопку OK.
Рисунок 5. Диалоговое окно Plug-in Selection
- Повторите шаги 3 и 4 для подключаемых модулей com.ibm.collaboration.realtime.messages, com.ibm.collaboration.realtime.core и com.ibm.collaboration.realtime.magiccarpet.
- Сохраните страницу Dependencies, нажав комбинацию клавиш Ctrl + S. Страница Dependencies должна выглядеть так, как показано на рисунке 6.
Рисунок 6. Страница Dependencies
Класс AudioPlayer и его метод playBack
Задача проигрывания звуковых файлов выполняется классом com.devworks.example.customsound.AudioPlayer. Проигрыватель звуковых файлов создается довольно просто, благодаря имеющимся в языке программирования Java аудио возможностям. Ниже приведен исходный код класса AudioPlayer.
public class AudioPlayer
{
public static void playBack(String filename) throws MalformedURLException
{
File file = new File(filename);
URL url = file.toURL();
java.applet.AudioClip clip = java.applet.Applet.newAudioClip(url);
clip.play();
}
}
|
Фактическая работа по проигрыванию звукового файла выполняется при загрузке вашего файла как java.applet.AudioClip (как это ни странно, вы можете использовать код, даже не применяя Java-апплет). Теперь, все что вы должны сделать для проигрывания вашего объекта AudioClip - использовать метод play.
ПРИМЕЧАНИЕ: Класс AudioPlayer может проигрывать звуковые файлы следующих форматов: WAV, AIF, MID, AU и RMF.
Файл sound.properties
Назначения проигрываемых классом AudioPlayer звуковых файлов при поступлении мгновенного сообщения для данного Sametime-партнера хранятся в файле свойств с названием sound.properties. Этот файл свойств должен размещаться в каталоге самого верхнего уровня подключаемого модуля. Вы можете изменять файл свойств вручную. Формат файла - идентификатор Sametime-партнера, за которым следуют знак равенства и месторасположение звукового файла. Ниже приведен пример содержимого файла sound.properties:
talbotm@us.ibm.com=C\:\\lotus\\flg\\media\\cheering.wav
kbhogal@us.ibm.com=C\:\\lotus\\flg\\media\\carskid.wav
Обратите внимание на необходимость использования двойных символов косая черта в путях файлов. Для предоставления более интуитивного метода мы позволяем пользователю Sametime-клиента обновлять связь Sametime-партнеров с месторасположением звуковых файлов графически через добавление элемента в контекстное меню, появляющееся при нажатии правой кнопкой мыши на Sametime-партнере, как показано на рисунке 1. Добавление элемента "Assign WAV file for IMs" в контекстное меню рассматривается в разделе "Точка расширения PopupMenus".
Класс SoundStore
К файлу sound.properties доступ осуществляется через класс com.devworks.example.sound.SoundStore. Класс SoundStore имеет методы getter и setter для получения и установки месторасположения звукового файла для конкретного Sametime-партнера. В следующем фрагменте кода показан класс SoundStore.
Объект Properties используется для размещения содержимого файла sound.properties. Логическая переменная (Boolean) initialized выступает в качестве переменной-переключателя, указывающей, инициализирован объект SoundStore или нет.
public class SoundStore {
public static Properties properties = new Properties();
public static boolean initialized = false;
private SoundStore() {
}
|
Показанный в следующем фрагменте кода метод initSoundCache читает содержимое файла sound.properties, который, как указывалось ранее, содержит отображения имя-значение идентификатора Sametime-партнера на месторасположение звукового файла.
private static void initSoundCache() {
properties = new Properties();
Activator soundActivator = Activator.getDefault();
Bundle soundBundle = soundActivator.getBundle();
URL propFile = soundBundle.getResource("sound.properties");
try {
if (propFile != null) {
InputStream inStream = propFile.openStream();
properties.load(inStream);
inStream.close();
initialized = true;
}
} catch (IOException e) {
e.printStackTrace();
}
}
|
В предыдущем коде URL файла sound.properties обнаруживается через общий экземпляр bundle. Имея URL, вы можете открыть поток для чтения файла свойств. Данные из файла свойств читаются затем в объект Properties с использованием InputStream. После загрузки свойств InputStream закрывается. Наконец, переменная initialized устанавливается в значение true, указывающее на то, что файл свойств был прочитан и объект properties заполнен.
В следующем фрагменте кода метод getSound читает объект Properties для определения месторасположения файла, назначенного данному идентификатору Sametime-партнера. Метод возвращает месторасположение файла, если оно определено. Если для данного партнера звуковой файл не назначен, метод возвращает пустую строку.
public static String getSound(String partnerId) {
String partnerSound;
if (!initialized)
initSoundCache();
Object soundObject = properties.get(partnerId);
if (soundObject != null)
partnerSound = (String) soundObject;
else
partnerSound = "";
return partnerSound;
}
|
В начале метода setSound мы проверяем, инициализирован ли объект SoundStore (что указывается значением логической переменной initialized). Если объект SoundStore не инициализирован, мы инициализируем его при помощи метода initSoundCache, описанного выше. Затем используется метод get объекта Properties для извлечения названия звукового файла для данного партнера.
Метод setSound класса SoundStore ответственен за обновление объекта Properties и файла sound.properties идентификатором указанного Sametime-партнера и названием файла.
public static boolean setSound(String partnerId, String soundFile) {
boolean success = false;
if (!init)
initSoundCache();
properties.setProperty(partnerId, soundFile);
URL propURL = Activator.getDefault().getBundle().getResource(
"sound.properties");
try {
if (propURL==null)
propURL = new URL("file:\\\\\\sound.properties");
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
String bundleLocation = Activator.getDefault().getBundle()
.getLocation();
File propFile = new File(bundleLocation + propURL.getPath());
FileOutputStream out;
try {
out = new FileOutputStream(propFile);
String header = null;
properties.setProperty(partnerId, soundFile);
properties.store(out, header);
out.close();
success = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return success;
}
|
Аналогично методу getSound, метод setSound сначала проверяет, инициализирован ли класс SoundStore. Если нет, вызывается инициализация посредством метода initSoundCache. URL файла sound.properties получается из метода getResource общего экземпляра bundle. Чтобы не возникло ошибки, при отсутствии файла sound.properties он создается. С этим URL файла создается объект FileOutputStream. Наконец, файл sound.properties обновляется объектом FileOutputStream, содержащим обновленный данные по связи Sametime-партнера со звуковым файлом.
Далее вы увидите, как объект SoundStore используется подключаемым модулем. Графический компонент нашего подключаемого модуля использует объект SoundStore, что описано в следующем разделе.
Точка расширения PopupMenus
Чтобы добавить элемент контекстного меню "Assign Audio File for IMs", появляющийся при нажатии правой кнопкой мыши на Sametime-партнере (см. рисунок 1), создайте класс, расширяющий класс LiveNameActionDelegate. Для получения дополнительной информации по данной теме мы рекомендуем вам прочитать статью по Lotus на developerWorks "Расширение клиентского приложения Lotus Sametime подключаемым модулем для просмотра каталога LDAP", в которой подробно рассмотрена эта концепция. Мы называем наш класс: AssociateSound.
При выборе элемента меню "Assign Audio file for IMs" включается метод run класса AssociateSound, приведенного ниже.
public class AssociateSound extends LiveNameActionDelegate {
public void run(IAction arg0) {
Person persons[] = getSelectedPersons();
Person person = persons[0];
if (person != null) {
String id = person.getContactId();
System.out.println("Associating Sound for "
+ id); //$NON-NLS-1$
setUserSoundBox(id);
}
}
|
В методе run для получения идентификатора Sametime-партнера, на котором была нажата правая кнопка мыши, используется метод getSelectedPersons объекта Person. Затем выполняется вызов метода setUserSoundbox():
public static void setUserSoundbox(String id) {
Shell shell = new Shell();
FileDialog dialog = new FileDialog(shell);
String file = SoundStore.getSound(id);
dialog.setFileName(file);
dialog.setFilterExtensions(new String[]
{"*.wav; *.aif; *.mid; *.au; *.rmf"});
dialog.setFilterNames(new String[]
{"Supported Audio Files (*.wav; *.aif;
*.mid; *.au; *.rmf)"});
dialog.open();
String fileName = dialog.getFilterPath()
+ File.separator + dialog.getFileName();
SoundStore.setSound(id, fileName);
}
}
|
Метод setUserSoundbox отображает виджет (widget) FileDialog, как показано на рисунке 2, предлагая пользователю выбрать месторасположение звукового файла. После выбора пользователем месторасположения звукового файла это месторасположение связывается с идентификатором Sametime-партнера в файле свойств (используя метод setSound объекта SoundStore).
Перед отображением виджета FileDialog вы сначала получаете месторасположение существующего звукового файла, связанного с Sametime-партнером (если звуковой файл уже назначался), через метод SoundStore.getSound(id). Месторасположение по умолчанию в FileDialog устанавливается в месторасположение текущего звукового файла Sametime-партнера через метод dialog.setFileName(file). Затем фильтруются расширения файлов для отображения только тех файлов, которые поддерживаются объектом AudioPlayer, с использованием метода dialog.setFilterExtensions(new String[]). После назначения звукового файла пользователем клиентского приложения Sametime обновляется объект SoundStore указанным им месторасположением звукового файла.
За связь класса LiveNameActionDelegate (т.е., com.devworks.example.sound.AssociateSound) с элементом контекстного меню, появляющегося при нажатии правой кнопкой мыши на идентификаторе Sametime-партнера, отвечает точка расширения org.eclipse.ui.popupMenus. Вы определяете класс com.devworks.example.sound.AssociateSound как класс, обрабатывающий элемент меню "Assign Audio file for IMs", в приведенном ниже определении точки расширения, которое должно быть добавлено в ваш файл plugin.xml.
<extension point="org.eclipse.ui.popupMenus">
<objectContribution
adaptable="false"
id="com.devworks.example.sound.prersonselection"
objectClass=
"com.ibm.collaboration.realtime.livenames.PersonSelection">
<action
class="com.devworks.example.sound.AssociateSound"
enablesFor="1"
id="com.devworks.example.sound"
label="Assign Audio File For IMs"
style="push"/>
</objectContribution>
</extension>
|
Намного более подробно точку расширения org.eclipse.ui.popupMenus мы рассмотрели в статье по Lotus на developerWorks "Расширение клиента Lotus Sametime с помощью плагина просмотра LDAP-директорий". Мы рекомендуем вам просмотреть эту статью для более глубокого освоения данной концепции.
Уведомление событиями
Когда Sametime-клиент получает мгновенное сообщение, он получает объект IMTextReceived. Lotus Sametime Connect V7.5 предоставляет шину системы обмена сообщениями, которая позволяет компонентам взаимодействовать друг с другом. Sametime-компоненты, принимающие участие в обмене сообщениями, называются участниками. Для получения сообщения из другого компонента компонент-участник должен знать только то, как взаимодействовать с шиной системы обмена сообщениями.
Перед дальнейшим погружением в детали реализации, специфичные для проигрывания звуковых файлов при поступлении мгновенного сообщения, мы сначала приведем высокоуровневый обзор способа доступа к шине системы обмена сообщениями:
- Для доступа к шине системы обмена сообщениями сначала создайте субкласс DefaultMessageHandler, класс, обрабатывающий события системы обмена сообщениями.
- Затем создайте субкласс MessageHandlerAdapter, класс, который подключается к шине системы обмена сообщениями через точку расширения.
- Затем переопределите конструктор по умолчанию класса MessageHandlerAdapter для вызова его конструктора с одним аргументом с DefaultMessageHandler (который был создан ранее) в качестве параметра. Это свяжет класс DefaultMessageHandler с классом MessageHandlerAdapter.
- Затем зарегистрируйте класс MessageHandlerAdapter с точкой расширения com.ibm.collaboration.realtime.messages.MessageHandlerListener. Регистрация с точкой расширения соединяет ваш класс MessageHandlerAdapter с шиной системы обмена сообщениями Sametime.
В следующих разделах мы рассмотрим наши классы DefaultMessageHandler и MessageHandlerAdapter.
Знакомство с нашим классом DefaultMessageHandler: SoundHandler
Для создания специальной реакции на получение мгновенного сообщения, необходимо создать класс, расширяющий класс com.ibm.collaboration.realtime.messages.DefaultMessageHandler. Создаваемый вами класс должен переопределять метод handleMessage, наследуемый им из родительского класса. В нашем случае мы создали класс com.devewokrs.example.sound.SoundHandler:
public class SoundHandler extends DefaultMessageHandler {
public void handleMessage(ImTextReceivedMessage message) {
String soundFile = "";
String partnerId = message.getPartnerID();
soundFile = SoundStore.getSound(partnerId);
if ((soundFile != null) &&
(soundFile.trim().equals(""))) {
File soundlocation = new File(soundFile);
if (soundlocation.exists()) {
try {
AudioPlayer.playBack(soundFile);
} catch (MalformedURLException e) {
MessageBox mBox =
new MessageBox(new Shell());
mBox.setMessage("Invalid Sound File");
mBox.setText(e.getMessage());
mBox.open();
}
}
}
}
|
Класс DefaultMessagerHandler имеет назначенный метод для обработки получения сообщений каждого типа, которые являются подклассами класса Message. Подключаемый модуль WAV Playback обрабатывает только текстовые сообщения. Таким образом, в приведенном выше коде мы переопределили метод handleMessage, который принимает класс ImTextReceivedMessage в качестве параметра. Этот метод вызывается при получении Sametime-клиентом текстового сообщения от партнера.
В предыдущем коде вы сначала получаете идентификатор партнера, передавшего мгновенное сообщение. Затем ищется месторасположение звукового файла для этого партнера при помощи вызова класса SoundStore, рассмотренного ранее. После определения месторасположения звукового файла проверяется его существование и затем проигрывается звук с использованием класса AudioPlayer. Если при проигрывании файла возникает ошибка, в окне сообщения отображается MalformedURLException.
Как упоминалось ранее, класс DefaultMessageHandler имеет метод для обработки каждого Sametime-класса, который является подклассом класса Message. Пока методы обработки этих сообщений не будут явно переопределены вашим подклассом DefaultMessageHandler, метод, унаследованный от родительского класса DefaultMessageHandler, выполняет холостую команду. Например, существуют переопределенные нами методы для получения ImTextReceivedMessage. Аналогично, существует соответствующий метод объекта com.ibm.collaboration.realtime.messages.FileReceivedMessage (для использования при получении файла) и т.д.
Хотя мы этого не делали, у вас есть возможность создать подкласс класса Message. Для обработки таких специализированных объектов Message не существует встроенного метода в классе DefaultMessageHandler. Вместо этого эти объекты подкласса Message обрабатываются абстрактным методом handleDefaultMessage, который вы должны включить в класс, расширяющий класс DefaultMessageHandler. Поскольку вы не создаете подкласс класса Message, метод handleDefaultMessage не делает ничего, что показано в следующем коде:
public void handleDefaultMessage(Message arg0) {
}
}
|
Подключение класса MessageHandler к шине системы обмена сообщениями: MessageHandlerAdapter
Вам нужен способ уведомления класса SoundHandler при получении объекта сообщения ImTextReceivedMessage. Здесь вступает в игру класс com.ibm.collaboration.realtime.messages.MessageHandlerAdapter. Этот класс адаптера является мостом между точкой расширения MessageHandlerListener (которую мы рассмотрим в следующем разделе) и нашим классом DefaultMessageHandler (или более точно - классом SoundHandler). Для установки этого моста создается класс com.devworks.example.sound.SoundHandlerAdapter, который расширяет класс MessageHandlerAdapter:
public class SoundHandlerAdapter extends MessageHandlerAdapter {
public SoundHandlerAdapter(MessageHandler arg0) {
super(arg0);
}
public SoundHandlerAdapter() {
super(new SoundHandler());
}
}
|
Обратите внимание на то, что в этом коде мы переопределили конструктор по умолчанию для приема нашего DefaultMessageHandler, SoundHandler, в качестве параметра. Затем регистрируется SoundHandlerAdapter с точкой расширения com.ibm.collaboration.realtime.messages.MessageHandlerListener.
Точка расширения MessageHandlerListener
Последним шагом в регистрации класса SoundHandler с шиной системы обмена сообщениями Sametime является регистрация только что определенного вами класса MessageHandlerAdapter с точкой расширения MessageHandlerListener, как показано в следующем фрагменте исходного кода. В ваш файл plugin.xml необходимо добавить определение расширения messageHandler.
<extension point="com.ibm.collaboration.realtime.messages.MessageHandlerListener">
<messageHandler class="com.devworks.example.sound.SoundHandlerAdapter" />
</extension>
В этом определении вы определяете расширение точки расширения MessageHandlerListener. Для тега messageHandler указывается ваш класс MessageHandlerAdapter, а именно: com.devworks.example.sound.SoundHandlerAdapter. При получении события клиентом Sametime уведомляется SoundHandlerAdapter. Этот адаптерный класс, в свою очередь, уведомляет класс SoundHandler. Если событие системы обмена сообщениями является событием ImTextReceivedMessage, активизируется метод handleMessage класса SoundHandler. Следовательно, если передавшему текстовое сообщение партнеру был назначен звуковой файл, этот файл будет проигрываться.
Заключение
Если вы принадлежите к людям, любящим все переделывать (автомобиль, пиццу и т.д.), вам придется по вкусу настраиваемая, расширяемая природа Lotus Sametime Connect V7.5, основанная на архитектуре Eclipse. В данной статье мы рассказали, как вы можете настроить способ реагирования клиентского приложения Sametime на получение мгновенного сообщения. В частности, мы показали, как программным способом изменить клиентское приложение Sametime для проигрывания звукового файла (который можно назначить для каждого Sametime-партнера) при получении мгновенного сообщения. Естественно, от вас зависит, что вы будете делать с полученным сообщением! Вы можете "научить" клиентское приложение Sametime делать другие вещи. Вы ограничены только вашим воображением!
Ресурсы Научиться
Получить продукты и технологии
Обсудить
Об авторах  | |  | Mark Talbot works for IBM as a developer for Industry Solutions. You can reach Mark at talbotm@us.ibm.com. |
 | |  | Kulvir Singh Bhogal works as a consultant for IBM Software Services for WebSphere, devising and implementing J2EE solutions at customer sites across the U.S. You can reach Kulvir at kbhogal@us.ibm.com. |
Выскажите мнение об этой странице
|