Affichage des articles dont le libellé est Trucs et astuces. Afficher tous les articles
Affichage des articles dont le libellé est Trucs et astuces. Afficher tous les articles

6 mars 2009

Comment lire la version d'un JAR à partir du fichier « Manifest » ?


Toute application doit avoir un numéro de version. Il permet d'identifier aisément, entre autres, la branche du code source à l'origine de sa création (pour corriger des bogues, effectuer des évolutions, etc.). La technique la plus répandue c'est d'écrire le numéro de version dans un fichier de propriétés (properties) dont le contenu pourrait ressembler à ce qui suit :

application.version=1.0b

Il est alors possible à l'application d'extraire le numéro de version pour l'afficher dans la barre de titre, par exemple, ou l'utiliser dans la trace applicative. Ce procédé vous oblige à maintenir le fichier et à veiller à incrémenter correctement le numéro de version.

Bonne nouvelle si vous utilisez Maven : vous n’aurez plus à effectuer cette tache ! En effet, Maven inscrit systématiquement le numéro de version dans le Manifest (MANIFEST.MF) des JAR qu'il produit (le numéro de version est exactement le même que celui qui figure dans le POM du projet Maven).

Comment extraire le numéro de version ?

Commençons par un code simple. Cela se fait en deux étapes : charger le fichier MANIFEST.MF, puis lire son contenu grâce à la classe java.util.jar.Manifest.

La classe suivante est « packagée » dans un jar nommé version.jar.
public class VersionUtil {

public static void main(String[] args) throws IOException {
System.out.println(readVersion());
}

public static String readVersion() throws IOException {

InputStream in = VersionUtil.class.getResourceAsStream("/META-INF/MANIFEST.MF");

Manifest manifest = new Manifest(in);

// Lire la propriété "Implementation-Version" du Manifest

String version = manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);

return version;

}
}

Le code ci-dessus fonctionne sans erreur, mais affiche quand même un résultat erroné : 1.5.0_10. Il correspond en réalité au numéro de version du JDK. Le ficher MANIFEST.MF chargé n'était «manifestement» pas celui du JAR en question, mais celui de rt.jar (le jar qui contient les classes de base de Java). L'explication est la suivante : la méthode getResourceAsStream(..) délègue la lecture de MANIFEST.MF au chargeur de classe (classloader) de la classe VersionUtil.class, or ce chargeur de classe se trouve dans rt.jar et non dans version.jar. Pour qu'une classe puisse charger le fichier MANIFEST.MF du JAR dans lequel elle se trouve, elle recourt à une méthode utilitaire qui calcule le chemin dudit JAR. Elle déduit ensuite l'emplacement du Manifest.

L'extrait de code Java montre comment le chemin vers le MANIFEST.MF est trouvé. J'avoue que le code est un peu alambiqué, mais heureusement il est commenté. La méthode présente l'avantage de fonctionner, et pour une classe se trouvant dans un jar, et pour une classe se trouvant dans un répertoire. Pour une meilleure compréhension, j'ai mis en commentaires le contenu des variables à chaque étape, et ce, pour les deux cas précités.
private static String getPathToManifest(){

// 1 - Lire le nom de la classe
String classSimpleName = VersionUtil.class.getSimpleName() + ".class";
// classSimpleName = VersionUtil.class

// 2 - Récupérer le chemin physique de la classe
String pathToClass = VersionUtil.class.getResource(classSimpleName).toString();

// pathToClass = file:/C:/workspace/VersionUtil/bin/com/abdennebi/version/VersionUtil.class
// pathToClass = jar:file:/C:/version.jar!/com/abdennebi/version/VersionUtil.class

// 3 - Récupérer le chemin de la classe à partir de la racine du classpath
String classFullName = VersionUtil.class.getName().replace('.', '/') + ".class";
// classFullName = com/abdennebi/version/VersionUtil.class

// 4 - Récupérer le chemin complet vers MANIFEST.MF
String pathToManifest = pathToClass.substring( 0, pathToClass.length() - (classFullName.length())) + "META-INF/MANIFEST.MF";
// pathToManifest = file:/C:/workspace/VersionUtil/bin/META-INF/MANIFEST.MF
// pathToManifest = jar:file:/C:/version.jar!/META-INF/MANIFEST.MF

return pathToManifest;
}
L'exemple complet se trouve à cet endroit VersionUtil.java. Une modification pour Java 1.4 se trouve ici : VersionUtil14.java.

