Brevet FR2888351A1 — publié le 20070112

ARBORESCENCE DE CHARGEURS DE CLASSES MAPPÉE SUR L'ARBORESCENCE DE RÉPERTOIRES La présente invention se rapporte au domaine du chargement de bytecodes (pseudo-codes) dans des environnements logiciels interprétés. La présente invention concerne plus particulièrement un procédé et une architecture pour le chargement de tels bytecodes, par exemple des classes, offrant la possibilité, sur une même machine virtuelle et en même temps, d'exécuter différentes implémentations d'une même classe et d'en faciliter la gestion. Dans les environnements de langage de programmation, l'exécution de programmes de type Java requiert que le code source du programme soit compilé en pseudo-codes (bytecodes) Java, lesquels sont interprétés par un ordinateur virtuel, appelé Machine Virtuelle. Les codes sources Java sont constitués généralement de classes stockées dans des fichiers de classes sous le format de bytecode, par exemple des fichiers JAR (Java ARchive) pour le langage Java (nom commercial). Une classe est un ensemble de variables et de méthodes qui modélisent le comportement d'un objet. Ces classes sont chargées dans la mémoire de la machine virtuelle à l'aide d'un chargeur de classe (class loader) pour ensuite être interprétées par la machine virtuelle. Afin d'optimiser la gestion de la mémoire utilisée par la machine virtuelle, le chargement des classes peut être réalisé de façon dynamique lors de l'exécution du programme sur la machine virtuelle, comme dans l'exemple de réalisation décrit plus en détail dans le brevet US 6 470 494 ou dans la demande de brevet US 2004 / 261 069. Le chargement dynamique offre la possibilité de ne charger en mémoire les classes ou versions de classe que lorsque celles-ci sont utilisées, permettant d'économiser de la sorte les ressources de la machine virtuelle lors de l'exécution du code source. On connaît déjà des solutions logicielles de chargement dynamique de classes, telles que Eclipse d'IBM (noms commerciaux). Dans cette dernière, l'intégralité des fichiers de classes d'un même dossier est chargée en utilisant un unique chargeur de classe. Cependant il peut être souhaitable d'exécuter sur une même machine virtuelle VM, plusieurs configurations sensiblement proches, c'est-à-dire plusieurs implémentations d'une même classe. Dans les solutions courantes, une variable appelée ClassPath (chemin de classe) permet de localiser le fichier de classes à partir du nom de la classe. En fonctionnement traditionnel, si deux classes portent le même nom, la seconde est ignorée. Il n'est donc pas possible d'avoir deux implémentations d'une même classe portant le même nom. Pour permettre toutefois la présence de deux implémentations d'une même classe, il est possible de dupliquer la classe en lui attribuant un autre nom, ou de produire des classes d'extension d'une même classe (concept d'héritage en langage orienté objet). Lors du chargement, un chargeur de classe spécifique est employé pour chacune des deux classes (ou des deux classes étendues) que l'on désire implémenter. Cette solution présente certains inconvénients, notamment. la difficulté de maintenir une compatibilité ascendante: comment s'assurer que la modification d'une classe mère n'altère pas le bon fonctionnement des classes filles ?, l'architecture est figée pour une implémentation, la maintenance est rendue difficile: si l'on souhaite modifier un élément commun à l'ensemble, il faut modifier l'ensemble des classes et mettre à jour le ClassPath, l'impossibilité de décharger une implémentation de classes sans avoir à décharger la machine virtuelle dans sa 10 totalité, la difficulté à identifier les parties communes qui pourraient être réutilisées pour un éventuel partage de ces classes avec d'autres modules. Il existe donc un besoin de solution pour le chargement de classes offrant la possibilité, sur une même machine virtuelle et en même temps, d'exécuter différentes implémentations d'une même classe, portant éventuellement le même nom, et d'en faciliter la gestion. L'invention propose de résoudre les inconvénients de l'art antérieur en organisant et stockant les bytecodes ou classes dans une arborescence de stockage de données, par exemple une arborescence de répertoires, et en affectant un chargeur de bytecodes à chacun des noeuds de l'arborescence. Notamment, cette arborescence permet de conserver l'héritage de classes en organisant les classes mères dans le répertoire parent des classes filles. Ainsi, les chargeurs de classes sont mappés sur l'arborescence de répertoires dans laquelle sont stockés les fichiers de classes: le lien de parenté entre un classloader (chargeur de classes) affilié à un répertoire et un classloader affilié au répertoire parent est le même que celui entre un répertoire et le répertoire parent. L'invention offre les avantages suivants: différentes implémentations d'une même classe indépendamment de leur nom, en même temps et sur un même VM, sont possibles; en effet, deux classloaders sont créés pour deux classes stockées dans deux répertoires séparés, la factorisation des classes en utilisant l'arborescence des répertoires pour conserver le mécanisme classique de l'héritage en plaçant les classes mères dans un répertoire parent. Cette factorisation fournit alors une organisation modulaire des classes, permettant un chargement plus rapide dans la machine virtuelle et un déchargement possible et ciblé sans arrêter l'exécution de la machine virtuelle (la gestion de la mémoire en est alors fortement simplifiée), un cycle de vie spécifique pour chacune des implémentations de la classe permettant une gestion et une maintenance (évolution propre des propriétés, chargement ou déchargement indépendant) de l'implémentation indépendamment des autres: toute modification sur une implémentation de classe n'affecte pas les autres classes. L'invention s'applique particulièrement aux IHM (Interface Homme-Machine) mettant en oeuvre des objets similaires avec des spécificités ou fonctionnalités différentes. Par exemple, un logiciel de programmation pour carte à puce qui doit présenter, sur une même interface de programmation API, des fonctionnements identiques de cartes alors même que ces cartes ont des spécificités de ressources matérielles différentes de l'une à l'autre. Dans cette optique, l'invention permet de créer des ensembles de classes communes (classes mères) à toutes les configurations de cartes et des parties plus spécifiques (classes filles) dans des sousrépertoires propres à chacune des cartes. À cet effet, l'invention concerne, dans son acception la plus générale, un procédé de chargement dynamique de classes dans une machine virtuelle d'un système informatique comportant un système arborescent de stockage de données du système d'exploitation, caractérisé en ce qu'il comprend: une étape d'enregistrement de fichiers de classes dans les noeuds de l'arborescence du système de stockage, une étape de balayage de l'arborescence, pour au moins un noeud de ladite arborescence, le 10 noeud comprenant au moins un fichier de classes, o une étape de création d'un chargeur de classes référençant les classes du noeud et les classes du noeud parent, o une étape de chargement dans ladite machine 15 virtuelle du chargeur de classes. Dans un mode de réalisation approprié pour conserver l'héritage de classes (par exemple l'héritage de classes), ledit chargeur de classes créé référence les classes du chargeur de classes dudit noeud parent. Particulièrement, le chargeur de classes du noeud racine référence uniquement les classes du noeud racine. Cela permet d'initier le chargement pour le noeud le plus en amont. Dans un autre mode de réalisation, le chargeur de classes du noeud racine référence les classes du noeud racine et des classes par défaut. Dans un mode de réalisation particulier, ladite arborescence respecte l'héritage entre classes. L'invention concerne également une architecture pour le chargement dynamique de classes dans une machine virtuelle d'un système informatique comportant un système de stockage de données en arborescence, caractérisée en ce qu'elle comprend une pluralité de fichiers de classes organisés dans les noeuds de l'arborescence du système de stockage et une pluralité de chargeurs de classes correspondant chacun à un noeud contenant au moins un fichier de classes, lesdits chargeurs de classes référençant les classes du noeud correspondant et les classes du noeud parent. Dans un mode de réalisation, lesdits chargeurs de classes créés référencent chacun les classes du chargeur de 10 classes de leur noeud parent. Dans un autre mode de réalisation, lesdits chargeurs de classes sont organisés selon une arborescence mappée sur ladite arborescence des noeuds du système de stockage. Dans un mode de réalisation particulier, l'architecture comporte au moins deux classes portant le même nom dans deux noeuds différents ayant un même noeud parent. Particulièrement, ladite arborescence respecte l'héritage entre classes. On comprendra mieux l'invention à l'aide de la description, faite ciaprès à titre purement explicatif, d'un mode de réalisation de l'invention, en référence à la figure 1 annexée qui illustre le mapping des chargeurs de classes sur l'arborescence des répertoires. Le mode de réalisation pour la description qui suit aborde l'invention dans le contexte d'un logiciel de programmation pour cartes à puce, comme précédemment introduit, lequel doit prendre en compte différents profils ou configurations matérielles de cartes. Pour chaque profil, un ensemble de classes est développé pour gérer une carte spécifique. Un tel logiciel permet de programmer des actions à réaliser (le code programme est en Java) sur une carte Java en faisant appel à des classes. Pour simplifier la gestion du nombre croissant de cartes différentes, il est intéressant de pouvoir gérer les différentes cartes en utilisant différentes versions ou implémentations d'une même classe, les implémentations portant le même nom et chacune d'entre-elles reflétant les particularités matérielles des cartes. Dans l'exemple de la figure 1, on utilise deux configurations différentes de carte: GXXv3.2 et GX3Gv2.2. On entend par implémentation le développement d'un nouveau code source, ici le code Java de définition et description des classes. Également à des fins de simplicité, nous n'utiliserons, dans l'exemple qui suit, qu'un seul fichier de classes par répertoire et une seule classe par fichier alors que l'invention peut être mise en oeuvre avec plusieurs fichiers JAR dans le même répertoire et plusieurs classes au sein d'un même fichier d'archive, que ces classes aient ou non une classe mère dans le(s) fichier(s) d'archive du répertoire parent. Il est bien entendu que, même si le langage Java a été évoqué précédemment, l'invention peut s'appliquer à de nombreux langages de programmation pouvant générer un bytecode interprétable, par exemple les langages orientés objets C++ ou encore C# utilisé dans le framework.Net (plateforme logicielle de développement Microsoft - nom commercial). *** L'arborescence des classes *** En référence à la figure 1, des fichiers JAR (Java ARchive pour Java2) de classes, par exemple corecommands.jar , sont enregistrés dans les répertoires du système de fichiers du système d'exploitation, par exemple le dossier GXXv3.2 . Les répertoires de tous les niveaux de l'arborescence sont susceptibles de recevoir un ou des fichiers d'archive JAR. On entend par arborescence du système de fichiers, la structure hiérarchique d'organisation des dossiers et sous-dossiers (ou répertoires) dont la forme rappelle celle d'un arbre. Le répertoire parent Lib contient un fichier d'archive commandframework.jar qui contient la définition de la classe SendAPDU. class . Le répertoire fils GXXv3.2 contient également un fichier d'archive corecommands.jar contenant la définition de la classe Create.class dont la classe SendAPDU.class est une classe mère au sens de l'héritage des classes dans les langages orientés objets. Un autre répertoire fils GX3Gv2.2 du répertoire Lib contient également un fichier d'archive du même nom corecommands.jar et/ou contenant une autre définition de la même classe Create.class dont la classe SendAPDU.class est une classe mère au sens de l'héritage des classes. Cet autre fichier corecommands.jar contient une implémentation de la classe Create.class différente de celle du premier fichier pour satisfaire aux spécificités matérielles de la carte à puce associée au type GX3Gv2.2. Les deux classes Create.class définissent une même classe (d'où le même nom) pour des configurations différentes: la configuration GXXv3.2 pour la première, GX3Gv2.2 pour la seconde. Leur définition diffère au niveau du code informatique enregistré dans les fichiers de classes JAR. *** Les ClassLoaders *** Lorsque l'on désire exécuter, sur la machine virtuelle, le programme faisant appel à ces classes, un parcours (scan) de l'arborescence des répertoires est 2888351 9 réalisé depuis la racine jusqu'aux répertoires de niveau le plus profond. Lors de ce scan de l'arborescence, tous les fichiers d'archive JAR sont identifiés ainsi que leurs répertoires. Dans le répertoire racine, Lib dans l'exemple de la figure 1, le fichier JAR commandframework.jar est détecté. Toujours en référence à la figure 1, un chargeur de classes LibClassLoader est alors créé, charge la classe SendAPDU.class et la référence afin que la machine virtuelle puisse y avoir accès. En langage Java, cette opération peut être réalisée par la fonction suivante: URLClassLoader LibClassLoader = new URLClassLoader (URL[l "/Lib/') Le chargement de classes référence également les classes précédemment chargées dans la machine virtuelle, par exemple les classes par défaut chargées par le ClassPath statique au lancement de la machine virtuelle. Les classes par défaut ainsi que la classe SendAPDU.class peuvent être instanciées dans la machine virtuelle par le chargeur de classes LibClassLoader . Lors du parcours de l'arborescence, le répertoire fils GXXv3.2 est détecté comme contenant un fichier archive de classe corecommands.jar . Un chargeur de classes GXXv32ClassLoader est alors créé en référençant les classes contenues dans son répertoire GXXv3.2 , à savoir Create.class et les classes contenues dans le répertoire parent Lib , à savoir SendAPDU.class . Cette opération peut être réalisée par la fonction Java: URLClassLoader GXXv32ClassLoader = new URLClassLoader (URL[] "/Lib/GXXv3.2/", LibClassLoader) Dans cette fonction, on passe en paramètre le chemin "/Lib/GXXv3.2/" du répertoire permettant de charger les classes de tous les fichiers JAR présents dans le répertoire, ici le seul fichier corecommands.jar . Dans la fonction, on passe également en paramètre le chargeur de classes parent (ici LibClassLoader ). LibClassLoader a déjà chargé les classes du répertoire Lib et on transmet ces classes au nouveau chargeur de classes créé, un chargeur de classes fils de LibClassLoader . Par cette fonction, le chargeur GXXv32ClassLoader référence non seulement Create.class et SendAPDU.class mais également les autres classes que référence LibClassLoader , à savoir dans cet exemple les classes de Java par défaut. Ainsi toutes ces classes ( Create.class , SendAPDU.class et les classes par défaut) peuvent être instanciées par ce chargeur de classes. Il est à noter qu'avec une arborescence profonde (plusieurs niveaux), les classes chargées dans un chargeur de classes sont toutes celles des répertoires parents: répertoire parent de niveau 1, de niveau 2, ..., et les classes par défaut. De même, lors du parcours de l'arborescence, l'autre répertoire fils GX3Gv2.2 est détecté et le fichier de classes corecommands.jar associé également. Un chargeur de classes GX3Gv22ClassLoader est alors créé en référençant les classes contenues dans son répertoire GX3Gv2.2 , à savoir Create.class et les classes contenues dans le répertoire parent Lib , à savoir SendAPDU.class . Cette opération peut être réalisée par la fonction Java: URLClassLoader GX3Gv22ClassLoader = new URLClassLoader (URL[] "/Lib/GX3Gv2.2/", LibClassLoader) Par cette fonction, le chargeur GX3Gv22ClassLoader référence non seulement Create.class et SendAPDU.class mais également les autres classes que référence LibClassLoader , à savoir dans cet exemple les classes de Java par défaut. Ainsi toutes ces classes ( Create.class , SendAPDU.class et les classes par défaut) peuvent être instanciées par ce chargeur de classes GX3Gv22ClassLoader . Dans cette configuration, deux définitions/implémentations d'une même classe sous le même nom coexistent, dans des répertoires frères (répertoires ayant le même répertoire parent). Les deux fichiers JAR sont distincts et les implémentations de classes sont totalement séparées dans la machine virtuelle lors de l'exécution du programme grâce à la séparation des chargeurs de classes, même si les classes portent le même nom. L'utilisation d'une telle arborescence est avantageuse pour accéder à la fois à des configurations différentes (les deux classes Create. class ) et à des configurations communes (la classe SendAPDU.class ), par exemple pour les cartes à puce dont le fonctionnement général est identique mais dont certaines configurations matérielles peuvent différer. Les chargeurs de classes GXXv32ClassLoader et GX3Gv22ClassLoader ont donc comme chargeur de classes parents LibClassLoader . Le lien de parenté entre un chargeur de classes associé à un répertoire et un chargeur de classes associé au répertoire parent est identique à celui qui lie les deux répertoires; on dit alors que les chargeurs de classes sont mappés sur l'arborescence des répertoires: il apparaît clairement que, par la présente invention, l'arborescence des chargeurs de classes peut être créée dynamiquement et mappée sur l'arborescence des répertoires. Il est bien sûr prévu de ne pas se limiter à deux niveaux d'arborescence et de dépasser l'exemple présenté. Par exemple, si la configuration matérielle de la carte à puce GX3Gv2.2 se trouve divisée en deux sous-configurations, on peut créer deux sousrépertoires fils du répertoire GX3Gv2.2 comportant chacun une classe de même nom mais spécifique à chacune des deux sous-configurations. Les chargeurs de classes associés aux deux sous-répertoires fils référencent alors leur propre classe ainsi que les classes mères du chargeur GX3Gv22ClassLoader . Ainsi, le logiciel de programmation peut utiliser selon ses besoins le chargeur GX3Gv22ClassLoader ou le chargeur GXXv32ClassLoader pour créer l'instance de la classe Create.class . *** Modification d'une classe *** Lors d'opération de maintenance, on peut être amené à modifier/mettre à jour une implémentation de classe, par exemple l'implémentation GX3Gv2.2 de la classe Create.class . Le code source de la classe Create.class est alors modifié dans le fichier de classes corecommands.jar du dossier GX3Gv2.2 . Cette modification n'a aucun impact sur le fichier corecommands.jar du répertoire GXXv3.2 et sur le comportement à l'exécution de la classe Create.class de l'implémentation GXXv3.2 puisque le chargeur GXXv32ClassLoader ne charge pas le fichier de classe du dossier GX3Gv2.2 . L'organisation modulaire permet ainsi de modifier une classe indépendamment des autres implémentations de la même classe: chaque implémentation d'une classe a un cycle de vie qui lui est propre. De même, puisque la classe SendAPDU.class est partagée pour les deux implémentations GXXv3.2 et GX3Gv2.2 , une modification des propriétés de la classe SendAPDU.class est prise en compte par les deux chargeurs de classes GXXv32ClassLoader et GX3Gv22ClassLoader . L'invention permet donc de factoriser le code source commun (une classe par exemple) à plusieurs implémentations afin d'en faciliter la maintenance: un seul chargeur est utilisé par les différentes implémentations pour charger les parties communes de code. *** Déchargement d'une classe *** De nombreuses recherches ont été effectuées pour optimiser la gestion de la mémoire dans les machines virtuelles. À cette fin, la présente invention permet à la machine virtuelle de récupérer une partie de la mémoire sans avoir à arrêter l'exécution de cette machine virtuelle. Ceci est possible en réalisant le déchargement de classes chargeur par chargeur. On peut alors détruire un chargeur de classes et la machine virtuelle récupère la mémoire affectée lorsque le Garbage collector (routine de récupération de la mémoire inutilisée dans le cadre Java) est déclenché. Pour mettre en oeuvre ce déchargement, on peut modifier la référence du chargeur de classes en la mettant à la valeur NULL dans le code de gestion. La conséquence de cette modification est la perte des références vers les classes chargées, et donc la récupération, lors du passage du garbage collector, de l'espace mémoire qui leur était attribué. REVENDICATIONS 1. Procédé de chargement dynamique de classes dans une machine virtuelle d'un système informatique comportant un système arborescent de stockage de données du système d'exploitation, caractérisé en ce qu'il comprend: une étape d'enregistrement de fichiers de classes dans les noeuds de l'arborescence du système de stockage, une étape de balayage de l'arborescence, pour au moins un noeud de ladite arborescence, le noeud comprenant au moins un fichier de classes, o une étape de création d'un chargeur de classes référençant les classes du noeud et les classes du noeud parent, o une étape de chargement dans ladite machine virtuelle du chargeur de classes. 2. Procédé selon la revendication précédente, caractérisé en ce que ledit chargeur de classes créé référence les classes du chargeur de classes dudit noeud parent. 3. Procédé selon la revendication précédente, caractérisé en ce que le chargeur de classes du noeud racine 25 référence uniquement les classes du noeud racine. 4. Procédé selon la revendication 2, caractérisé en ce que le chargeur de classes du noeud racine référence les classes du noeud racine et des classes par défaut. 5. Procédé selon la revendication 1, caractérisé en ce que ladite arborescence respecte l'héritage entre classes. 6. Architecture pour le chargement dynamique de classes dans une machine virtuelle d'un système informatique comportant un système de stockage de données en arborescence, caractérisée en ce qu'elle comprend une pluralité de fichiers de classes organisés dans les noeuds de l'arborescence du système de stockage et une pluralité de chargeurs de classes correspondant chacun à un noeud contenant au moins un fichier de classes, lesdits chargeurs de classes référençant les classes du noeud correspondant et les classes du noeud parent. 7. Architecture selon la revendication précédente, caractérisée en ce que lesdits chargeurs de classes créés référencent chacun les classes du chargeur de classes de leur noeud parent. 8. Architecture selon la revendication précédente, caractérisée en ce que lesdits chargeurs de classes sont organisés selon une arborescence mappée sur ladite arborescence des noeuds du système de stockage. 9. Architecture selon la revendication 6, caractérisée en ce qu'elle comporte au moins deux classes portant le même nom dans deux noeuds différents ayant un même noeud parent. 10. Architecture selon la revendication 6, caractérisée en ce que ladite arborescence respecte l'héritage entre classes.