Статьи

Профили Pax Runner и распределенные OSGi

На прошлой неделе мы рассмотрели, как Pax Runner делает простую работу по запуску OSGi-фреймворка (какой бы вы ни захотели) и загрузке его с помощью набора пакетов. Мы также увидели, как легко переключаться между различными реализациями OSGi и версиями этих реализаций. И мы увидели, насколько гибким может быть Pax Runner с тем, как он предоставляет пакеты, будь то из файловой системы, из репозитория Maven или из ZIP-файла.

Статья на этой неделе продолжает обсуждение Pax Runner со сделкой два на один. Сначала рассмотрим профили Pax Runner, одну из самых удобных функций Pax Runner. Затем мы собираемся использовать профиль для настройки среды, чтобы мы могли опробовать Distributed OSGi, новую функцию OSGi 4.2.

Использование профилей Pax Runner

При разработке приложений для OSGi всегда будет несколько сторонних пакетов, от которых будут зависеть наши пакеты. Хотя добавить пакеты в схему инициализации Pax Runner довольно просто, иногда поиск пакетов, в которых мы нуждаемся, и проверка того, что мы ничего не пропустили, могут быть довольно сложной задачей. Профили предлагают способ идентифицировать коллекцию пакетов, которые мы хотели бы, чтобы Pax Runner установил и запустил для нас, без явной идентификации их один за другим.

Например, большинству каждого приложения нужна какая-то форма регистрации. Но какие пакеты нам нужно установить для поддержки регистрации в приложении OSGi? С профилем журнала Pax Runner нам не нужно беспокоиться о том, какие пакеты следует установить. Вместо этого мы просто сообщаем Pax Runner, что хотим войти, запустив его так:

sandbox% pax-run.sh --p=e --profiles=log

Здесь я дал Pax Runner две опции командной строки. Во-первых, —p = e — это просто сокращенная версия —platform = equinox, которую мы обсуждали на прошлой неделе. Второй вариант самый интересный. Он сообщает Pax Runner, что мы хотим, чтобы он использовал свой профиль «log» для установки и запуска любых пакетов, необходимых для поддержки регистрации в приложении OSGi. Какие пакеты он устанавливает? Что ж, если мы введем команду Equinox ss, мы увидим их:

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.3.R34x_v20081215-1030
1 ACTIVE org.eclipse.osgi.util_3.1.300.v20080303
2 ACTIVE org.eclipse.osgi.services_3.1.200.v20070605
3 ACTIVE org.ops4j.pax.logging.pax-logging-api_1.3.0
4 ACTIVE org.ops4j.pax.logging.pax-logging-service_1.3.0

osgi>

Пакеты 3 и 4 представляют Pax Logging , реализацию службы ведения журнала OSGi с API, который имитирует несколько популярных каркасов ведения журналов, таких как Log4J или Commons Logging. Мы поговорим о Pax Logging позже. Но пока достаточно знать, что нам не нужно искать Pax Logging, чтобы включить регистрацию в нашем приложении. Нам просто нужно было сказать Pax Runner использовать его профиль «log».

Профиль «log» — это только один из многих профилей, доступных для Pax Runner. Чтобы получить полный список доступных профилей, посетите http://paxrunner.ops4j.org/display/paxrunner/Pax+Runner+profiles+list .

Теперь давайте попробуем что-нибудь более интересное, чем просто добавление пары пакетов для поддержки ведения журнала. Выпуск OSGi R4.2 не за горами, и одна из новых функций в нем называется Distributed OSGi . В двух словах, Distributed OSGi (или D-OSGi для краткости) предлагает способ автоматической публикации служб OSGi в качестве веб-служб. Уже есть реализация D-OSGi, доступная в проекте Apache CXF .

Допустим, мы хотим использовать D-OSGi для создания веб-сервиса на основе OSGi. Чтобы использовать реализацию D-OSGi в CXF, нам понадобится несколько десятков пакетов, установленных в качестве предварительного условия. Это может быть утомительно и может привести к человеческим ошибкам (что если мы забудем пакет или случайно установим несовместимую версию?). Но с профилем Pax Runner «cxf.dosgi» нет ничего сложного в том, чтобы начать работу с D-OSGi:

sandbox% pax-run.sh --p=e --profiles=cxf.dosgi

После запуска платформы OSGi мы можем получить краткий статус (ы), чтобы увидеть, что нам дал профиль:

osgi> ss

Framework is launched.

id	State       Bundle
0	ACTIVE      org.eclipse.osgi_3.4.3.R34x_v20081215-1030
1	ACTIVE      org.eclipse.osgi.util_3.1.300.v20080303
2	ACTIVE      org.eclipse.osgi.services_3.1.200.v20070605
3	ACTIVE      org.apache.geronimo.specs.geronimo-annotation_1.0_spec_1.1.1
4	ACTIVE      org.apache.geronimo.specs.geronimo-activation_1.1_spec_1.0.2
5	ACTIVE      org.apache.geronimo.specs.geronimo-javamail_1.4_spec_1.2.0
6	ACTIVE      org.apache.geronimo.specs.geronimo-ws-metadata_2.0_spec_1.1.2
7	ACTIVE      com.springsource.org.jdom_1.0.0
8	ACTIVE      org.ops4j.pax.logging.pax-logging-api_1.3.0
9	ACTIVE      org.ops4j.pax.logging.pax-logging-service_1.3.0
10	ACTIVE      org.ops4j.pax.web.service_0.5.2
11	ACTIVE      com.springsource.org.aopalliance_1.0.0
12	ACTIVE      org.springframework.aop_2.5.6
13	ACTIVE      org.springframework.beans_2.5.6
14	ACTIVE      org.springframework.context_2.5.6
15	ACTIVE      org.springframework.context.support_2.5.6
16	ACTIVE      org.springframework.core_2.5.6
17	ACTIVE      com.springsource.org.objectweb.asm_2.2.3
18	ACTIVE      com.springsource.edu.emory.mathcs.backport_3.1.0
19	ACTIVE      com.springsource.net.sf.cglib_2.1.3
20	ACTIVE      org.springframework.osgi.extensions.annotations_1.2.0
21	ACTIVE      org.springframework.osgi.core_1.2.0
22	ACTIVE      org.springframework.osgi.extender_1.2.0
23	ACTIVE      org.springframework.osgi.io_1.2.0
24	ACTIVE      org.apache.servicemix.bundles.jaxb-impl_2.1.6.1
25	ACTIVE      org.apache.servicemix.bundles.wsdl4j_1.6.1.1
26	ACTIVE      org.apache.servicemix.bundles.xmlsec_1.3.0.1
27	ACTIVE      org.apache.servicemix.bundles.wss4j_1.5.4.1
28	ACTIVE      org.apache.servicemix.bundles.xmlschema_1.4.2.1
29	ACTIVE      org.apache.servicemix.bundles.asm_2.2.3.1
30	ACTIVE      org.apache.servicemix.bundles.xmlresolver_1.2.0.1
31	ACTIVE      org.apache.servicemix.bundles.neethi_2.0.4.1
32	ACTIVE      org.apache.servicemix.bundles.woodstox_3.2.7.1
33	ACTIVE      org.apache.servicemix.specs.saaj-api-1.3_1.1.1
34	ACTIVE      org.apache.servicemix.specs.stax-api-1.0_1.1.1
35	ACTIVE      org.apache.servicemix.specs.jaxb-api-2.1_1.1.1
36	ACTIVE      org.apache.servicemix.specs.jaxws-api-2.1_1.1.1
37	ACTIVE      org.apache.cxf.cxf-bundle-minimal_2.2.0.SNAPSHOT
38	ACTIVE      cxf-dosgi-ri-discovery-local_1.0.0.SNAPSHOT
39	INSTALLED   cxf-dosgi-ri-dsw-cxf_1.0.0.SNAPSHOT

osgi> 

Вау! Только потому, что мы указали профиль «cxf.dosgi», нам дали три десятка пакетов (в дополнение к основным пакетам Equinox)! Это было довольно легко, не так ли?

