Java/JPackagePolicyTranslation

Материал из ALT Linux Wiki
Перейти к: навигация, поиск

Содержание

JPackage JavaTM infrastructure design and packaging policy[править]

Nicolas Mailhot
JPackage Project
Ville Skyttä
JPackage Project

$Id: jpackage-1.5-policy.xhtml,v 1.2 2005/09/17 07:06:26 david Exp $

Резюме[править]

Этот документ содержит политику упаковки в соответствии с JPackage cross-distribution RPM Java? packaging project.

Почему?[править]

Нормальная упаковка Java всегда являлась сложной задачей. Нехватка стандартов относительно расположения файлов в системе, в купе с общими условиями лицензирования, которые позволяли лишь свободное распространение ключевых компонентов только как часть единого целого, привели к систематическому выпуску самодостаточных приложений со встроенными копиями внешних компонентов.

Как следствие, приложения были проверены только с версиями компонентов, с которыми они были связаны. Вся Java-система страдает бесконечным дублированием одних и тех же модулей, объединение повторяющихся частей может быть кошмаром, так как они обязаны зависеть от тех же самых компонентов -- только с различными и изощренно несовместимыми версиями[1]. Любое обновление по безопасности или по совместимости должно быть выполнено для всех этих дублирующихся компонентов.

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

Это не удивительно, что сложные Java системы имеют тенденцию костенеть очень быстро. И приводить к быстрому росту стоимости обслуживания, что в свою очередь приводит к падению интереса к поддержанию таких систем в рабочем состоянии. И в конечном итоге люди бросают этим заниматься.

Данная ситуация не совместима с типичной быстро развивающейся Linux-системой. Чтобы достигнуть своей цели, создания дружественных для пользователей и администраторов методов rpm упаковки Java приложений, JPackage Project должен развить свою системную инфраструктуру и строгие правила упаковки.

Глава 1. Общие правила[править]

Будь модульным[править]

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

Be vendor and implementation agnostic[править]

Пользователь должен иметь возможность выбора между различными реализациями одного и того же компонента, в особенности когда их лицензионные условия не эквивалентны или когда их уровень законченности отличается. Необходимо учесть возможность параллельной установки таких компонентов, с возможностью самостояетльного выбора пользователем между ними или лучшего из них системой[2]

Be distribution agnostic[править]

Пакеты должны работать на большинстве основных rpm-based дистрибутивах. Это означает следование стандартам, таких как Linux Standard Base, Filesystem Hierarchy Standard или freedesktop.org спецификациям

Прежде всего запрещено использование дистрибутивно-специфичных особенностей[3]

Отметим, что это - прагматическое чтение стандартов. Средства обслуживания не определены, но в основном находятся в состоянии готовности для использования в проекте[4], дистрибутивно-специфичные адаптации допускаются при условии их не вмешательства в общее использование.

Глава 2. Назначение имен[править]

Имя пакета[править]

Пакеты должны быть названы общим именем их оригинального проекта в нижнем регистре. Когда пакет предоставляет расширение, которое было в какой-то момент заложено в Java стандарте, -ext (как external) суффикс должен быть добавлен, для различия между именем пакета и именем расширения. И JVM, которое включает данное расширение, и автономный пакет расширения, должны иметь оригинальное название как virtual Provides.

JVM должны носить имя -- java-standard_version-vendor. Оригинальное название с сайта не должно использоваться в связи с широкой практикой разброса в именовании от вендора к вендроу и от версии к версии.

Название Jar-файлов[править]

  • Если пакет предоставляет только один jar, он должен иметь тоже название что и пакет, с добавлением версии продукта.
jaf-1.0.2.jar
  • Безверсионная символьная ссылка, смотрящая на оригинальный файл тоже должна быть предоставлена (провайдена)
jaf-1.0.2.jar
jaf.jar -> jaf-1.0.2.jar
  • Если название проекта и часто используемое jar-имя отличаются, символьная ссылка на принятое имя должна так же быть предоставлена (провайдиться).
jaf-1.0.2.jar
jaf.jar ->  jaf-1.0.2.jar
activation.jar -> jaf-1.0.2.jar
  • Если пакет состоит из нескольких jar'ов, их обычные названия также будут использоваться.
