Especificaciones de Java en Empaquetado de Fedora

Distribución de Directorio

Esta sección describe las mayoría de los directorios usados para el empaquetado de Java. Cada directorio se nombra en formato de macro RPM, el cual muestra como sería utilizado en los archivos de especificaciones RPM. El nombre simbólico es seguido por la expansión de macro usual (esto es, ubicación del directorio físico en el sistema de archivos) y una descripción breve.

Directorios usados comúnmente por los paquetes normales
%{_javadir} — /usr/share/java

Directorio que aloja todos los archivos JAR que no contienen o usan código nativo y no dependen de una versión estándar de Java concreta. Los archivos JAR se pueden situar directamente en este directorio o en uno de sus subdirectorios. Con frecuencia los paquetes crean sus propios subdirectorios allí, en este caso el nombre del subdirectorio debería coincidir con el nombre del paquete.

%{_jnidir} — /usr/lib/java

Directory where architecture-specific JAR files are installed. In particular, JAR files containing or using native code (Java Native Interface, JNI) should be installed there.

%{_javadocdir} — /usr/share/javadoc

Directorio raíz donde se instala toda la documentación de la API de Java (Javadoc). Cada paquete fuente suele crear un único subdirectorio que contiene la documentación Javadoc agregada para todos los paquetes binarios que produce.

%{_mavenpomdir} — /usr/share/maven-poms

Directorio donde se instalan los archivos del Modelo de Objeto de Proyecto (POM) utilizados por Apache Maven. Cada POM debe tener un nombre que corresponda estrictamente al archivo JAR en %{_javadir} o %{_jnidir}.

%{_ivyxmldir} — /usr/share/ivy-xmls

Directorio donde ivy.xml los archivos utilizaron por Apache Ivy está instalada. Cada XML tiene que tener nombre que estrictamente corresponde a archivo de JAR en %{_javadir} o %{_jnidir}.

Otros directorios
%{_jvmdir} — /usr/lib/jvm

Directorio raíz donde se instalan las distintas máquinas virtuales Java (JVM). Cada JVM crea un subdirectorio, posiblemente con varios nombres alternativos implementados mediante enlaces simbólicos. Los directorios que comienzan con java contienen el Kit de Desarrollo de Java (JDK), mientras que los directorios cuyos nombres comienzan con jre contienen el Entorno de Ejecución de Java (JRE).

%{_jvmsysconfdir} — /etc/jvm
%{_jvmcommonsysconfdir} — /etc/jvm-common

Directorios que contienen archivos de configuración para máquinas virtuales Java (JVM).

%{_jvmprivdir} — /usr/lib/jvm-private
%{_jvmlibdir} — /usr/lib/jvm
%{_jvmdatadir} — /usr/share/jvm
%{_jvmcommonlibdir} — /usr/lib/jvm-common
%{_jvmcommondatadir} — /usr/share/jvm-common

Los directorios que contienen archivos de implementación de Máquinas Java Virtuales (JVM). Describiéndoles en detalle es fuera de alcance para este documento. El propósito de cada directorio está comentado brevemente en el archivo macros.jpackage en /etc/rpm. Más descripción detallada puede encontrarse en la normativa de JPackage.

%{_javaconfdir} — /etc/java

El directorio que contiene archivos de configuración de Java. En particular contiene el archivo principal de la configuración de Java — java.conf.

Identificación de Archivo JAR

Las aplicaciones Java complejas normalmente constan de múltiples componentes. Cada componente puede tener múltiples implementaciones, llamadas artefactos. Los artefactos en el contexto Java normalmente son archivos JAR, pero también pueden ser archivos WAR y cualquier otra familia de archivo.

Hay múltiples formas incompatibles de identificar (denominar) artefactos Java y cada sistema de compilación a menudo fomenta el uso de un esquema de nomenclatura específico. Esto significa que las distribuciones Linux también necesitan permitir que cada artefacto sea ubicado utilizando varios identificadores diferentes, utilizando posiblemente diferentes esquemas. Por otro lado es prácticamente imposible utilizar todos los esquemas de nomenclatura, por lo que existen algunas simplificaciones.

Este capítulo describe diferentes formar de identificar y localizar artefactos en el repositorio del sistema.

Rutas relativas

Los artefactos JAR son instalados un uno de los árboles de directorio estándar. Usualmente esto es o bien %{_javadir} (/usr/share/java) o bien %{_jnidir} (/usr/lib/java).

La forma más sencilla de identificar artefactos es mediante su ruta relativa desde una de las ubicaciones estándar. Todos los artefactos pueden identificarse de esta manera, ya que cada uno tiene un nombre de archivo único. En este documento, cada ruta que identifica un artefacto se denominará "ruta del artefacto".