Что ж, хотя впечатляет, что мы установили чуть более трех десятков пакетов, просто запросив профиль «cxf.dosgi», есть одна небольшая проблема. Обратите внимание, что пакет 39 не был запущен. Это потому, что CXF зависит от новой функциональности ловушек, которая не является частью последней выпущенной версии Equinox. Но эти хуки являются частью последнего и лучшего снимка Equinox, и мы используем только последнюю выпущенную версию.

Это не имеет ничего общего с профилями, но дает мне возможность показать вам еще один трюк с Pax Runner. Давайте скажем «Pax Runner» перейти к передовому краю и использовать последний снимок «Равноденствия»:

sandbox% pax-run.sh --p=e --profiles=cxf.dosgi --snapshot

Опция —snapshot указывает Pax Runner использовать последнюю версию снимка целевой платформы OSGi. В этом случае, я прошу последнюю не выпущенную версию Equinox, которая является 3.5 M7, когда я пишу это.

Краткий обзор установленных пакетов (с использованием ss) показывает, что все пакеты CXF D-OSGi (и их зависимости) установлены и готовы к работе с D-OSGi.

И на этом завершается сегодняшнее удовольствие с профилями Pax Runner. Я мог бы поклониться этой статье и начать думать о том, что я собираюсь написать на следующей неделе, но … пока у нас есть поддержка D-OSGi, давайте посмотрим, что мы можем с ней сделать.

Публикация распределенных сервисов OSGi

Чтобы продемонстрировать мощь D-OSGi, мы собираемся создать два пакета. Один из них предоставит простой сервис OSGi, который мы попросим D-OSGi опубликовать как веб-сервис. Другой пакет будет содержать интерфейс для этой службы.

Хотя не обязательно, чтобы реализация службы OSGi и ее интерфейс были упакованы в отдельные пакеты, это имеет большой смысл, особенно при использовании D-OSGi. Это потому, что мы хотим распространять пакет интерфейса (отдельно от реализации) вместе с любыми клиентами, которые его используют.

Начнем с интерфейса сервиса:

package com.osgiknowhow.sandbox;

public interface PigLatinService {
String translate(String text);
}

Как вы видите, мы собираемся создать сервис, который переводит фразы в Pig Latin. Это довольно простой сервис с единственным методом, который принимает строку и возвращает переведенную строку. Не волнуйтесь, хотя … насколько я знаю, вы не можете заразиться свиным гриппом, работая с этим примером.

Если вы скачали пример кода, вы найдете интерфейсный пакет в проекте «piginterface». Вы можете построить его с помощью Maven, как это:

piginterface% mvn install

Вы, наверное, заметили, что, хотя мы собираем пакет OSGi, я не показал вам, как определить файл META-INF / MANIFEST.MF. Это потому, что я использую плагин Felix Bundle для Maven, чтобы автоматически генерировать для меня манифест. Вот что он произвел для пакета интерфейса:

Manifest-Version: 1.0
Bundle-Name: Pig Latin Service Interface
Built-By: wallsc
Build-Jdk: 1.5.0_16
Created-By: Apache Maven Bundle Plugin
Import-Package: com.osgiknowhow.sandbox
Bundle-ManifestVersion: 2
Bundle-SymbolicName: com.osgiknowhow.sandbox.pig-latin-service-interface
Tool: Bnd-0.0.255
Bnd-LastModified: 1241320637536
Export-Package: com.osgiknowhow.sandbox
Bundle-Version: 1.0.0

Опять же, просто для ясности, нам не нужно самим писать файл манифеста. Пусть Maven и плагин связки сделают всю работу.

Теперь для пакета реализации и класса реализации сервиса:

package com.osgiknowhow.sandbox.internal;

import com.osgiknowhow.sandbox.PigLatinService;

public class PigLatinServiceImpl implements PigLatinService {
private final String VOWELS = "AEIOUaeiou";

public String translate(String text) {
String[] words = text.split("\\s");
String result = "";

for(String word : words) {
result += translateWord(word) + " ";
}

return result.trim();
}

private String translateWord(String word) {
StringBuffer result = new StringBuffer();
String start = "";
for(int i=0; i<word.length(); i++) {
char c = word.charAt(i);
if(VOWELS.indexOf(c) >= 0) {
start = word.substring(i);
break;
}
result.append(c);
}

return start + "-" + result + "AY";
}
}

