En esta entrada de hoy mostraré como implementar un sistema para que los usuarios de nuestras librerías puedan averiguar fácilmente cual es la versión que están utilizando y que se mantenga automáticamente al generar nuestros .jar con Maven.
Introducción
Uno de los “problemas/features” cuando uno usa
Maven/
Ivy/
Grape o sistemas similares para gestionar sus dependencias es que independientemente de la versión, las librerías acaban teniendo un nombre común. Es decir, que la librería
org.hibernate:hibernate:3.2.6.ga acaba llamandose
hibernate.jar, igual que si fuera la
3.3.0.SP1 o cualquier otra versión. Esta característica ayuda a la hora de reemplazar una versión con otra, pero dificulta averiguar de un vistazo que versiones de librería estamos utilizando.
En caso de que nosotros hagamos una librería y se use a través de uno de estos sistemas, nuestros usuarios tendrán el mismo problema para averiguar en el sistema final qué versión está desplegada. Como somos unos “grandes” programadores, queremos facilitar a nuestros usuarios el averiguar está información, pero como somos unos programadores
vagos eficientes no queremos tener que hacerlo a mano cada vez que generamos un .jar, y menos si usamos algo como
Maven para gestionar nuestro proyecto. Así pues, ¿como lo podemos hacer?
Implementación
Paso 1:
Lo primero que tenemos que hacer es almacenar el número de versión de forma automática en algún sitio. Un buen sitio para hacerlo es en el fichero Manifest de nuestro .jar, y para hacerlo de forma automática podemos utilizar el plugin de Maven org.codehaus.mojo.buildnumber-maven-plugin. La documentación que tiene no es demasiado extensa, pero investigando un poco podemos averiguar cómo usarlo. En mi caso, dado que utilizo Mercurial como sistema de versiones y el numero de versión que utiliza no es muy significativo (no es un número correlativo) así que lo he sustituido por una marca de tiempo que me da una indicación más fiable. Si usas algo como Subversion, entonces quizá la configuración estándar del plugin ya te sirva Dado que el plugin no se encuentra en el repositorio central de Maven, tenemos que añadir un repositorio de plugins para encontrarlo, de la siguiente forma:
codehaus-snapshot
Cohehaus snapshot repository
https://nexus.codehaus.org/content/groups/snapshots-group
true
Una vez hecho esto, configuramos el plugin para que nos defina unas variables con la información que queremos, así:
org.codehaus.mojo
buildnumber-maven-plugin
1.0-beta-5-SNAPSHOT
validate
create
true
true
{0,date,dd/MM/yyyy HH:mm:ss}
- timestamp
Con esto le decimos que nos añada el timestamp a la variable
buildNumber, que es donde el plugin pone su información.
Por último, configuramos el
plugin org.apache.maven.plugins.maven-jar-plugin para que use esa información para añadir una nueva entrada en el Manifest de nuestro jar. De la siguiente forma:
org.apache.maven.plugins
maven-jar-plugin
2.3.1
false
${version}-${buildNumber}
my.package.MainApp
Una vez hecho esto, si ejecutamos
mvn package, por ejemplo, para generar nuestro fichero ,jar y miramos el fichero MANIFEST.MF dentro del directorio META-INF, deberíamos ver algo tal que así:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: usuario
Build-Jdk: 1.6.0_21
Main-Class: my.package.MainApp
MyLibrary-version: 0.1-SNAPSHOT-25/06/2011 13:33:01
Paso 2:
Bien, ya tenemos almacenada la versión en el .jar. ¿Ahora que hacemos para facilitar que el usuario pueda ver esa información sin tener que abrir el .jar y mirar el manifest? Muy sencillo: la clase my.package.MainApp que es la principal de nuestra aplicación tiene que mostrar esa versión. En mi caso, la librería es una utilidad que no se lanza en linea de comandos, se usa añadiéndola al classpath, así que mi clase MainApp simplemente muestra la versión de la librería.
¿Y como hacemos para leer el manifest del mismo fichero del cual nos estamos ejecutando? Pues averiguando donde se encuentra el .jar en tiempo de ejecución y accediendo a él para leer el fichero manifest. Podemos hacerlo así (código simplificado sin gestión de errores):
String jarFileURL =
MainApp.class.getProtectionDomain().getCodeSource().getLocation().toString();
int pos = jarFileURL.indexOf("!");
if(pos!=-1)
{
jarFileURL = jarFileURL.substring(0,pos);
}
if(!jarFileURL.startsWith("jar:"))
{
jarFileURL = "jar:" + jarFileURL;
}
URL manifestUrl = new URL(jarFileURL + "!/META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(manifestUrl.openStream());
return manifest.getMainAttributes().getValue(“MyLibrary-version”);
Y así podemos hacer que al ejecutar java -jar milibreria.jar nos devuelva la versión de la librería, o si lo ponemos en un método público, podemos usar este número para mostrarlo en las aplicaciones que usen la librería y así puedan saber que versión están utilizando, comprobar si existen nuevas versiones etc.
Espero que os sirva, al menos a mi me ha servido, y que vuestros usuarios estén más contentos :).
Happy coding! EJ