Я разрабатываю приложение в 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? В качестве напоминания, вот мой список требований:
- Простое включение и отключение
REngineProvider
пакетов. Код клиента будет просто использовать другого провайдера.
- Конфигурация пакетов REngineProvider.
- Несколько
REngine
экземпляров на один клиентский пакет.
- Явное освобождение
REngine
экземпляров
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
становится недействительным.