Eliminando redundancia de configuración: Maven
Uno de los pilares de MuleSoft es fomentar la reutilización para reducir el Time To Market. Esto se puede aplicar en todos los niveles, desde la creación de fragments en la etapa de diseño y APIs ‘componibles’ hasta configuraciones de Maven. En este artículo, veremos cómo eliminar la redundancia en la configuración de nuestras aplicaciones con Maven utilizando los archivos pom.xml, parent-pom.xml y bom.xml.
Flujo de trabajo
Conceptos Básicos
POM (Project Object Model)
El POM es la unidad básica de trabajo en Maven y contiene cada parte importante de información acerca del proyecto:
- Coordenadas
- Tipo de empaquetado para el proyecto: jar, pom, mule-application
- Dependencias y la ubicación del repositorio donde residen.
- Configuraciones de compilación y gestión de plugins
- Cada pom.xml hereda implícitamente un Super POM
- Las configuraciones pueden ser externalizadas a settings.xml: credenciales para repositorios privados, como por ejemplo Mule EE o el de nuestra propia Org. de Anypoint Platform.
Coordenadas
Todo en Maven se identifica por coordenadas que están conformadas por: groupId + artifactId + version
settings.xml
Este archivo, ubicado en la subcarpeta conf dentro de la carpeta raíz de Maven, se utiliza para definir configuraciones de usuario específicas que pueden incluir detalles como las credenciales para repositorios privados y configuraciones de proxy. Es una buena práctica externalizar configuraciones sensibles y de entorno en este archivo.
Simplificando la configuración de nuestras aplicaciones
Para evitar configuraciones duplicadas en nuestras aplicaciones, es fundamental eliminar la redundancia durante la compilación. Esto se puede lograr externalizando las configuraciones de Maven en el archivo settings.xml
y creando los archivos bom.xml
y parent-pom.xml
. Esta práctica permite desplegar aplicaciones sin depender de Anypoint Studio y asegura una configuración centralizada y uniforme en todos los proyectos.
El pom.xml
de la aplicación va a heredar del parent-pom
y éste, del bom
.
Archivo BOM (Bill Of Materials)
El BOM es un proyecto Maven centraliza la configuración de todas las versiones de los conectores, módulos y plugins que se van a utilizar en toda la organización, así como también los repositorios y distintos perfiles de ejecución. Con esto se asegura que todas las aplicaciones utilicen las mismas versiones y es más fácil de hacer un seguimiento si llegara a haber problemas con una versión en particular o surgiera la necesidad de actualizar un conector por nuevas funciones de un release posterior.
Para crear un BOM, hay que crear un proyecto Maven con el empaquetado pom
y especificar las versiones de las dependencias que queremos centralizar, así como también repositorios, perfiles, plugins, etc:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Este archivo es un bom de ejemplo. Se necesita adaptar, completar y configurar para que sea de uso final -->
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>TU_ANYPOINT_ORG_ID</groupId>
<artifactId>myorg-mule-bom</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<properties>
<!-- Mule Runtime Version -->
<mule.runtime.version>4.4.7</mule.runtime.version>
<!-- Mule Plugins Versions -->
<mule.maven.plugin.version>4.1.2</mule.maven.plugin.version>
<mule.http.connector.version>1.9.3</mule.http.connector.version>
<mule.db.connector.version>1.14.0</mule.db.connector.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Mule HTTP Connector -->
<dependency>
<groupId>org.mule.connectors</groupId>
<artifactId>mule-http-connector</artifactId>
<version>${mule.http.connector.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<!-- Mule DB Connector -->
<dependency>
<groupId>org.mule.connectors</groupId>
<artifactId>mule-db-connector</artifactId>
<version>${mule.db.connector.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<!-- Otros conectores y módulos -->
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<!-- Mule Maven Plugin -->
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<extensions>true</extensions>
</plugin>
<!-- Munit Maven Plugin -->
<plugin>
<groupId>com.mulesoft.munit.tools</groupId>
<artifactId>munit-maven-plugin</artifactId>
<version>${munit.version}</version>
</plugin>
<!-- Mule Extensions Maven Plugin -->
<plugin>
<groupId>org.mule.runtime.plugins</groupId>
<artifactId>mule-extensions-maven-plugin</artifactId>
<version>${mule.extensions.maven.plugin.version}</version>
</plugin>
<!-- Otros plugins -->
</plugins>
</pluginManagement>
</build>
<repositories>
<repository>
<id>exchange-v3-myorg</id>
<name>Anypoint Exchange V3</name>
<url>https://maven.anypoint.mulesoft.com/api/v3/maven</url>
</repository>
<repository>
<id>mulesoft-releases</id>
<url>https://repository.mulesoft.org/releases/</url>
</repository>
<!-- Este es el repositorio MuleSoft Enterprise Edition,
se necesitan credenciales para acceder, que son configuradas en el settings.xml -->
<repository>
<id>releases-ee</id>
<name>Mule Release Repository</name>
<url>https://repository.mulesoft.org/nexus/content/repositories/releases-ee/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>mulesoft-releases</id>
<name>mulesoft release repository</name>
<layout>default</layout>
<url>https://repository.mulesoft.org/releases/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>releases-ee</id>
<name>Mule Release Repository</name>
<url>https://repository.mulesoft.org/nexus/content/repositories/releases-ee/</url>
</pluginRepository>
</pluginRepositories>
<distributionManagement>
<repository>
<id>exchange-v3-myorg</id>
<name>Exchange Repository</name>
<url>https://maven.anypoint.mulesoft.com/api/v3/organizations/${gsc.ap.orgId}/maven</url>
<layout>default</layout>
</repository>
</distributionManagement>
<profiles>
<profile>
<id>deploy-to-exchange-myorg</id>
<build>
<plugins>
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<version>${mule.maven.plugin.version}</version>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>exchange-pre-deploy</goal>
</goals>
</execution>
<execution>
<id>deploy</id>
<phase>deploy</phase>
<goals>
<goal>exchange-deploy</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Archivo Parent-POM
El parent-pom
es un proyecto Maven que, por lo general, referencia al bom
y al que se puede referenciar desde el pom.xml
de la aplicación Mule para obtener información adicional, como propiedades y configuraciones de despliegues. Es útil para administrar recursos compartidos y tener un único punto de modificación para los proyectos.
Para crear un parent-pom
, hay que crear un proyecto Maven con el empaquetado pom
, referenciar al bom y especificar las propiedades y configuraciones comunes, como puede ser para el despliegue de nuestras aplicaciones:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Este archivo es un parent-pom de ejemplo. Se necesita adaptar, completar y configurar para que sea de uso final -->
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>TU_ANYPOINT_ORG_ID</groupId>
<artifactId>myorg-mule-bom</artifactId>
<version>1.0.0</version>
</parent>
<groupId>TU_ANYPOINT_ORG_ID</groupId>
<artifactId>myorg-mule-parent-pom</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<properties>
<!-- Definir todas las properties necesarias -->
<!-- Para tagear el tipo de API -->
<api.layer.exp>Experience</api.layer.exp>
<api.layer.prc>Process</api.layer.prc>
<api.layer.sys>System</api.layer.sys>
<api.layer.backend>Backend</api.layer.backend>
<api.layer.none>None</api.layer.none>
<!-- Properties para despliegue ... -->
<deployment.env>setear con -Ddeployment.env=...</deployment.env>
<deployment.prefix>myorg-</deployment.prefix>
<deployment.suffix>-${deployment.env}</deployment.suffix>
<deployment.name>${deployment.prefix}${project.name}${deployment.suffix}</deployment.name>
<deployment.timeoutMillis>1200000</deployment.timeoutMillis>
<ap.uri>https://anypoint.mulesoft.com</ap.uri>
<!-- master\subOrg1\subOrg2 -->
<ap.businessGroup/>
<ap.environment>${deployment.env}</ap.environment>
<ch.space>Cloudhub-US-East-1</ch.space>
<ch.replicas>2</ch.replicas>
<ch.vCores>0.1</ch.vCores>
<!-- API autodiscovery -->
<ap.client_id>setear con -Dap.client_id=...</ap.client_id>
<ap.client_secret>setear con -Dap.client_secret=...</ap.client_secret>
<!-- para despliegue con Connected Apps -->
<ap.ca.client_id>setear con -Dap.ca.client_id=...</ap.ca.client_id>
<ap.ca.client_secret>setear con -Dap.ca.client_secret=...</ap.ca.client_secret>
<!-- Más properties requeridas en los proyectos -->
</properties>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
<pluginManagement>
<plugins>
<!-- permiten que los archivos de recursos contengan referencias a propiedades de Maven como ${property.nombre} -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<!-- excluir todos los archivos binarios del filtrado. -->
<nonFilteredFileExtension>p12</nonFilteredFileExtension>
<nonFilteredFileExtension>crt</nonFilteredFileExtension>
<nonFilteredFileExtension>pem</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
<!-- para poder crear y empaquetar aplicaciones Mule y desplegarlas en CH, CH 2.0, RTF -->
<!-- -->
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<!--
A modo de ejemplo, está configurado para CH 2.0. Para más información de otras opciones revisar la documentación oficial de mule-maven-plugin
https://docs.mulesoft.com/mule-runtime/latest/mmp-concept
-->
<cloudhub2Deployment>
<businessGroup>${ap.businessGroup}</businessGroup>
<environment>${ap.environment}</environment>
<target>${ch.space}</target>
<muleVersion>${app.runtime.semver}</muleVersion>
<provider>MC</provider>
<replicas>${ch.replicas}</replicas>
<vCores>${ch.vCores}</vCores>
<applicationName>${deployment.name}</applicationName>
<deploymentTimeout>${deployment.timeoutMillis}</deploymentTimeout>
<connectedAppClientId>${ap.ca.client_id}</connectedAppClientId>
<connectedAppClientSecret>${ap.ca.client_secret}</connectedAppClientSecret>
<connectedAppGrantType>client_credentials</connectedAppGrantType>
<properties>
<anypoint.platform.config.analytics.agent.enabled>true</anypoint.platform.config.analytics.agent.enabled>
<anypoint.platform.visualizer.displayName>${project.name}</anypoint.platform.visualizer.displayName>
<!-- api.layer debe establecerse en cada aplicación particular de Mule. -->
<anypoint.platform.visualizer.layer>${api.layer}</anypoint.platform.visualizer.layer>
<env>${deployment.env}</env>
<anypoint.platform.client_id>${ap.client_id}</anypoint.platform.client_id>
<anypoint.platform.client_secret>${ap.client_secret}</anypoint.platform.client_secret>
<!-- Las aplicaciones Mule específicas pueden configurar sus propias properties que se fusionarán con las proporcionados aquí -->
</properties>
<secureProperties>
<encrypt.key>${encrypt.key}</encrypt.key>
</secureProperties>
<deploymentSettings>
<http>
<inbound>
<lastMileSecurity>true</lastMileSecurity>
</inbound>
</http>
</deploymentSettings>
<integrations>
<services>
<objectStoreV2>
<enabled>true</enabled>
</objectStoreV2>
</services>
</integrations>
</cloudhub2Deployment>
</configuration>
</plugin>
<!-- para correr pruebas de MUnit -->
<plugin>
<groupId>com.mulesoft.munit.tools</groupId>
<artifactId>munit-maven-plugin</artifactId>
<executions>
<execution>
<id>test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
<goal>coverage-report</goal>
</goals>
</execution>
</executions>
<configuration>
<runtimeVersion>${app.runtime}</runtimeVersion>
<runtimeProduct>MULE_EE</runtimeProduct>
<environmentVariables>
<!-- esto implica que todas las pruebas ejecutadas en la misma compilación de Maven deben utilizar la misma encrypt.key -->
<encrypt.key>${encrypt.key}</encrypt.key>
</environmentVariables>
<coverage>
<runCoverage>true</runCoverage>
<failBuild>true</failBuild>
<!-- Reemplazar el 0 por los valores de coverage de pruebas mínimos requeridos -->
<requiredApplicationCoverage>0</requiredApplicationCoverage>
<requiredResourceCoverage>0</requiredResourceCoverage>
<requiredFlowCoverage>0</requiredFlowCoverage>
<formats>
<format>console</format>
<format>html</format>
</formats>
</coverage>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<appendAssemblyId>true</appendAssemblyId>
</configuration>
<executions>
<execution>
<id>create-distribution</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>/src/main/resources/docs-assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Archivo POM
El POM es el archivo de configuración Maven para nuestro proyecto específico. Referencia al parent-pom
mediante el tag <parent>
para simplificar las configuraciones, podemos observar lo simple que se ve utilizando la herencia de poms:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Este archivo es un pom de ejemplo. Se necesita adaptar, completar y configurar para que sea de uso final -->
<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>
<parent>
<groupId>TU_ANYPOINT_ORG_ID</groupId>
<artifactId>myorg-mule-parent-pom</artifactId>
<version>1.0.0</version>
</parent>
<groupId>TU_ANYPOINT_ORG_ID</groupId>
<artifactId>sys-my-mule-app</artifactId>
<version>1.0.0</version>
<packaging>mule-application</packaging>
<name>sys-my-mule-app</name>
<properties>
<!-- información sin procesar para la especificación de la API expuesta por esta implementación de API -->
<!-- expresada a través de propiedades definidas en el parent POM padre (BOM) -->
<api.groupId>${sys-my-mule-app.groupId}</api.groupId>
<api.artifactId>${sys-my-mule-app.artifactId}</api.artifactId>
<api.version>${sys-my-mule-app.version}</api.version>
<api.layer>${api.layer.sys}</api.layer>
</properties>
<dependencies>
<dependency>
<groupId>org.mule.connectors</groupId>
<artifactId>mule-http-connector</artifactId>
<classifier>mule-plugin</classifier>
</dependency>
<dependency>
<groupId>org.mule.connectors</groupId>
<artifactId>mule-db-connector</artifactId>
<classifier>mule-plugin</classifier>
</dependency>
<!-- Mas dependencias requeridas en este proyecto -->
</dependencies>
El pom
resultante, conocido como “effective POM”, combina el POM del proyecto con sus padres, el super POM, y cualquier configuración definida en el archivo settings.xml
. Esto muestra todas las configuraciones, dependencias y propiedades que realmente se utilizarán para construir el proyecto.
Para ver el “effective POM” de un proyecto, puedes ejecutar el siguiente comando:
mvn help:effective-pom
Archivo /conf/settings.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Este archivo es un settings.xml de ejemplo. Se necesita adaptar, completar y configurar para que sea de uso final -->
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<pluginGroups>
<pluginGroup>org.mule.tools</pluginGroup>
</pluginGroups>
<servers>
<server>
<id>releases-ee</id>
<username>YOUR_MULE_EE_USERNAME</username>
<password>YOUR_MULE_EE_PASSWORD</password>
</server>
<server>
<id>anypoint-exchange-v3-myorg</id>
<!-- Connected App username -->
<username>~~~Client~~~</username>
<!-- <password>connected_app_clientId~?~connected_app_client_secret</password> -->
<password>CONNECTED_APP_CLIENT_ID~?~CONNECTED_APP_CLIENT_PASSWORD</password>
</server>
</servers>
</settings>
Tips
- Para que Anypoint Studio reconozca el bom y parent-pom es necesario instalarlos localmente, dentro de la ruta donde está ubicado el archivo, asumiendo que se llaman bom.xml y parent-pom.xml respectivamente, ejecutar:
mvn install:install:file –Dfile=bom.xml -DpomFile=bom.xml
mvn install:install:file –Dfile=parent-pom.xml -DpomFile=parent-pom.xml
- Para deployar en Exchange, suponiendo que en el bom configuramos un profile para desplegar en el Business Group depoy-to-exchange-v3-myorg, ejecutar:
mvn clean deploy -Pdepoy-to-exchange-v3-myorg -f bom.xml
mvn clean deploy -Pdepoy-to-exchange-v3-myorg -f parent-pom.xml
Para asegurarnos que la app compila correctamente, ejecutar el comando mvn clean verify –U en el proyecto para que traiga todas las dependencias del repositorio externo.
Conclusión
La eliminación de la redundancia en las configuraciones de Maven no sólo simplifica el mantenimiento de las aplicaciones, sino que también promueve la consistencia y la reutilización a lo largo de todos los proyectos Mule. Al centralizar las versiones de las dependencias y las configuraciones comunes en los archivos bom
y parent-pom
, podemos garantizar que todas las aplicaciones dentro de una organización sigan las mismas directrices y utilicen las mismas versiones de los componentes, lo que facilita la gestión y la actualización. Además, al externalizar configuraciones sensibles y específicas del entorno en el archivo settings.xml
, se mejora la seguridad y la flexibilidad del proceso de desarrollo.
Implementar esta estructura en nuestros proyectos Mule ayuda a reducir el tiempo de implementación y facilita el manejo de las dependencias y configuraciones, asegurando que nuestros proyectos sean más eficientes y manejables a largo plazo.