ant-1.5.3.jar
ant.jar -> ant-1.5.3.jar
ant-optional-1.5.3.jar
ant-optional.jar -> ant-optional-1.5.3.jar

  • Если число jar'ов превышает два, или если они были предоставлены в виде монолитного jar'а, файлы должны быть помещены в поддиректорию с названием пакета (так же как и для одиночного jar'а).
javamail
javamail/imap-1.3.jar
javamail/imap.jar -> imap-1.3.jar
javamail/mailapi-1.3.jar
javamail/mailapi.jar -> mailapi-1.3.jar
javamail/pop3-1.3.jar
javamail/pop3.jar -> pop3-1.3.jar
javamail/smtp-1.3.jar
javamail/smtp.jar -> smtp-1.3.jar
  • Если проект предлагает выбор метода упаковки, между одним монолитным jar'ом или разбиением на несколько более мелких, упаковка с разбиением будет предпочтительнее.

Глава 3. Структура директорий[править]

Основная структура директорий, предоставляемая пакетом jpackage-utils состоит из:

%{_javadir}[править]

/usr/share/java[править]

RPM макрос %{_javadir} задает главный jar-репозиторий. Исторически это была единственная директория, используемая 1.0 JPakage, прежде чем упаковочные ограничения привели к более сложной системе. Он обычно раскрывается в /usr/share/java.

Все jar-файлы и директории с jar-файлами, которые не зависят от конретной версии Java-стандарта или JNI должны быть установлены в %{_javadir}.

/usr/share/java-ext[править]

От %{_javadir} мы получаем %{_javadir}-ext. Все jar-файлы и директории jar-файлов, которые зависят от конкретной версии Java-стандарта, но не от JNI, должны быть установлены в %{_javadir}-ext.

/usr/share/java-x.y.z[править]

Директории %{_javadir}-x.y.z содержат символьные ссылки на файлы или директории для всех элементов %{_javadir}-ext, которые действительны для x.y.z версии Java-стандарта. С тех пор как реализация обычно действительна для ряда повторений Java-стандартов, файл или директория в %{_javadir}-ext будет содержать несколько символьных ссылок ссылающихся на нее. Так же следует отметить безверсионные символьные ссылки: для двух jar'ов названных foo13.jar и foo14.jar, foo.jar символьная ссылка будет указывать на foo13.jar в %{_javadir}-1.3.0 и %{_javadir}-1.3.1, и foo14.jar в %{_javadir}-1.4.0, %{_javadir}-1.4.1 и %{_javadir}-1.4.2.

К сожалению, Java-стандарт как известно меняется довольно сильно между младшими версиями, поэтому мы должны учитывать полную версию и различия между %{_javadir}-1.4.0 и %{_javadir}-1.4.1.

Версионные особенности Java-стандарт при использовании в репозитории

/usr/share/java-ext/jsse
/usr/share/java-ext/jsse/jcert-1.0.3.01.jar
/usr/share/java-ext/jsse/jcert.jar -> jcert-1.0.3.01.jar
/usr/share/java-ext/jsse/jnet-1.0.3.01.jar
/usr/share/java-ext/jsse/jnet.jar -> jnet-1.0.3.01.jar
/usr/share/java-ext/jsse/jsse-1.0.3.01.jar
/usr/share/java-ext/jsse/jsse.jar -> jsse-1.0.3.01.jar
/usr/share/java-1.3.0/jsse  -> /usr/share/java-ext/jsse

/usr/share/java-1.3.1/jsse -> /usr/share/java-ext/jsse

/usr/share/java-utils[править]

Используется для множества java-связанных скриптов и функций, включая главную библиотеку shell-функций java-functions.

%{_jnidir}: /usr/lib/java...[править]

RPM макрос %{_jnidir} определяет главный JNI jar-репозиторий. Так же как и %{_javadir} разветвляется на ветки -ext и -x.y.z . Придерживается тех же правил что и %{_javadir}-ответвление, исключая, то что он содержит jar'ы, которые используют JNI.

%{_jnidir} обычно указывает на /usr/lib/java.


%{_jvmdir}[править]

%{_libdir}/jvm: /usr/lib/jvm[править]

RPM макрос %{_jvmdir} определяет корневую директорию, в которую устанавливаются различные JVM-системы. Обычно это /usr/lib/jvm.

%{_libdir}/jvm-exports: /usr/lib/jvm-exports[править]

От %{_jvmdir} мы переходим к %{_jvmdir}-exports. Каждая поддиректория %{_jvmdir} должна иметь соответствующую в %{_jvmdir}-exports. Они используются для регистрации Java-расширений связанных с SDK или RE символьными ссылками, указывающими внутрь JMV структуры в %{_jvmdir}.

Символьные ссылки должны указывать на фактический JVM jar-файл, предоставляющий расширение (хотя это не жесткое требование для работы системы), должны присутствовать версионные и не версионные варианты и следовать общим правилам назначения имен.

%{_libdir}/jvm-private: /usr/lib/jvm-private[править]

%{_jvmdir}-private директория содержит "внутренние" JVM-файлы, но по каким-то причинам расположенные не в стандартной JVM-директории. Скрипты не должны ссылаться на эти файлы. Внутри данной директории расположены версионные директории в соответствии с их назначением.

Как пример "внутренних" файлов можно рассмотреть файлы политики JCE (Java Cryptography Extension), те что идут вместе с различными 1.4.x JVM'ами ограничены в функциональности и производители поставляют неограниченные по функциональности файлы политик отдельно. Зачастую эти файлы -- часть какой-то версии Java-стандарта конкретного вендора (типа java-1.4.2-sun).

JCE файлы политик для Sun's J2SE 1.4.2:

/usr/lib/jvm-private/java-1.4.2-sun
/usr/lib/jvm-private/java-1.4.2-sun/jce
/usr/lib/jvm-private/java-1.4.2-sun/jce/vanilla
/usr/lib/jvm-private/java-1.4.2-sun/jce/vanilla/US_export_policy.jar
/usr/lib/jvm-private/java-1.4.2-sun/jce/vanilla/local_policy.jar
/usr/lib/jvm-private/java-1.4.2-sun/jce/unlimited
/usr/lib/jvm-private/java-1.4.2-sun/jce/unlimited/US_export_policy.jar
/usr/lib/jvm-private/java-1.4.2-sun/jce/unlimited/local_policy.jar

Различные версии jar'ов JCE-политик в дальнейшем управляются через систему альтернатив, использующую ссылку, которая указывает на соответствующий jar-файл в JVM jre/lib/security директории, с большим приоритетом на более функциональную версию чем та что принадлежит JVM.

%{_sysconfdir}/java: /etc/java[править]

%{_sysconfdir}/java содержит основные файлы конфигурации, принадлежащие java-подсистеме, главным образом java.conf.

%{_javadocdir}[править]

Это корень всех установленных javadoc документов. Его расположение и предполагаемое использование обсуждается в данный момент.

Директории зависимые от приложения[править]

  • Собственные директории приложения должны располагаться в системе в соответствии с правилами Filesystem Hierarchy Standard
  • Если приложению необходимо свое файловое дерево, как в других операционных системах (а FHS требует, чтобы поддиректории были установленные в разные части системы), макрос %{_datadir}/appname должен быть использован как корневая-домашняя директория с символьными ссылками, указывающими на реальное расположение поддиректорий в системе. Конечно лучше изменить приложение, чтобы оно понимало правильное разделение файлов и отменяло пляску с символьными ссылками.

FHS и централизованная домашняя директория приложения:

/usr/share/tomcat4
/usr/share/tomcat4/bin
/usr/share/tomcat4/common -> /var/lib/tomcat4/common
/usr/share/tomcat4/conf -> /etc/tomcat4
/usr/share/tomcat4/logs -> /var/log/tomcat4
/usr/share/tomcat4/server -> /var/lib/tomcat4/server
/usr/share/tomcat4/shared -> /var/lib/tomcat4/shared
/usr/share/tomcat4/temp  -> /var/cache/tomcat4/temp
/usr/share/tomcat4/webapps  ->/var/lib/tomcat4/webapps
/usr/share/tomcat4/work -> /var/cache/tomcat4/work
  • Велосипеды лучше не создавать. Если директория всегда имеет только один единственный подкаталог, избавьтесь от него[5]
  • Если приложение использует classpath-компоненты, которые не являются jar-файлами, они должны быть установлены в собственную директорию приложения

zip, war и другие файлы архивов классов[править]

Любой может столкнуться с другими типами архивов используемых в classpaths. Если прямой необходимости в использовании таких файлов нет, то следует конвертировать их в jar. Это особенно важно для zip-файлов, которые были одно время в широком использовании, но в последствии вышли из употребления.

  • Если приложение состоит из собственных jar-файлов, то это всегда будет только одного пользователя, и они могут быть установлены в собственные директории приложения.

Собственные jar-файлы[править]

Это предполагает, что стандартные правила, не могут быть использованы для построения classpath-приложения, таким образом эта часть должна быть обработана самим приложением или мантейнером пакета[6]. Тем не менее, когда приложение может и будут читать собственный jar-репозиторий, мы действительно обеспечиваем средствами для управления частями репозитория, которые используются совместно с другими приложениями.

Глава 4. Скрипты и выбор classpath при запуске[править]

Мы предполагаем что верные значения переменных окружения уже выставлены, по крайней мене $JAVA_HOME для выбора JVM в %{_jvmdir}, и в конечном счете $JAVACMD, $LD_ASSUME_KERNEL, $LANG, и $JAVA_COMPILER переменные.

FIXME: Исправить

Текущая реализация данной политики не столь хороша как хотелось бы и тащит с собой кучу наследственного мусора. Нормальная реализация будет использовать значения переменных из /.apprc, с откатом в /etc/app.conf, хранением пользовательских переменных окружения в /.java и /etc/java/java.conf. Если $JAVA_HOME после этого будет не определена, то по умолчанию будет использовано значение /usr/lib/jvm/java.

К сожалению, мы не делаем этого прямо сейчас.

Основные правила разрешения[править]

Когда мы запрашиваем foo/bar-x.y, мы ищем foo/bar-x.y.jar jar-файл, затем foo/bar-x.y jar-директорию, в следующих местах:

  • %{_jvmdir}-exports/name Отображение JVM определено как $JAVA_HOME=%{_jvmdir}/name. Это JVM-специфичный репозиторий, в который вы вносим Java-расширения, принадлежащие ему.
  • %{_jnidir}-java_version Где java_version является JVM стандартным Java уровнем согласия как видно из
[bob@sys dir]$ $JAVACMD -version
  • %{_javadir}-java_version java-version specific non-JNI jar repository.
  • %{_jnidir} Основной JNI jar-репозиторий.
  • %{_javadir} Основной jar-репозиторий.

Если мы ничего не находим, поиск повторяется для foo/bar.jar, foo/bar, foo.jar, и наконец foo каталог. Заметим, поиск выполняется для пары jar/директория, т.е. поддиректория расположенная в более конкретном репозитории будет всегда иметь превосходство перед jar с таким же именем, но расположенном в менее конкретном репозитории.

find-jar[править]

find-jar  {объект}

Команда find-jar проверяет расположение указанного объекта. Возвращает имя jar-файл или директории. Эта утилита предназначена исключительно для тестирования расположения объекта и не должна использоваться в скриптах. Данная команда является обязательной даже для определения classpath'а для единственного объекта, в связи с тем что поиск для единственного объекта может приводить к различным результатам, когда объект в итоге раскрывается в директорию.

[bob@sys dir]$ find-jar jndi
/usr/lib/jvm-exports/java-1.3.1-blackdown/jndi.jar

build-classpath[править]

build-classpath  {объект...}

Команда build-classpath находит classpath, следуя основным правилам разрешения. Аргументами команды -- является список объектов. Если объект разрешается в директорию, все jar-файлы этой директории будут включены в classpath.

Результат выполнения build-classpath:

[bob@sys dir]$ export JAVA_HOME=/usr/lib/jvm/java-1.3.1-blackdown
[bob@sys dir]$ build-classpath jsse javamail/mailapi jaxp_parser_impl
/usr/share/java-1.3.1/jsse/jcert-1.0.3.01.jar:/usr/share/java-1.3.1/jsse/jnet-1.0.3.01.jar:/usr/share/java-1.3.1/jsse/jsse-1.0.3.01.jar:/usr/share/java/javamail/mailapi.jar:/usr/share/java/jaxp_parser_impl.jar
[bob@sys dir]$ export JAVA_HOME=/usr/lib/jvm/java-1.4.1-sun
[bob@sys dir]$ build-classpath jsse javamail/mailapi jaxp_parser_impl

/usr/lib/jvm-exports/java-1.4.1-sun/jsse.jar:/usr/share/java/javamail/mailapi.jar:/usr/share/java/jaxp_parser_impl.jar

Рекомендованная практика построения classpath, состоящей из достаточной и опциональной частей[править]

Построение classpath с достаточной и опциональной частью:

CLASSPATH=$(build-classpath list_of_required_elements):$(build-classpath list_of_optional_elements 2> /dev/null)


build-jar-repository[править]

build-jar-repository  [[-s] |  [--soft] |  [--symbolic] |  [-h] |  [--hard] |  [-c] |  [--copy]] [[-p] |  [--preserve-naming]] {директория} {объект...}

Команда build-jar-repository создает структуру директорий из симлинков на jar-файлы, по следующим правилам. Принимает в качестве аргументов имя директории и список объектов. После чего попытается создать набор символьных ссылок [foo][bar]xxx.jar в указанной директории для каждого запрошенного foo/bar объекта[7]. Особая структура имен символьных ссылок делает возможным определить были ли они созданным именно этой командой, и является необходимым условием для использования rebuild-jar-repository. Утилите build-jar-repository можно указать какого типа должны быть создаваемые объекты: символьной, жесткой ссылкой или копией файла. По умолчанию -- создается символьная ссылка, другой тип должен быть использован только для сильно поврежденного ПО.

Инкрементное использование[править]

build-jar-repository' может быть свободно использован для одной и той же директории. Предыдущие симлинки не будут удалены. Удаление символьных ссылок в директории, производится только пользователем, утилита этого не делает.

Задание имен, для безопасного перемещения =[править]

Если вы хотите распространить директория с jar копиями или ссылками на них, вы можете использовать ключ --preserve-naming. При его использовании, build-jar-repository будет создавать файлы с именами наиболее близкими к оригинальным. Заметим, что это приведет к будущим проблемам при обновления этого репозитория. Не используйте данный ключ, пока вы точно не будете уверены, что вы делаете.

--preserve-naming включает в себя --copy, пока не определено обратного.

Результат выполнения build-jar-repository[править]
[bob@sys dir]$ export JAVA_HOME=/usr/lib/jvm/java-1.3.1-blackdown
[bob@sys dir]$ build-jar-repository lib jsse javamail/mailapi
[bob@sys dir]$ build-jar-repository lib jaxp_parser_impl
[bob@sys dir]$ tree lib
[nim@rousalka nim]$ tree lib
lib
|-- [javamail][mailapi].jar -> /usr/share/java/javamail/mailapi.jar
|-- [jaxp_parser_impl].jar -> /usr/share/java/jaxp_parser_impl.jar
|-- [jsse]jcert-1.0.3.01.jar -> /usr/share/java-1.3.1/jsse/jcert-1.0.3.01.jar
|-- [jsse]jcert.jar -> /usr/share/java-1.3.1/jsse/jcert.jar
|-- [jsse]jnet-1.0.3.01.jar -> /usr/share/java-1.3.1/jsse/jnet-1.0.3.01.jar
|-- [jsse]jnet.jar -> /usr/share/java-1.3.1/jsse/jnet.jar
|-- [jsse]jsse-1.0.3.01.jar -> /usr/share/java-1.3.1/jsse/jsse-1.0.3.01.jar
`-- [jsse]jsse.jar -> /usr/share/java-1.3.1/jsse/jsse.jar

rebuild-jar-repository[править]

rebuild-jar-repository  [[-s] |  [--soft] |  [--symbolic] |  [-h] |  [--hard] |  [-c] |  [--copy]] {директория}

Команда rebuild-jar-repository обновляет jar-репозиторий, созданный build-jar-repository. Аргументом команды является имя директории, и предназначена для исправления символьных ссылок после изменения $JAVA_HOME, для совместимости с новым JVM. Опции для типа создаваемых объектов такие же что и у build-jar-repository.

Смешанное использование[править]

Специфичные имена символьных ссылок, которые создаются build-jar-repository и rebuild-jar-repository позволяют смешивать автоматические ссылки, созданные в ручную и обычные файлы в директориях, обрабатываемых этими утилитами. Скрипты меняют только имена собственных ссылок

Результаты выполнения rebuild-jar-repository:

[bob@sys dir]$ export export JAVA_HOME=/usr/lib/jvm/java-1.4.1-sun
[bob@sys dir]$ rebuild-jar-repository lib
[bob@sys dir]$ tree lib
lib
|-- [javamail][mailapi].jar -> /usr/share/java/javamail/mailapi.jar
|-- [jaxp_parser_impl].jar -> /usr/share/java/jaxp_parser_impl.jar
`-- [jsse].jar -> /usr/lib/jvm-exports/java-1.4.1-sun/jsse.jar

Невозможность разрешения объекта[править]

В отличие от build-jar-repository, rebuild-jar-repository будет создавать символьные ссылки. Это сделано для предотвращения потери объектов при сломанной java-подсистеме.[8] Созданная символьная ссылка указывает в "никуда" и всегда должна быть "поломанной".

Примечания[править]

  1. Различные требования, различные ошибки
  2. Основанные на лицензионных условиях, известные завершенности, относительное отсутствие ошибок, рекламные проникновения и так далее
  3. Как Mandrake'овская gprintf функция.
  4. Для примера RPM 4 возможности, или Debian'ская система alternatives(8)...
  5. те не создавайте единственный подкаталог для библиотеки в %{_datadir}/appname, только потому что более сложные приложения делают это. Если он всегда будет один, используйте сразу %{_datadir}/appname
  6. Hardcoding classpath bits for example
  7. Единичный объект может быть разрешен в директорию с большим числом jar-файлов.
  8. Если устранить проблемы: установка нужных jar'ов или выбор более полной версии JVM, то rebuild-jar-repository отработает нормально, как-будто ничего и не случалось.