Как добавить пакеты импорта из определенной версии пакета в OSGi

В моем проекте есть два пакета OSGi (A и B), которые должны использовать разные версии javax.activation — для A требуется версия 1.1.0, а для B — 1.1.1.

По умолчанию в AEM 5.6.1 уже установлен пакет, который экспортирует версию 1.1.1, которую использует пакет A. Чтобы заставить его использовать 1.1.0, я использовал делегирование загрузки, чтобы получить javax.activation из JRE 7 для системного пакета, который равен 1.1.0. Я устанавливаю это с помощью файла sling.properties в AEM 5.6.1.

Если я укажу версию для javax.activation выше 1.1.1 в этом файле sling.properties, и A, и B используют системную версию (даже если версия import-packages указана в файле manifest.mf); но если я даю версию меньше 1.1.1, оба пакета используют версию, предоставленную AEM.

Как я могу настроить свои пакеты, чтобы использовать разные версии javax.activation для пакета A из пакета B?


person user2784095    schedule 11.11.2014    source источник
comment
Не могли бы вы предоставить декларацию Import-Package из своего манифеста?   -  person santiagozky    schedule 13.11.2014


Ответы (2)


Если вы хотите использовать именно версию 1.1.0 в комплекте A, вы должны указать это в файле манифеста A:

Import-Package: javax.activation;version="[1.1.0,1.1.0]"

Манифест пакета B будет таким:

Import-Package: javax.activation;version="[1.1.1,1.1.1]"
person Fordren    schedule 19.11.2014

Это может быть совершенно сложно из-за правил разрешения пакетов OSGI. Прочтите эту статью — я нашел, что это хорошее объяснение различных применимых правил. В частности, ознакомьтесь с директивой uses: http://www.christianposta.com/blog/?p=241

Жизнь будет намного проще, если у обоих будет возможность использовать одну и ту же версию (но я знаю, что это не всегда возможно).

Это из статьи выше:

Для каждого объявления пакета Import-Package должен быть соответствующий Export-Package с тем же пакетом.

Пакеты также могут прикреплять другие атрибуты к пакетам, которые он импортирует или экспортирует. Что, если мы добавим в наш пример атрибут версии:

Bundle-Name: Bundle A Import-Package: org.apache.foo;version="1.2.0"

Это означает, что пакет A зависит от пакета org.apache.foo с минимальной версией 1.2.0. Да, вы правильно прочитали. Хотя с OSGI вы можете указать диапазон версий, если вы не укажете диапазон, а вместо этого используете фиксированную версию, это приведет к значению «минимум» фиксированного значения. Если для того же пакета существует более поздняя версия, будет использоваться более поздняя версия. Таким образом, пакет A не будет правильно разрешен, если не будет соответствующего пакета B, который экспортирует требуемый пакет:

Bundle-Name: Bundle B Export-Package: org.apache.foo;version="1.2.0"

Обратите внимание, что обратное неверно... Если Bundle B экспортирует версию 1.2.0, Bundle A не требуется указывать версию 1.2.0. Он может использовать этот импорт и разрешать просто отлично:

Bundle-Name: Bundle A Import-Package: org.apache.foo

Это связано с тем, что импорт объявляет нужные версии. Экспортированная версия не указывает ничего, что должен использовать импортирующий пакет (это справедливо для любых атрибутов, а не только для версии). Import-Package точно определяет, какая версия (или атрибут) ему нужна, и должен существовать соответствующий Export-Package с тем же атрибутом.

Что произойдет, если у вас есть сценарий, в котором пакет A импортирует пакет и указывает версию, предоставляемую двумя пакетами:

Bundle-Name: Bundle A Import-Package: org.apache.foo;version="1.2.0"

Bundle-Name: Bundle B Export-Package: org.apache.foo;version="1.2.0"

Bundle-Name: Bundle C Export-Package: org.apache.foo;version="1.2.0"