Помимо логики перевода, в PigLatinServiceImpl нет ничего особенного. Это просто POJO, который реализует интерфейс PigLatinService.

Теперь нам нужно опубликовать экземпляр службы PigLatinServiceImpl в реестре службы OSGi. Есть несколько способов сделать это, включая написание активатора пакета, использование декларативных сервисов OSGi или даже IPOJO. Но так как я большой поклонник Spring-DM, я собираюсь использовать это для публикации сервиса. (Кроме того, если вы не заметили, у нас уже установлен Spring-DM благодаря профилю «cxf.dosgi»).

Для этого давайте создадим определение контекста приложения Spring, которое объявляет PigLatinServiceImpl как bean-компонент Spring:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<bean id="pigLatinService"
class="com.osgiknowhow.sandbox.internal.PigLatinServiceImpl" />

</beans>

Если вы знакомы с Spring, вы поймете, что это очень простой файл конфигурации Spring, который объявляет один компонент в контексте Spring. Теперь давайте создадим файл определения контекста Spring, который объявляет этот компонент как службу OSGi:

<beans:beans xmlns="http://www.springframework.org/schema/osgi" 
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<service ref="pigLatinService"
interface="com.osgiknowhow.sandbox.PigLatinService" />

</beans:beans>

Элемент <service> является частью схемы конфигурации Spring-DM и просто говорит Spring-DM опубликовать компонент, идентифицируемый атрибутом ref, в реестр службы OSGi в интерфейсе, указанном атрибутом interface.

Обратите внимание, что рекомендуется хранить стандартные объявления bean-компонентов Spring в одном файле определения контекста Spring, а детали Spring-DM — ​​в отдельном файле. Это связано с тем, что компоненты Spring могут использоваться в контексте, отличном от OSGi (например, в интеграционных тестах), без привлечения Spring-DM или инфраструктуры OSGi. В этом случае стандартное объявление bean-компонента Spring находится в файле с именем pig-latin-context.xml, а конфигурация Spring-DM — ​​в файле с именем pig-latin-osgi.xml. Оба файла помещаются в папку пакета META-INF / spring, чтобы расширитель Spring-DM мог их найти.

На самом деле, если бы мы собирали и развертывали пакет услуг, бин был бы опубликован как сервис OSGi, но не был бы представлен как веб-сервис D-OSGi. Это потому, что мы не добавили крошечную магию D-OSGi, чтобы это произошло. Давайте добавим это сейчас:

    <service ref="pigLatinService" 
interface="com.osgiknowhow.sandbox.PigLatinService">
<service-properties>
<beans:entry key="osgi.remote.interfaces" value="*" />
</service-properties>
</service>

Установив для свойства службы osgi.remote.interfaces значение «*», мы сообщаем реализации D-OSGi (в нашем случае CXF), что мы хотим, чтобы этот сервис был представлен как веб-сервис с использованием всех интерфейсов, которые этот сервис опубликовано в (сейчас это только интерфейс PigLatinService).

Теперь мы готовы развернуть пакет, чтобы увидеть, работает ли он. Первый шаг — это построить:

pigservice% mvn install

Опять же, проект пакета услуг опирается на плагин Felix Bundle для Maven, чтобы автоматически создать манифест для пакета. Если вам интересно, вот что он придумал для пакета реализации:

Manifest-Version: 1.0
Built-By: wallsc
Created-By: Apache Maven Bundle Plugin
Import-Package: com.osgiknowhow.sandbox
Bnd-LastModified: 1241145464887
Export-Package: com.osgiknowhow.sandbox
Bundle-Version: 1.0.0
Bundle-Name: Pig Latin Service
Build-Jdk: 1.5.0_16
Private-Package: com.osgiknowhow.sandbox.internal
Bundle-ManifestVersion: 2
Bundle-SymbolicName: com.osgiknowhow.sandbox.pig-latin-service
Tool: Bnd-0.0.255