16 janvier 2009

Maven, considérer le répertoire source comme un répertoire de ressources

Par défaut, Maven sépare les sources java des autres ressources, telles que les fichiers properties ou les fichiers XML. Ceci, constitue en général, une bonne pratique. Cependant, si vous migrez une application et que vous ne désirez pas séparer les ressources des sources Java, il est impératif d'en informer Maven, sinon vous risquerez d'avoir des surprises (un WAR sans le moindre fichier properties).

Pour ce faire, ajoutez ce bout de code XML au fichier POM de votre projet :


...


src/main/java

**/*.java



...

Cette déclaration informe Maven que le répertoire src/main/java contient des ressources et qu'il ne faut pas prendre en compte les fichiers Java (sinon ils risquent d'être inclus dans l'artéfact généré par Maven).

9 janvier 2009

Ajoutez un deuxième répertoire source à votre projet Maven

Actuellement, je m'occupe de la migration du code d'une application historique vers Maven. Cette application contient deux répertoires sources Java, l'un contient du code généré (des proxies PacBase), et l'autre contient le code écrit par le programmeur. Pour ce faire, il faut indiquer à Maven d'utiliser un répertoire supplémentaire à savoir src/main/javaproxie (en plus du classique src/main/java).

Maven permet de définir un répertoire source différent du répertoire source conventionnel grâce à la déclaration suivante (en prenant comme exemple src/main/javaproxies):


src/main/javaproxies


Le problème est qu'il n'est pas possible d'ajouter (nativement) un nouveau répertoire source. C'est plutôt le rôle du plugin build-helper et son goal add-source, il permet, en effet, de définir plusieurs répertoires sources de la manière suivante :




org.codehaus.mojo
build-helper-maven-plugin


add-source
generate-sources

add-source



src/main/javaproxies







En résumé, dans des situations où il est nécessaire d'utiliser un répertoire source supplémentaire, par exemple du code généré par xDoclet, des stubs et proxies Corba ou Web Services, ce plugin vous sauvera la vie !

17 décembre 2008

Connaitre la version d'un driver JDBC

Un des soucis majeurs d'un développeur Maven est de tomber sur un JAR propriétaire et par-dessus le marché sans aucune indication de version. Tel était mon cas. Actuellement, je migre une ancienne application vers Maven, elle utilise un driver DB2 dont le JAR ne contient pas le numéro de version qu'on trouve habituellement dans META-INF/MANIFEST.MF. Heureusement, JDBC prévoit la possibilité de récupérer le numéro de version d'un driver et ce, à l'aide de la classe DatabaseMetaData.

Le code suivant charge le driver JDBC, puis se connecte à la base de données (l'inconvénient est l'obligation de se connecter à une base de données, je n'ai pas trouvé mieux !), il fait ensuite appel à la méthode getDriverVersion().


import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Version {

public static void main(String args[]) throws InstantiationException,
IllegalAccessException, ClassNotFoundException, SQLException {
Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();
Connection con = DriverManager.
getConnection("jdbc:db2://<nom de la base>", "<utilisateur>", "<mot de passe>");
DatabaseMetaData dmd = con.getMetaData();
System.out.println("La version du driver est : " + dmd.getDriverVersion());

}
}

21 mai 2007

Trouver l’explication d’une erreur Oracle

Si vous êtes en face d'un code erreur de la base de données Oracle (de type ora-XXXXX), tapez le nom d'erreur en tant qu'un sous domaine du site ora-code.com et vous aurez le texte expliquant la cause de l'erreur.

Par exemple, pour le code erreur ora-00906 le lien est http://ora-00906.ora-code.com.

Il y a même une rubrique qui indique l'action a entreprendre pour régler le problème. ça peut servir ....