Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Фреймворк Jitsi

Глава 10 из книги "Архитектура приложений с открытым исходным кодом", том 1.

Оригинал: "Jitsi", глава 10 из 1 тома книги "The Architecture of Open Source Applications"
Автор: Emil Ivov
Перевод: Н.Ромоданов

10.2. Jitsi и фреймворк OSGi

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

Кроме всего прочего, OSGi является модульным. Возможности в приложениях OSGi разделены на отдельные сборки. Сборка OSGi представляет собой немного большим, чем обычные файлы JAR, которые используются для распространения Java-библиотек и приложений. Jitsi представляет собой коллекцию таких сборок. Имеется сборка, которая отвечает за подключение к Windows Live Messenger, другая, в которой реализован XMPP, еще сборка, которая обрабатывает GUI, и так далее. Все эти сборки работают вместе в среде, которая с нашем случае предоставляется при помощи Apache Felix — реализации OSGi с открытым исходным кодом.

Все эти модули должны работать вместе. Сборка графического пользовательского интерфейса должна посылать сообщения через сборки, реализующие протоколы, которые, в свою очередь, должны запоминать их с помощью сборок обработки истории сообщений. Это то, для чего предназначены сервисы OSGi: они представляют собой часть сборки, которая видна всем остальным. Сервис OSGi чаще всего является группой интерфейсов Java, которые позволяют использовать специальные функциональные возможности, например, ведение журнала, отсылки сообщений по сети или получение списка последних вызовов. Классы, в которых фактически реализованы функциональные возможности, известны как реализация сервисов. Большинство из них носят название интерфейса сервиса, который они реализуют, с суффиксом "Impl" в конце названия (например, ConfigurationServiceImpl). Фреймворк OSGi позволяет разработчикам скрывать реализации сервисов и быть уверенным, что они никогда не будут видны снаружи сборки, в которой они находятся. Таким образом, другие сборки могут использовать их только через интерфейсы сервисов.

В большинстве сборок также есть активаторы. Активаторы являются простыми интерфейсами, в которых определены мотоды start и stop. Каждый раз, когда Felix в Jitsi загружает или удаляет сборку, он вызывает эти методы с тем, чтобы сборку можно было подготовить к работе или к завершению. Когда эти методы вызываются, Felix передает им параметр, называемый BundleContext. BundleContext предоставляет сборкам метод подключения к среде OSGi. Таким образом, они могут обнаружить, какой сервис OSGi они должны использовать, или зарегистрироваться сами (рис.10.1).

Рис.10.1: Активация сборки OSGi

Итак, давайте посмотрим, как это работает на практике. Представьте себе сервис, который реализует постоянное хранение и выборку свойств. В Jitsi это то, что мы называем ConfigurationService, и это выглядит следующим образом:

package net.java.sip.communicator.service.configuration;

public interface ConfigurationService
{
  public void setProperty(String propertyName, Object property);
  public Object getProperty(String propertyName);
}

Очень простая реализация ConfigurationService выглядит, например, следующим образом:

package net.java.sip.communicator.impl.configuration;

import java.util.*;
import net.java.sip.communicator.service.configuration.*;

public class ConfigurationServiceImpl implements ConfigurationService
{
  private final Properties properties = new Properties();

  public Object getProperty(String name)
  {
    return properties.get(name);
  }

  public void setProperty(String name, Object value)
  {
    properties.setProperty(name, value.toString());
  }
}

Обратите внимание, как сервис определен в пакете net.java.sip.communicator.service, а реализация - в net.java.sip.communicator.impl. Все сервисы и реализации разнесены в Jitsi по этим двум пакетам. OSGi позволяет, чтобы в сборках только некоторые пакеты были видны за пределами своего собственного архива JAR, так что такое разделение облегчает сборкам экспортировать только пакеты сервисов и оставлять их реализации скрытыми.

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

package net.java.sip.communicator.impl.configuration;

import org.osgi.framework.*;
import net.java.sip.communicator.service.configuration;

public class ConfigActivator implements BundleActivator
{
  public void start(BundleContext bc) throws Exception
  {
    bc.registerService(ConfigurationService.class.getName(), // имя сервиса
         new ConfigurationServiceImpl(), // реализация сервиса
         null);
  }
}

После того, как класс ConfigurationServiceImpl зарегистрирован в BundleContext, другие сборки могут начать его использовать. Ниже приведен пример, показывающий, как некоторая случайным образом выбранная сборка может использовать наш конфигурационный сервис:

package net.java.sip.communicator.plugin.randombundle;

import org.osgi.framework.*;
import net.java.sip.communicator.service.configuration.*;

public class RandomBundleActivator implements BundleActivator
{
  public void start(BundleContext bc) throws Exception
  {
    ServiceReference cRef = bc.getServiceReference(
                              ConfigurationService.class.getName());
    configService = (ConfigurationService) bc.getService(cRef);

    // И это все! У нас есть ссылка на реализацию сервиса
    // и мы готовы запустить сохраненные свойства:
    configService.setProperty("propertyName", "propertyValue");
  }
}

Еще раз обратите внимание на пакет. В net.java.sip.communicator.plugin мы сохраняем сборки, которые используют сервисы, определяемые другими сборками, но в которых ничего самостоятельно не экспортируется и не реализуется. Хорошим примером таких плагинов является конфигурационные формы: Они служат дополнениями к пользовательскому интерфейсу Jitsi, которые позволяют пользователям выполнять некоторые конкретные настройки приложения. Когда пользователи изменяют настройки, конфигурационные формы взаимодействуют с ConfigurationService или напрямую со сборками, ответственными за некоторую функциональную возможность. Впрочем, никакой из других сборок никогда не потребуется взаимодействовать с ними каким-либо другим образом (рис. 10.2).

Рис.10.2: Структура сервиса


Продолжение статьи: 10.3. Собираем и запускаем сборку.