После сборки пакета давайте запустим Pax Runner. Мы должны быть уверены, что используем профиль «cxf.dosgi», как и раньше, и проинструктируем его для загрузки наших сервисов и пакетов интерфейса:

piglatin% pax-run.sh --p=e --profiles=cxf.dosgi --snapshot pigservice/target/pig-latin-service-1.0.0.jar piginterface/target/pig-latin-interface-1.0.0.jar

После его запуска вы сможете указать свой браузер по адресу http: // localhost: 9000 / com / osgiknowhow / sandbox / PigLatinService? Wsdl, чтобы увидеть, что служба публикуется. Обратите внимание, что URL-адрес веб-службы получен из экспортированного имени пакета. Но мы можем контролировать это, установив еще несколько свойств:

    <service ref="pigLatinService" 
interface="com.osgiknowhow.sandbox.PigLatinService">
<service-properties>
<beans:entry key="osgi.remote.interfaces" value="*" />
<b><beans:entry key="osgi.remote.configuration.type" value="pojo"/>
<beans:entry key="osgi.remote.configuration.pojo.address"
value="http://localhost:9000/piglatin"/></b>
</service-properties>
</service>

Сконфигурированный таким образом, новый URL-адрес службы — http: // localhost: 9000 / piglatin (это означает, что вы можете увидеть его WSDL по адресу http: // localhost: 9000 / piglatin? Wsdl).

Использование услуг с D-OSGi

Теперь, когда мы увидели, как представлять сервисы OSGi в качестве веб-сервиса с использованием D-OSGi, кажется, что наш следующий естественный шаг — написать клиент, который будет использовать наш переводящий веб-сервис Pig Latin. Чтобы проиллюстрировать D-OSGi на стороне клиента, мы начнем с создания нового проекта для клиента. В этом пакете мы создадим класс клиента:

package com.osgiknowhow.sandbox.client;

import com.osgiknowhow.sandbox.PigLatinService;

public class PigLatinClient {
public void tryIt() {
System.out.println("TRANSLATED: " +
pigLatinService.translate("Dogs hate cats"));
}

private PigLatinService pigLatinService;
public void setPigLatinService(PigLatinService pigLatinService) {
this.pigLatinService = pigLatinService;
}
}

В методе tryIt () происходит все самое интересное. Он вызывает функцию translate () PigLatinService для перевода образца набора текста. Обратите внимание, что PigLatinClient вводится (с помощью метода установки) с помощью PigLatinService. Подробности о том, где этот PigLatinService, будут опубликованы, но сначала давайте посмотрим, как мы связываем этот компонент в контексте приложения Spring.

В META-INF / spring пакета клиента я создал файл pig-latin-context.xml. Это простой файл определения контекста Spring, который связывает компонент PigLatinClient:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<bean id="pigLatinClient"
class="com.osgiknowhow.sandbox.client.PigLatinClient"
init-method="tryIt">
<property name="pigLatinService" ref="pigLatinService" />
</bean>

</beans>

PigLatinClient довольно прост. Его свойство pigLatinService связано со ссылкой на компонент, идентификатор которого равен «pigLatinService». Что делает его немного особенным, так это то, что он имеет метод init, который запускает метод tryIt () при создании компонента.

Что касается компонента «pigLatinService», он определяется в отдельном файле META-INF / spring / pig-latin-osgi.xml:

<beans:beans xmlns="http://www.springframework.org/schema/osgi" 
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<reference id="pigLatinService"
interface="com.osgiknowhow.sandbox.PigLatinService" />

</beans:beans>

Здесь я использую элемент <reference> в Spring-DM для объявления bean-компонента, идентификатор которого равен «pigLatinService», и реализацию которого можно найти в реестре службы OSGi в интерфейсе com.osgiknowhow.sandbox.PigLatinService.

Большой вопрос здесь: откуда бин pigLatinService? Spring-DM предполагает, что он будет доступен в реестре службы OSGi. Но как это туда добраться? Помните: «D» в стандартах D-OSGi для «распределенных». Это означает, что наш сервис, скорее всего, будет работать в совершенно другом режиме OSGi, чем клиент. Так как же удаленный сервис попадает в реестр клиентов OSGi?

