410013796724260
• Webmoney
R335386147728
Z369087728698
Механизм publish/subscribe в OSGiПри разработке бандлов для OSGi-приложений очень важное значение приобретает реализация механизма publish/subscribe (публикация и подписка). Ведь согласно спецификации OSGi бандл может ничего не знать о других модулях программы. Кроме этого, «условно-зависимые» бандлы (если можно так выразиться) могут разрабатываться и совершенствоваться разными программистами и функционал приложения может расширяться за счет установки дополнительных бандлов. К примеру, как быть, если один из бандлов определяет язык локализации интерфейса приложения, а ряд других бандлов отображают графический интерфейс согласно выбранной Locale? Аналогичная ситуация может возникнуть и с текущей валютой, значение которой может влиять на представление определенной информации в разных формах и отчетах (бандлах). Описание бандла (bundle) согласно спецификации OSGi и его отличие от обычного jar-файла подробно описано здесь. Механизм публикации и подписки как нельзя лучше позволяет решить описанные выше проблемы. Так бандл, управляющий определенными свойствами приложения, рассылает (публикует) сообщения при изменении этих свойств. Остальные бандлы, использующие данные свойства приложения, подписываются на рассылку этих сообщений. Такой подход прозволяет существенно облегчить труд программистов (не надо придумывать API), поскольку для разработки «условно-зависимых» бандлов, использующих механизм publish/subscribe необходимо только определить текст отправляемого сообщения. Генерация событий и формат сообщенияСледует несколько слов сказать о генерации событий и формате рассылаемых сообщений. Для генерации событий фреймворк использует OSGi-сервис EventAdmin, в котором определены два метода:
Оба метода в качестве параметра получают событие Event, которое включает текстовый топик события (EVENT_TOPIC) и свойства, описывающие конкретное событие (тип Dictionary). Топик события является фильтром для диспетчера событий, который находит обработчик для конкретного события. Формат топика должна удовлетворять доменной модели с использованием в качестве разделителя символа обратного слеша "/". Например, топик события "service/event/Currency". Обработчики могут подписываться сразу на группу событий, используя в качестве последнего домена символ "*". Так топик "org/osgi/framework/BundleEvent/*" позволяет подписаться на все события, связанные с изменением состояний различных бандлов. Свойства Event содержат информацию, описывающую событие. Поскольку OSGi не поддерживает иерархию классов над Event, то предполагается сериализация конкретного события в словарь свойств. Следует быть внимательным при использовании в качестве значений данных, отличающихся от примитивов и строк, поскольку при запуске бандлов на разных машинах могут возникнуть проблемы, связанные с сериализацией и десериализацией данных. Пример использования publish/subscribe в OSGi приложенииРассмотрим пример взаимодействия двух бандлов посредством публикации и подписки. Один bundle (bundle-exchange) подпишем на событие изменения валюты 'service/event/Currency' и дополнительно на изменение состояний бандлов 'org/osgi/framework/BundleEvent/*'. Таким образом, bundle-exchange будет контролировать как возникновение всех событий, связанных с изменением состояний бандлов, так и событий, связанных с изменением валюты. Второй бандл (bundle-publisher) будет отправлять с определенной периодичностью события 'service/event/Currency'. Дополнительно, в качестве «дирижера» используем приложение framework-pubsub, которое инсталлирует и стартует фреймворк и бандлы. Для реализации тестового примера создаем maven-проекты. Дополнительно используем бандл org.apache.felix.eventadmin-1.4.8.jar, для отправки сообщений. В качестве фреймворка в приложении framework-pubsub используем Felix. Описание проекта bundle-exchangeСтруктура проекта bundle-exchange, представленная на следующем скриншоте, включает два класса : активатор ExchangeActivator и обработчик события ExchangeSubscriber. Листинг обработчика событий ExchangeSubscriber.javaКласс ExchangeSubscriber выводит в консоль информацию о событии. package com.osgi.bundle; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; public class ExchangeSubscriber implements EventHandler { @Override public void handleEvent(Event event) { System.out.println("\t! ExchangeSubscriber : " + "received event on topic = " + event.getTopic()); for (String propertyName : event.getPropertyNames()) System.out.println("\t!\t" + propertyName + " = " + event.getProperty(propertyName)); System.out.println("\t------------------------------------"); } } Листинг активатора сервиса ExchangeActivator.javaАктиватор бандла ExchangeActivator реализует методы start и stop интерфейса BundleActivator. В методе start активатор получает в качестве параметра контекст фреймворка BundleContext, в котором подписывается на два события вызовом метода контекста registerService. В качестве параметров в метод registerService передаются обработчик событий ExchangeSubscriber и свойства, включающие EVENT_TOPIC события. В методе stop бандл освобождает ресурсы и отменяет регистрацию сервисов вызовами метода unregister класса ServiceRegistration. package com.osgi.bundle; import java.util.Dictionary; import java.util.Hashtable; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleActivator; import org.osgi.service.event.EventHandler; import org.osgi.service.event.EventConstants; import org.osgi.framework.ServiceRegistration; public class ExchangeActivator implements BundleActivator { private ServiceRegistration<?> service_currency; private ServiceRegistration<?> service_bundle ; //--------------------------------------------------------------- @Override public void start(BundleContext context) throws Exception { System.out.println(" start : bundle-exchange"); ExchangeSubscriber monitor = new ExchangeSubscriber(); Dictionary<String, Object> dict1; Dictionary<String, Object> dict2; String EVENT1 = "org/osgi/framework/BundleEvent/*"; String EVENT2 = "service/event/Currency"; // Подключение слушателя dict1 = new Hashtable<String, Object>(); dict1.put(EventConstants.EVENT_TOPIC, EVENT1); service_bundle = context.registerService( EventHandler.class.getName(), monitor, dict1); if (service_bundle != null) System.out.println("\nExchangeActivator : Service " + "'org/osgi/framework/BundleEvent/*' " + "is registered\n"); else System.out.println("ExchangeActivator : Service "'org/osgi/framework/BundleEvent/*' "is not registered"); // Подключение слушателя dict2 = new Hashtable<tring, Object>(); dict2.put(EventConstants.EVENT_TOPIC, EVENT2); service_currency = context.registerService( EventHandler.class.getName(), monitor, dict2); if (service_currency != null) System.out.println("\nExchangeActivator : Service " + "'service/event/Currency' " + "is registered\n"); else System.out.println("ExchangeActivator : Service " + "'service/event/Currency' " + "is not registered"); } //--------------------------------------------------------------- @Override public void stop(BundleContext context) throws Exception { if (service_currency != null) { service_currency.unregister(); service_currency = null; } if (service_bundle != null) { service_bundle.unregister(); service_bundle = null; } System.out.println("stop : bundle-exchange"); } } Описание сборки pom.xmlДля сборки бандла bundle-exchange используется pom.xml следующего содержания : <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.osgi.bundle</groupId> <artifactId>bundle-exchange</artifactId> <packaging>bundle</packaging> <version>1.0.0</version> <name>Bundle exchange</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding> UTF-8 </project.build.sourceEncoding> <maven.test.skip>true</maven.test.skip> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.apache.felix.framework</artifactId> <version>5.6.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.apache.felix.eventadmin</artifactId> <version>1.2.2</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> </configuration> </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>2.3.7</version> <extensions>true</extensions> <configuration> <instructions> <Bundle-SymbolicName> ${project.groupId}.${project.artifactId} </Bundle-SymbolicName> <Bundle-Name>${project.name}</Bundle-Name> <Bundle-Version> ${project.version} </Bundle-Version> <Bundle-Activator> ${project.groupId}.ExchangeActivator </Bundle-Activator> <Import-Package> org.osgi.framework.*, org.osgi.service.event.*; </Import-Package> </instructions> </configuration> </plugin> </plugins> </build> </project> В файле описания сборки pom.xml определяются зависимости фреймворка (секция <dependencies>) и параметры bundle для формирования манифеста MANIFEST.MF. Следует обратить внимание, что в теге <scope> зависимостей указано значение provided, чтобы они не были включены в бандл. Бандл должен получить классы/объекты данных зависимостей от фреймворка (см. тег Import-Package). В результате сборки в поддиректории проекта target будет создан bundle в виде файла bundle-exchange-1.0.0.jar с манифестом следующего содержания : Manifest-Version: 1.0 Bnd-LastModified: 1500971779957 Build-Jdk: 1.8.0_141 Built-By: EugeneMK Bundle-Activator: com.osgi.bundle.ExchangeActivator Bundle-ManifestVersion: 2 Bundle-Name: Bundle exchange Bundle-SymbolicName: com.osgi.bundle.bundle-exchange Bundle-Version: 1.0.0 Created-By: Apache Maven Bundle Plugin Export-Package: com.osgi.bundle;uses:="org.osgi.service.event,org.osgi. framework";version="1.0.0" Import-Package: org.osgi.framework;version="[1.8,2)",org.osgi.service. event;version="[1.2,2)" Tool: Bnd-1.50.0 Описание проекта bundle-publisherСтруктура проекта bundle-publisher, представленная на следующем скриншоте, включает активатор бандла PublisherActivator и «издателя» сообщений EventPublisher. Листинг EventPublisher.javaКласс EventPublisher отправляет сообщения. Конструктор класса получает в качестве параметра объект EventAdmin контекста фреймворка. При вызове метода отправки события sendCurrencyEvent формируется набор свойств dict и создается событие EVENT_TOPIC. Для отправки используется метод postEvent. Вы можете проверить метод sendEvent. package com.osgi.bundle; import java.util.Dictionary; import java.util.Hashtable; import org.osgi.service.event.Event; import org.osgi.service.event.EventAdmin; public class EventPublisher { private final EventAdmin admin; private final String EVENT_TOPIC = "service/event/Currency"; private final String TEMPLATE = "bundle-publisher : \n" + " send event '%s'," + " currency = %s"; //--------------------------------------------------------------- public EventPublisher(EventAdmin admin) { this.admin = admin; } //--------------------------------------------------------------- public void sendCurrencyEvent(String curr) { Dictionary<String, Object> dict; dict = new Hashtable<String,Object>(); dict.put("currency" , currency); Event event = new Event(EVENT_TOPIC, dict); System.out.println(String.format(TEMPLATE, EVENT_TOPIC,curr)); admin.postEvent(event); // admin.sendEvent(event); } } Активатор PublisherActivator.javaАктиватор бандла PublisherActivator в методе start создает «издателя» событий EventPublisher. Для создания издателя в методе createPublisher определяется ссылка ServiceReference на объект EventAdmin контекста фреймворка. При ненулевой ссылке ref извлекается объект EventAdmin из контекста фреймворка (getService), и только после этого создается объект EventPublisher. Далее активатор формирует поток, который с интервалом в 1 сек. отправляет три сообщения и завершает работу. package com.osgi.bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleActivator; import org.osgi.framework.ServiceReference; import org.osgi.service.event.EventAdmin; public class PublisherActivator implements BundleActivator { private EventPublisher eventPublisher; private final String[] curencies = {"rub", "usd", "eur"}; private int idx = 0; //--------------------------------------------------------------- @Override public void start(BundleContext context) throws Exception { System.out.println(" START : bundle-publisher"); eventPublisher = createPublisher(context); if (eventPublisher != null) { new Thread(new Runnable() { @Override public void run() { while (true) { try { String curr = curencies[idx++]; eventPublisher.sendCurrencyEvent(curr); if (idx > 2) break; Thread.sleep(1000); } catch (InterruptedException ex) {} } } }).start(); } } //--------------------------------------------------------------- @Override public void stop(BundleContext context) throws Exception { System.out.println("stop : bundle-publisher"); } //--------------------------------------------------------------- @SuppressWarnings("unchecked") private EventPublisher createPublisher(BundleContext context) { EventPublisher publisher = null; ServiceReference<EventAdmin> ref; ref = (ServiceReference<EventAdmin>) context .getServiceReference(EventAdmin.class.getName()); if (ref != null) { EventAdmin eventAdmin; eventAdmin = (EventAdmin) context.getService(ref); if (eventAdmin != null) publisher = new EventPublisher(eventAdmin); else System.out.println(" ERROR : eventAdmin is null"); } return publisher; } } Описание сборки pom.xmlДля сборки проекта bundle-publisher используется pom.xml следующего содержания : <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.osgi.bundle</groupId> <artifactId>bundle-publisher</artifactId> <packaging>bundle</packaging> <version>1.0.0</version> <name>Bundle publisher</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding> UTF-8 </project.build.sourceEncoding> <maven.test.skip>true</maven.test.skip> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.apache.felix.framework</artifactId> <version>5.6.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.apache.felix.eventadmin</artifactId> <version>1.2.2</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> </configuration> </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>2.3.7</version> <extensions>true</extensions> <configuration> <instructions> <Bundle-SymbolicName> ${project.groupId}.${project.artifactId} </Bundle-SymbolicName> <Bundle-Name>${project.name}</Bundle-Name> <Bundle-Version> ${project.version} </Bundle-Version> <Bundle-Activator> ${project.groupId}.PublisherActivator </Bundle-Activator> <Import-Package> org.osgi.framework.*, org.osgi.service.event.*; </Import-Package> </instructions> </configuration> </plugin> </plugins> </build> </project> Файл описания сборки pom.xml бандла bundle-publisher практически не отличается от pom.xml бандла bundle-exchange. Изменения касаются только наименования артефакта, наименования бандла и активатора. Здесь также в теге <scope> зависимостей указано значение provided, чтобы они не были включены в бандл. Бандл должен получить объект EventAdmin от фреймворка (см. тег Import-Package). В результате сборки в поддиректории проекта target будет создан bundle в виде файла bundle-publisher-1.0.0.jar с манифестом следующего содержания : Manifest-Version: 1.0 Bnd-LastModified: 1500974333681 Build-Jdk: 1.8.0_141 Built-By: EugeneMK Bundle-Activator: com.osgi.bundle.PublisherActivator Bundle-ManifestVersion: 2 Bundle-Name: Bundle publisher Bundle-SymbolicName: com.osgi.bundle.bundle-publisher Bundle-Version: 1.0.0 Created-By: Apache Maven Bundle Plugin Export-Package: com.osgi.bundle;uses:="org.osgi.service.event,org.osgi. framework";version="1.0.0" Import-Package: org.osgi.framework;version="[1.8,2)",org.osgi.service. event;version="[1.2,2)" Tool: Bnd-1.50.0 Описание проекта framework-pubsubСтруктура проекта framework-pubsub, представленная на следующем скриншоте, включает основной класс тестирования механизма publish/subscribe FrameworkService и набор бандлов в поддиректории bundles. Командный файл run.bat позволяет запустить готовый к тестированию пример без инсталляции проекта в Eclipse. При описании OSGi приложения с использованием фреймворка Felix представлен механизм инсталляции фреймворка и перевода его в различные состояния, а также описан процесс инсталляции бандлов. Поэтому в этой статье остановимся только на тестировании механизма publish/subscribe, т.е. на последовательности инсталляции и запуска бандлов. Листинг FrameworkServiceВ листинге класса FrameworkService на странице представлен только конструктор класса. Вспомогательные методы createFramework, installBundles, startBundles и printBundleParams с небольшими отличиями приведены на странице описания OSGi приложения. При желании Вы можете скачать исходные коды примера. private Framework framework = null; private String cache = "bundles-cache"; private String[] files = { "bundles/org.apache.felix.eventadmin-1.4.8.jar", "bundles/bundle-exchange-1.0.0.jar", "bundles/bundle-publisher-1.0.0.jar" }; private String BUNDLE_PUBLISHER = "com.osgi.bundle.bundle-publisher"; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public FrameworkService() { createFramework(); if (framework == null) { System.out.println ("framework is not created"); return; } try { try { installBundles(); startBundles (); //------------------------ // создание объекта чтения из стандартного потока ввода Scanner in = new Scanner(System.in); // чтение строки из консоли System.out.print ("\n\nEnter pub : " ); String cmd = in.nextLine(); while (!cmd.equalsIgnoreCase("pub")) { cmd = in.nextLine(); } //------------------------ for (int i = 0; i < framework.getBundleContext() .getBundles().length; i++) { Bundle bundle = framework.getBundleContext() .getBundles()[i]; if (bundle.getSymbolicName() .equalsIgnoreCase(BUNDLE_PUBLISHER)) { try { bundle.start(); printBundleParams(bundle, "Bundle", false); } catch (BundleException e) { } } } //------------------------ System.out.print ("\n\nEnter exit : " ); // чтение строки из консоли while (!cmd.equalsIgnoreCase("exit")) cmd = in.nextLine(); in.close(); stopFramework(); } catch (Exception e) { System.err.println("Exception : " + e.getMessage()); } } finally { if (framework != null) { try { framework.stop(); framework.waitForStop(2000); } catch (BundleException e) { } catch (InterruptedException e) {} } } } При тестировании механизма publish/subscribe приложение проходит три этапа:
Примечание : Результаты тестированияРезультаты работы примера выводятся в консоль. Старт фреймворка и инсталляция бандловНа первом этапе приложение создает, инсталлирует и стартует фреймворк Felix. Если фреймворк стартовал, то приложение инсталлирует все бандлы. Информация о фреймворке и бандлах выводится в консоль. После инсталляции бандлов приложение стартует их за исключением bundle-publisher и переходит в режим ожидания ввода пользователем "pub". Бандл bundle-exchange при старте сразу же подписывается на определенные события и успевает обработать сообщение об изменении состояния "самого себя". Т.е. задержка обработки изменений состояний во фреймворке превышает время регистрации обработчика события в бандле. Framework is created Version = 5.6.2 SymbolicName = org.apache.felix.framework Location = System Bundle BundleId = 0 Framework state : INSTALLED Framework state : STARTING Framework state : ACTIVE INSTALL BUNDLES ... Bundle <org.apache.felix.eventadmin-1.4.8.jar> Version = 1.4.8 SymbolicName = org.apache.felix.eventadmin Location = file:/D:/framework-pubsub/bundles/\ org.apache.felix.eventadmin-1.4.8.jar BundleId = 1 Bundle state : INSTALLED Bundle <bundle-exchange-1.0.0.jar> Version = 1.0.0 SymbolicName = com.osgi.bundle.bundle-exchange Location = file:/D:/framework-pubsub/bundles/\ bundle-exchange-1.0.0.jar BundleId = 2 Bundle state : INSTALLED Bundle <bundle-publisher-1.0.0.jar> Version = 1.0.0 SymbolicName = com.osgi.bundle.bundle-publisher Location = file:/D:/framework-pubsub/bundles/\ bundle-publisher-1.0.0.jar BundleId = 3 Bundle state : INSTALLED START BUNDLES Version = 1.4.8 SymbolicName = org.apache.felix.eventadmin Location = file:/D:/framework-pubsub/bundles/\ org.apache.felix.eventadmin-1.4.8.jar BundleId = 1 Bundle state : ACTIVE start : bundle-exchange ExchangeActivator : \ Service 'org/osgi/framework/BundleEvent/*' is registered ExchangeActivator : \ Service 'service/event/Currency' is registered Version = 1.0.0 SymbolicName = com.osgi.bundle.bundle-exchange Location = file:/D:/framework-pubsub/bundles/\ bundle-exchange-1.0.0.jar BundleId = 2 Bundle state : ACTIVE ----------------------------------------------------------------- ! ExchangeSubscriber : received event on topic = \ ! org/osgi/framework/BundleEvent/STARTED ! bundle.symbolicName = com.osgi.bundle.bundle-exchange ! bundle.id = 2 ! event = org.osgi.framework.BundleEvent[source=\ ! com.osgi.bundle.bundle-exchange [2]] ! bundle = com.osgi.bundle.bundle-exchange [2] ! event.topics = org/osgi/framework/BundleEvent/STARTED ----------------------------------------------------------------- Enter pub : Старт бандла publish-subcribeПосле ввода "pub" (сокращение от publisher), приложение стартует bundle-publisher, которое начинает отправлять сообщения. Бандл bundle-exchange обрабатывает сообщения 'service/event/Currency' и 'org/osgi/framework/BundleEvent/*'. Обратите внимание, что сначала bundle-exchange успевает получить сообщение 'service/event/Currency', после которого два сообщения об изменении состояния bundle-publisher, хотя теоретически должно было быть наоборот. Задержки связаны с дополнительной обработкой событий в фреймворке и определением подписавшегося на эти события обработчиков. Enter pub : pub START : bundle-publisher Bundle state : ACTIVE bundle-publisher : send event 'service/event/Currency', currency = rub ----------------------------------------------------------------- ! ExchangeSubscriber : received event on topic = \ ! service/event/Currency ! currency = rub ! event.topics = service/event/Currency ----------------------------------------------------------------- ! ExchangeSubscriber : received event on topic = \ ! org/osgi/framework/BundleEvent/RESOLVED ! bundle.symbolicName = com.osgi.bundle.bundle-publisher ! bundle.id = 3 ! event = org.osgi.framework.BundleEvent[source=\ ! com.osgi.bundle.bundle-publisher [3]] ! bundle = com.osgi.bundle.bundle-publisher [3] ! event.topics = org/osgi/framework/BundleEvent/RESOLVED ----------------------------------------------------------------- ! ExchangeSubscriber : received event on topic = \ ! org/osgi/framework/BundleEvent/STARTED ! bundle.symbolicName = com.osgi.bundle.bundle-publisher ! bundle.id = 3 ! event = org.osgi.framework.BundleEvent[source=\ ! com.osgi.bundle.bundle-publisher [3]] ! bundle = com.osgi.bundle.bundle-publisher [3] ! event.topics = org/osgi/framework/BundleEvent/STARTED ----------------------------------------------------------------- bundle-publisher : send event 'service/event/Currency', currency = usd ----------------------------------------------------------------- ! ExchangeSubscriber : received event on topic = \ ! service/event/Currency ! currency = usd ! event.topics = service/event/Currency ----------------------------------------------------------------- bundle-publisher : send event 'service/event/Currency', currency = eur ----------------------------------------------------------------- ! ExchangeSubscriber : received event on topic = \ ! service/event/Currency ! currency = eur ! event.topics = service/event/Currency ----------------------------------------------------------------- Останов бандлов и завершение работыПри остановке приложения фреймворк останавливает бандлы, после чего завершает работу сам. Здесь, следует отметить, что bundle-exchange успевает обработать сообщение об остановке bundle-publisher, но после этого завершает работу сам, и фреймворк выводит предупреждающее сообщение, что обработка событий EventAdmin прервана и не может быть должным образом обработана. Т.е. необходимо было во время завершить работу сервиса, связанную с контролем состояний бандлов. Enter exit : exit stop : bundle-publisher ----------------------------------------------------------------- ! ExchangeSubscriber : received event on topic = \ ! org/osgi/framework/BundleEvent/STOPPED ! bundle.symbolicName = com.osgi.bundle.bundle-publisher ! bundle.id = 3 ! event = org.osgi.framework.BundleEvent[source=\ ! com.osgi.bundle.bundle-publisher [3]] ! bundle = com.osgi.bundle.bundle-publisher [3] ! event.topics = org/osgi/framework/BundleEvent/STOPPED ----------------------------------------------------------------- WARNING: EventAdmin: Event Task Processing Interrupted. \ Events may not be recieved in proper order. stop : bundle-exchange stop : framework Скачать примерИсходный код рассмотренного примера использования механизма publish/subscribe можно скачать здесь (1.16 Мб). Пример создания фреймворка Felix, перевода его в различные состояния и инсталляции бандлов в OSGi контейнер представлен здесь. Примеры реализация механизма publish/subscribe (публикация и подписка) представлены в разделе описания многомодульного OSGi-приложения на платформе JaBricks. |