Para que las rutas de los artefactos sean más sencillas y legibles, se puede omitir la extensión si es igual a jar. Para los artefactos que no son JAR, la extensión no se puede omitir y debe conservarse.

Además, si la ruta del artefacto apunta a un directorio, representa todos los artefactos contenidos en dicho directorio. Esto permite hacer referencia fácilmente a un conjunto completo de artefactos relacionados, simplemente especificando el nombre del directorio que los contiene.

Si el mismo parche del artefacto tiene extensiones válidas en dos directorios raíz diferentes entonces no está especificado cuales artefactos estarán situados.

Especificación de artefacto

Como notado en sección anterior, cada artefacto puede ser identificado únicamente por su ruta de archivo. Sin embargo esto no siempre la manera preferida para identificación de artefacto.

Modern Java build systems provide a way of identifying artifacts with an abstract identifier, or more often, a pair of identifiers. The first if usually called group ID or organization ID while the second is just artifact ID. This pair of identifiers will be called artifact coordinates in this document. Besides group ID and artifact ID, artifact coordinates may also include other optional information about artifact, such as extension, classifier and version.

In Linux distributions it is important to stay close to upstreams providing software being packaged, so the ability to identify artifacts in the same way as upstream does is very important from the packaging point of view. Every artifact can optionally be identified by artifact coordinates assigned during package build. Packages built with Maven automatically use this feature, but all other packages, even these built with pure javac, can use this feature too (see description of %mvn_artifact and %add_maven_depmap macros).

Alias

Los alias funcionan de dos maneras:

  • Enlaces simbólicos para rutas

  • Relaciones adicionales para las especificaciones de artefactos

In the real world the same project can appear under different names as it was evolving or released differently. Therefore other projects may refer to those alternative names instead of using the name currently prefered by upstream.

Aliases de artefacto

XMvn provides a way to attach multiple artifact coordinates to a single artifact. Dependent projects that use alternative coordinates can then be built without the need to patch their POMs or alter the build by other means. It will also generate virtual provides for the alias, so it can be also used in Requires and BuildRequires. Creating an alias is achieved by %mvn_alias macro.

Ejemplo de invocación
# com.example.foo:bar (el artefacto real existente en el proyecto) también
# está disponible como com.example.foo:bar-all
%mvn_alias com.example.foo:bar com.example.foo:bar-all

# No es necesario repetir la parte de las coordenadas que permanece igual
# (groupID en este caso)
%mvn_alias com.example.foo:bar :bar-all

# Puedes especificar varios alias a la vez.
%mvn_alias com.example.foo:bar :bar-all :bar-lib

# La macro admite varios atajos para generar múltiples alisaes.
# Ramas - {} - captura su contenido, los cuales entonces ser referenced en la
# parte alias con @N, donde N es el índice del grupo de captura.
# * actúa como comodín (coteja cualquiera)
# El siguiente genera aliases finalizados con sombreados para todos artefactos
# en el proyecto
%mvn_alias 'com.ejemplo.talcual:{}' :@1-sombreado

Versiones de compatibilidad

Manipular para compatibilidad de paquetes, jars versionados, etc.

In Fedora we prefer to always have only the latest version of a given project. Unfortunately, this is not always possible as some projects change too much and it would be too hard to port dependent packages to the current version. It is not possible to just update the package and keep the old version around as the names, file paths and dependency provides would clash. The recommended practice is to update the current package to the new version and create new package representing the old version (called compat package). The compat package needs to have the version number (usually only the major number, unless further distinction is necessary) appended to the name, thus effectivelly having different name from RPM’s point of view. Such compat package needs to perform some additional steps to ensure that it can be installed and used along the non-compat one.

You should always evaluate whether creating a compat package is really necessary. Porting dependent projects to new versions of dependencies may be a complicated task, but your effort would be appreciated and it is likely that the patch will be accepted upstream at some point in time. If the upstream is already inactive and the package is not required by anything, you should also consider retiring it.

Versiones de compatibilidad de Maven

XMvn supports marking particular artifact as compat, performing the necessary steps to avoid clashes with the non-compat version. An artifact can be marked as compat by %mvn_compat_version. It accepts an artifact argument which will determine which artifact will be compat. The format for specifying artifact coordinates is the same as with %mvn_alias. In the common case you will want to mark all artifacts as compat. You can specify multiple compat versions at a time.

Resolución de dependencias de artefactos de compatibilidad