Какой пакет использует Bundle A? Ответ: это зависит от того, какой пакет (B или C) был установлен первым. Пакеты, установленные первыми, используются для удовлетворения зависимости при обнаружении нескольких пакетов с одинаковой версией.

Все может стать немного сложнее при горячем развертывании пакетов после того, как некоторые из них уже были решены. Что, если сначала установить пакет B, а затем попытаться установить вместе пакет A и следующий пакет D:

Bundle-Name: Bundle D Export-Package: org.apache.foo;version="1.3.0"

Как мы видели выше, объявление версии в Bundle A (1.2.0) означает минимальную версию 1.2.0; поэтому, если бы была доступна более высокая версия, она была бы выбрана (версия 1.3.0 из Bundle D в данном случае). Однако это подводит нас к другому временному правилу для разрешения пакетов: уже разрешенные пакеты имеют более высокий приоритет, чем неразрешенные.

Причина этого в том, что структура OSGI склонна отдавать предпочтение повторному использованию данного пакета. Если проблема решена и она нужна новым пакетам, то он не будет пытаться иметь много других версий того же пакета, если в этом нет необходимости. Директива Bundle «использует»

Приведенных выше правил для разрешения пакетов по-прежнему недостаточно, и неправильный класс все еще может использоваться во время выполнения, что приводит к исключению приведения класса или аналогичному. Вы видите, чего может не хватать?

Что, если бы у нас был такой сценарий. Bundle A экспортирует пакет org.apache.foo, содержащий класс FooClass. У FooClass есть метод, который возвращает объект типа BarClass, но BarClass не определен в пространстве классов пакета, он импортируется следующим образом:

1 2 3 открытый класс FooClass { public BarClass execute(){ ... } }

Bundle-Name: Bundle A Import-Package: org.apache.bar;version="3.6.0" Export-Package: org.apache.foo;version="1.2.0"

Пока все в порядке, пока есть другой пакет, который правильно экспортирует org.apache.bar с правильной версией.

Bundle-Name: Bundle B Export-Package: org.apache.bar;version="3.6.0"

Эти две пачки будут нормально решаться. Теперь, если мы установим еще два пакета, Bundle C и Bundle D, которые будут выглядеть так:

Bundle-Name: Bundle C Import-Package: org.apache.foo;version="1.2.0", org.apache.bar;version="4.0.0"

Bundle-Name: Bundle D Export-Package: org.apache.bar;version="4.0.0"

Мы видим, что Bundle C импортирует пакет org.apache.foo из Bundle A. Bundle C может попытаться использовать FooClass из org.apache.foo, но когда он получит возвращаемое значение типа BarClass, что произойдет? Пакет A предполагает использование версии 3.6.0 BarClass, но пакет C использует версию 4.0.0. Таким образом, используемые классы не согласованы в пакетах во время выполнения (т. е. вы можете столкнуться с некоторым типом несоответствия или исключения приведения класса), но все равно все будет нормально разрешаться во время развертывания в соответствии с приведенными выше правилами. Что нам нужно, так это сообщить всем, кто импортирует org.apache.foo, что мы используем классы из определенной версии org.apache.bar, и если вы хотите использовать org.apache.foo, вы должны использовать ту же версию, которую мы импортируем. Это именно то, что делает директива uses. Давайте изменим пакет A, чтобы указать именно это:

Bundle-Name: Bundle A Import-Package: org.apache.bar;version="3.6.0" Export-Package: org.apache.foo;version="1.2.0"";uses:=org.apache.bar

Учитывая новую конфигурацию для Bundle A, пакеты не будут корректно разрешаться сверху. Пакет C не может разрешить, потому что он импортирует org.apache.foo, но ограничение «uses» для пакета A указывает, что C должен использовать ту же версию, что и A (3.6.0) для org.apache.bar, иначе пакет будет не разрешается при попытке развертывания. Решение этой проблемы — изменить версию в Bundle C для org.apache.bar на 3.6.0.

person Shawn    schedule 14.11.2014