Архитектура сервисов OSGi: создание сервиса по требованию потребителя - PullRequest
5 голосов
/ 28 марта 2012

Я разрабатываю приложение в Eclipse RCP. Мне нужна помощь с дизайнерским решением относительно дизайна услуги.

У меня есть несколько пакетов, которые используются для предоставления объекта REngine другим модулям. REngine является интерфейсом для механизма вычислений, который может быть реализован несколькими способами. Пакеты предоставляют экземпляры REngine путем подключения к удаленному серверу или запуска локального потока вычислений. Некоторые пакеты требуют настройки с помощью графического интерфейса (но также должны быть доступны на безголовой платформе). Пакет клиента может запросить несколько REngine объектов для параллельных вычислений.

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

Код для этого можно резюмировать следующим образом:

class API.REngine { ... }

class REngineProvider.Activator {
    public void start(BundleContext ctx) {
      ctx.registerService(REngine.class.getName(), new REngineFactory(), null);
    }
}
class REngineProvider.REngineFactory implements ServiceFactory {
    public Object getService(Bundle bundle, ServiceReference reference) {
      return new MyREngineImplementation();
    }
    public void ungetService(REngine service) {
       service.releaseAssociatedResources();
    }
}

class RConsumer.Class {
    REngine getREngine() {
        ServiceReference[] references = bundleContext.getAllServiceReferences(REngine.class.getName(), null);
        for(ServiceReference ref: references) {
            try {
            return bundleContext.getService(ref);
            } catch (Exception e) {} // too bad, try the next one
        }
    }
}

Я бы хотел оставить эту модель. Приятно, что спецификация службы OSGi соответствует моему бизнес-требованию, чтобы объекты REngine были живыми объектами, которые следует освобождать, когда они больше не нужны.

Однако зарегистрированный сервис может предоставить только один экземпляр сервиса на пакет. При втором запросе сервиса возвращается кэшированный экземпляр (вместо создания нового). Это не соответствует моему требованию; пакет должен иметь возможность получать несколько объектов REngine от одного поставщика.

Я уже рассмотрел другие классы OSGi-фреймворка, но, похоже, ничего не помогло. Альтернативой является модель доски, но кажется странным зарегистрировать REngineRequestService, который используется пакетом REngineProvider для выдачи живого REngine.

Как мне реализовать это в OSGi? В качестве напоминания, вот мой список требований:

  1. Простое включение и отключение REngineProvider пакетов. Код клиента будет просто использовать другого провайдера.
  2. Конфигурация пакетов REngineProvider.
  3. Несколько REngine экземпляров на один клиентский пакет.
  4. Явное освобождение REngine экземпляров
  5. REngine создание может завершиться неудачей. Клиентский модуль должен знать причину.

Просто чтобы добавить решение, которое я выбрал в качестве будущей ссылки. Похоже, что платформа OSGi Services не предназначена для «запроса сервиса». Это пакет поставщика, который создает сервис, и пакет клиента, который может найти и использовать сервисы. Невозможно обеспечить автоматическую «Фабрику» для услуг по запросу пользователя.

Выбранное решение включает в себя модель OSGi для доски . На первый взгляд это может показаться очень сложным, но Blueprint может сильно помочь!

Файл поставщика blueprint.xml:

<reference-list interface="org.application.REngineRequest"
          availability="optional">
  <reference-listener 
          bind-method="bind" unbind-method="unbind">
      <bean class="org.provider.REngineProvider"/>        
  </reference-listener>

Класс REngineRequest является общим классом API, позволяющим провайдеру вводить свой объект REngine или устанавливать исключение, объясняющее, почему создание не сработало.

Для клиента использование REngine теперь так же просто, как и:

REngineRequest req = new REngineRequest();
ServiceRegistration reg = bundleContext.registerService(req, REngineRequest.class.getName(), engineCreationProperties);
req.getEngine().doSomeStuff();
reg.unregister();

Мы предполагаем, что поставщик никогда не остановится, пока клиент использует REngine. Если это так, REngine становится недействительным.

Ответы [ 3 ]

3 голосов
/ 28 марта 2012

ComponentFactory из Декларативные услуги - это то, что вам нужно.Большую часть времени вам лучше использовать DS вместо ручной регистрации и поиска сервисов.

Сторона поставщика должна зарегистрировать сервис фабрики REngine (вам не нужно реализовывать саму фабрику, DS сделает это длявы).Потребитель должен объявить зависимость «один ко многим» к сервису REngine.Во время выполнения все доступные фабрики будут внедрены, и потребитель может пройти через них, чтобы создать фактические экземпляры REngine.

3 голосов
/ 02 апреля 2012

Два года назад я пытался создать Подлинные Сервисные Фабрики, которые позже стали Параметризованными Сервисами. Однако после анализа выяснилось, что ничего не нужно, просто зарегистрируйте фабрику в качестве службы.

Тем не менее.

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

Если такая модель возможна, она обычно значительно упрощается. Затем я обычно использую DS с конфигурациями Configuration Admin, которые управляют экземплярами (один из наиболее полезных аспектов DS, см. http://www.aqute.biz/Bnd/Components).. С интеграцией метатипа вы даже получаете пользовательский интерфейс для редактирования свойств конфигурации.

1 голос
/ 28 марта 2012

Одним из решений было бы зарегистрировать REngineFactory как службу, а не саму реализацию REngine, и вернуть фабрику из метода getService.Таким образом, клиенты могут искать фабрику и, успешно найдя ее, использовать ее для получения новой реализации REngine.

...