Cuando XMvn realiza la resolución de dependencias para un artefacto de dependencia en un proyecto, verifica la versión de la dependencia y la compara con todas las versiones del artefacto instaladas en el directorio de compilación. Si ninguno de los artefactos compatibles coincide, resolverá el artefacto al que no sea compatible. Esto tiene algunas implicaciones:

  • The versions are compared for exact match. The compat package should provide all applicable versions that are present in packages that are supposed to be used with this version.

  • The dependent packages need to have correct BuildRequires on the compat package as the virtual provides is also different (see below).

Los nombres de archivo y los proveedores virtuales

In order to prevent file name clashes, compat artifacts have the first specified compat version appended to the filename. Virtual provides for compat artifacts also contain the version as the last part of the coordinates. There are multiple provides for each specified compat version. Non-compat artifact do not have any version in the virtual provides.

Ejemplo de invocación de %mvn_compat_version
# Asumiendo el paquete tiene barra de nombre y versión 3
# Conjuntos el compat versión de foo:artefacto de barra a 3
%mvn_compat_versión foo:barra 3
# El archivo de artefacto instalada (suponiendo que es un jar y no había ninguno
# %mvn_llamadas de lima) será en %{_javadir}/barra/de barra-3.Bote
# El generado proporciona para foo:la barra será
# mvn(foo:barra:3) = 3
# mvn(foo:barra:pom:3) = 3

# Establece las versiones de compatibilidad de todos los artefactos en la compilación a 3 y 3.2.
%mvn_compat_version : 3 3.2

Manipular Dependencia

RPM has multiple types of metadata to describe dependency relationships between packages. The two basic types are Requires and Provides. Requires denote that a package needs something to be present at runtime to work correctly and the package manager is supposed to ensure that requires are met. A single Requires item can specify a package or a virtual provide. RPM Provides are a way to express that a package provides certain capability that other packages might need. In case of Maven packages, the Provides are used to denote that a package contains certain Maven artifact. They add more flexibility to the dependency management as single package can have any number of provides, and they can be moved across different packages without breaking other packages' requires. Provides are usually generated by automatic tools based on the information from the built binaries or package source.

Gestión de dependencias para paquetes Maven

The Java packaging tooling on Fedora provides automatic Requires and Provides generation for packages built using XMvn. The Provides are based on Maven artifact coordinates of artifacts that were installed by the currently being built. They are generated for each subpackage separately. They follow a general format mvn(groupId:artifactId:extension:classifier:version), where the extension is omitted if its jar and classifier is omitted if empty. Version is present only for compat artifacts, but the trailing colon has to be present unless it is a Jar artifact with no classifier.

# Ejemplo de provisión para artefacto Jar
mvn(org.eclipse.jetty:jetty-server)
# Ejemplo de provisión para artefacto POM
mvn(org.eclipse.jetty:jetty-parent:pom:)
# Ejemplo de provisión para artefacto Jar con clasificador
mvn(org.sonatype.sisu:sisu-guice::no_aop:)

The generated Requires are based on dependencies specified in Maven POMs in the project. Only dependencies with scope set to either compile, runtime or not set at all are used for Requires generation. Requires do not rely on package names and instead always use virtual provides that were described above, in exactly the same format, in order to be satisfiable by the already existing provides. For packages consisting of multiple subpackages, Requires are generated separately for each subpackage. Additionally, Requires that point to an artifact in a different subpackage of the same source package are generated with exact versions to prevent version mismatches between artifacts belonging to the same project.

The requires generator also always generates Requires on java-headless and javapackages-tools.

Manejo de dependencias para paquetes que no son Maven y que envían archivos POM

If the package is built built using different tool than Apache Maven, but still ships Maven POM(s), the you will still get automatic provides generation if you install the POM using %mvn_artifact and %mvn_install. The requires generation will also be executed but the outcome largely depends on whether the POM contains accurate dependency insformation. If it contains dependency information, you should double-check that it is correct and up-to-date. Otherwise you need to add Requires tags manually as described in the next section.

Manejo de dependencias para paquetes que no son Maven y que no incluyen archivos POM

For packages without POMs it is necessary to specify Requires tags manually. In order to build the package you needed to specify BuildRequires tags. Your Requires tags will therefore likely be a subset of your BuildRequires, excluding build tools and test only dependencies.

Consulta de Requisitos y Prestaciones de paquetes compilados

Los Requisitos y Provisiones generados de los paquetes compilados se pueden consultar usando rpm:

rpm -qp --provides path/to/example-1.0.noarch.rpm
rpm -qp --requires path/to/example-1.0.noarch.rpm
Generando BuildRequires