Что ж, эта магия достигается добавлением еще одного файла в клиентский пакет: OSGI-INF / remote-service / remote-services.xml:

<service-descriptions xmlns="http://www.osgi.org/xmlns/sd/v1.0.0">
<service-description>
<provide interface="com.osgiknowhow.sandbox.PigLatinService"/>
<property name="osgi.remote.interfaces">*</property>
<property name="osgi.remote.configuration.type">pojo</property>
<property name="osgi.remote.configuration.pojo.address">http://localhost:9000/piglatin</property>
</service-description>
</service-descriptions>

Этот файл сообщает реализации D-OSGi, что этот пакет будет использовать службу, которая на самом деле является веб-службой, размещенной в другом месте. D-OSGi возьмет этот файл и удостоверится, что в реестре службы OSGi есть прокси для удаленной службы, чтобы, когда Spring-DM искал com.osgiknowhow.sandbox.PigLatinService, он мог найти его.

Хорошо, все, что осталось сделать, это собрать все и запустить сервис и клиентские пакеты, каждый в отдельной среде выполнения OSGi. Сначала соберите это:

pigclient% mvn install

Еще раз, я рассчитываю на плагин пакета Felix, чтобы сделать тяжелую работу в отношении манифеста пакета. На этот раз он сгенерировал следующий файл META-INF / MANIFEST.MF:

Manifest-Version: 1.0
Bundle-Name: Pig Latin Client
Built-By: wallsc
Build-Jdk: 1.5.0_16
Private-Package: com.osgiknowhow.sandbox.client
Created-By: Apache Maven Bundle Plugin
Import-Package: com.osgiknowhow.sandbox
Bundle-ManifestVersion: 2
Bundle-SymbolicName: com.osgiknowhow.sandbox.pig-latin-client
Tool: Bnd-0.0.255
Bnd-LastModified: 1241320097283
Bundle-Version: 1.0.0

Далее мы запустим клиентскую среду выполнения OSGi способом, аналогичным тому, как мы запускали среду выполнения службы:

piglatin% pax-run.sh --p=e --profiles=cxf.dosgi --snapshot pigservice/target/pig-latin-client-1.0.0.jar piginterface/target/pig-latin-interface-1.0.0.jar

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

В любом случае, при запуске клиентского пакета Spring-DM попытается разрешить службу из реестра службы OSGi. Благодаря файлу remote-services.xml он найдет службу, которая на самом деле является просто прокси для удаленной службы, размещенной в другой среде выполнения OSGi. При наличии ссылки на службу он вызывает метод translate () и печатает следующее:

TRANSLATED:  ogs-DAY ate-hAY ats-cAY

И это подводит нас к концу приключения на этой неделе в OSGi. Напомним, что на этой неделе мы рассмотрели две разные темы:

  • Мы увидели, как профили Pax Runner облегчают загрузку и запуск выбора пакетов, которые в совокупности предоставляют некоторые функции для среды выполнения OSGi. Pax Runner предлагает несколько профилей в своем хранилище профилей, но мы сосредоточились на профиле «cxf.dosgi», который объединяет три десятка пакетов для работы с Distributed OSGi.
  • С пакетами из профиля «cxf.dosgi» мы работали с D-OSGi. Мы увидели, что создание удаленного сервиса — это простой вопрос публикации его с дополнительным свойством или двумя. И потреблять эту услугу не намного сложнее. Ключевым моментом является то, что публикация и использование сервисов D-OSGi является декларативным действием — ни один Java-код не пострадал при создании этой статьи.

Я надеюсь, что вам нравятся мои еженедельные статьи по OSGi. У меня есть длинный список потенциальных тем для записи. На следующей неделе я вернусь к Pax Construct, рассмотрев несколько функций, которые мы не видели в прошлый раз, когда я писал об этом. Но я также открыт для предложений. Если есть какая-либо тема, связанная с OSGi, которую вы хотите, чтобы я обсудил здесь, не стесняйтесь спрашивать. Я не даю никаких обещаний, но постараюсь добавить его в свой список для будущей статьи.

С http://www.jroller.com/habuma