While Requires and Provides generation is automated for Maven projects, BuildRequires still remains a manual task. However, there are tools to simplify it to some extent. XMvn ships a script xmvn-builddep that takes a build.log output from mock and prints Maven-style BuildRequires on artifacts that were actually used during the build. It does not help you to figure out what the BuildRequires are before you actually build it, but it may help you to have a minimal set of BuildRequires that are less likely to break, as they do not rely on transitive dependencies.

Paquetes de Javadoc

Javadoc subpackages in Fedora provide automatically generated API documentation for Java libraries and applications. Java Development Kit comes with tool called javadoc. This tool can be used for generating the documentation from specially formated comments in Java source files. Output of this tool, together with license files, usually represents only content of javadoc subpackages. Note javadoc invocation is typically handled by build system and package maintainer does not need to deal with it directly.

Javadoc subpackage shouldn’t depend on its base package and vice versa. The rationale behind this rule is that documentation can usually be used independently from application / library and therefore base package does not need to be always installed. Users are given an option to install application and documentation separately.

You can learn more about javadoc from official documentation.

Paquetes principales de Java

JVM

Fedora permite que múltiples Java Virtual Machines (JVM) sean empaquetadas independientemente. Los paquetes Java no deberían depender directamente de ninguna JVM en particular, sino que requiere de uno de los tres paquetes JVM virtuales dependiendo de la funcionalidad que se requiera.

java-headless

Este paquete proporciona un Java Runtime Environment (Entorno Java en Tiempo de Ejecución) (JRE) en funcionamiento con alguna funcionalidad inhabilitada. El soporte de gráficos y audio puede no estar disponible en este caso. java-headless proporciona una funcionalidad que es bastante para la mayoría de los casos y evita tirar de diversas bibliotecas de gráficos y audio como dependencias. Los requisitos en java-headless son apropiados para la mayoría de los paquetes Java.

java

Incluye la misma funcionalidad base que java-headless, pero también implementa subsistemas de audio y gráficos. Los paquetes deberían requerir java si necesitan alguna funcionalidad de estos subsistemas, por ejemplo la creación de IGU (Interfaz Gráfica de Usuario) usando la biblioteca AWT (Conjunto de Herramientas de X Window).

java-devel

Proporciona el Java Development Kit (Conjunto de Desarrollo Java) (JDK) completo. En la mayoría de los casos solo los paquetes relacionados con el desarrollo Java deberían tener dependencias en tiempo de ejecución sobre java-devel. Los paquetes en tiempo de ejecución deberían requerir java-headless o java. Algunos paquetes no relacionados estrictamente con el desarrollo java necesitan acceso a bibliotecas incluidas con JDK, pero no con JRE (por ejemplo tools.jar). Eso es uno de lo pocos casos donde puede ser necesario requerir java-devel.

Los paquetes que requieren una versión mínima estándar de Java pueden añadir dependencias versionadas en uno de los paquetes virtuales que proporcionan entorno Java . Por ejemplo si paquetes que dependen de la funcionalidad de JDK 8 pueden requerir java-headless >= 1:1.8.0.

Époco en versiones de paquetes JVM

Por compatibilidad con el proyecto JPackage los paquetes que proporcionan Java 1.6.0 o posterior usan época igual a 1. Esto fue necesario porque el paquete java-1.5.0-ibm del proyecto JPackage tenía época `1`por alguna razón, de modo que los paquetes que proporcionan otras implementaciones de JVM también tienen que usar época distinta de cero para mantener la ordenación correcta de versiones.

Herramientas de Paquetes Java

Las Herramientas de Paquetes Java están empaquetados como varios paquetes RPM binarios:

maven-local

Este paquete proporciona un entorno completo el cual es requerido para compilar paquetes Java utilizando sistema de compilación Apache Maven. Esto incluye una versión del sistema predeterminada del Java Developement Kit (JDK), Maven, un número de complementos Maven comúnmente utilizados para compilar paquetes, varios macros y herramientas de utilidades. `maven-local`usualmente está declarado como dependencia de compilación de paquetes Maven.

ivy-local

Analógicamente para maven-local, este paquete proporciona un entorno requerido para compilar paquetes de Java utilizando Apache Ivy como gestor de dependencia.

javapackages-local

El paquete que proporciona un entorno básico necesario para generar e instalar metadatos para el sistema del repositorio de artefacto.

javapackages-tools

Empaqueta propiedad básica de directorios Java y proporciona soporte para tiempo de ejecución para paquetes de Java. La gran mayoría de los paquetes Java dependen de javapackages-tools.