Flux RSS d'opikanoba.org

Sur l’interopérabilité, l’architecture et les systèmes d’informations de santé


Billets de la catégorie ‘java’

Jython : Java et Python

JPython est né d’une volonté d’utiliser les technologies Java avec un langage simple et puissant : Python. L’interpréteur python a donc été réécrit en Java pour permettre le mélange entre les classes du jdk et l’intrépeteur python au sein de la même machine virtuelle Java. Suite à des problèmes de license déténue par le CNRI (qui a vu la naissance de Python et de JPython), un nouveau nom a été donné à ce projet : Jython.

jython
Jython 2 est une version plus mature, qui subit un processus de développement plus intense que celui de JPython.

Jython permet de :

  • compiler dynamiquement du python en bytecode Java
  • hériter des classes Java en Jython
  • compiler statiquement (création d’applets, servlets, beans…)
  • utiliser la syntaxe et les modules python dans les programmes Java
  • avoir un interpréteur python manipulant des objets Java
  • Jython est certifié 100% Pure Java (portabilité assurée)

La procédure d’installation de Jython 2 n’a plus rien à voir avec celle de son ancêtre JPython 1.1. Elle est en effet vraiment trés simple. Pour ceux qui désirent travailler avec JPython 1.1, il faut non seulement installer JPython mais aussi l’errata de Finn Bock permettant de fixer pas mal de petites défaillances (voir liens). Cela dit, il n’y a pas vraiment de raison d’utiliser cette dernière, d’autant plus que la compatibilité ascendante est assurée.

Expérimentation de Jython

Voici un programme simple qui, décliné en plusieurs étapes permet de parcourir les possibilités d’utilisation du couple java/python. L’objet du programme est de retrouver des fichiers dans une arborescence, en utilisant les expressions régulières pour spécifier les noms de fichier.

 Le moteur de recherche de ces fichiers est écrit en python, et cela pour :

  • la faciliter d’écriture
  • bénéficier de la puissance des expressions régulières, module fournit dans la distribution python

Par exemple, pour trouver les fichiers python contenant dans le nom ‘mllib’ et étant suffixés par ‘py’ ou ‘pyc’ contenus dans le répertoire lib de la distribution python, en utilisant l’interpréteur python :

Python 2.0 (#2, Oct 30 2000, 14:29:42)
[GCC 2.8.1] on sunos5
Type “copyright”, “credits” or “license” for more information.
>>> import pyFind
>>> finder=pyFind.FileFind()
>>> finder.setPath(”/users/public_w3p/share/python/Python-2.0/lib”)
>>> finder.setExprFile(”[/].*?mllib[.](py|pyc)$”)
>>> finder.process()
>>> for elem in finder.getFoundFiles():
…     print elem
…
/users/public_w3p/share/python/Python-2.0/lib/python2.0/htmllib.py
/users/public_w3p/share/python/Python-2.0/lib/python2.0/sgmllib.py
/users/public_w3p/share/python/Python-2.0/lib/python2.0/xmllib.py
/users/public_w3p/share/python/Python-2.0/lib/python2.0/htmllib.pyc
/users/public_w3p/share/python/Python-2.0/lib/python2.0/sgmllib.pyc
/users/public_w3p/share/python/Python-2.0/lib/python2.0/xmllib.pyc
/users/public_w3p/share/python/Python-2.0/lib/python2.0/test/test_xmllib.py
/users/public_w3p/share/python/Python-2.0/lib/python2.0/test/test_xmllib.pyc
>>>

Une couche graphique

Pour rendre le moteur de recherche disponible de façon plus conviviale, une interface graphique est rajoutée. Pour cela, l’utilisation de Jython permet d’utiliser

  • un composant python existant
  • les librairies Java/Swing existantes

Jython sert alors de liant entre ces différentes technologies.

interface de FindGui

En plus de la présentation graphique, on peut rajouter la possibilité d’exécuter une action en double-cliquant sur un élément de la ul (classiquement une action d’édition ou de suppression).

Il y a trois (au moins) façons de réaliser ce programme. Les trois étapes décrites par la suite représentent une évolution du même programme depuis une approche 100% Java jusqu’à l’approche 100% Jython.

Pour chaque étape, le composant de recherche python décrit plus haut est utilisé, et :

  1. 100% du GUI en Java
  2. les composants graphiques adaptés de swing en Java, le modèle de données en Java, l’application graphique en Jython
  3. 100% du GUI en Jython

Etape 1 : Java utilise Python

Cet exemple illustre l’utilisation de l’interpréteur python au travers du code Java. Le but ici est d’utiliser le composant de recherche écrit en python dans du code Java. Le programme étant assez simple, voici un diagramme de classe :

Etape 1

Le package dont le rôle de contrôleur devrait faire l’interface entre les données, le graphique et l’interpréteur python, a été volontairement laissé de côté afin de réaliser un exemple court et fonctionnel. Il est à compléter.

Main
La classe Main représente juste le point de départ de l’application
FindGui
Le package contient la classe de l’interface graphique: une JFrame spécialisée. Elle recoit les évenements provenant de l’utilisateur, pilote l’interpréteur python, remplit le modèle de données, exécute ce qui doit l’être lors d’un double-clique (en somme GUI + contrôleur).
FindData
Le package contient la classe gérant les données issues de la recherche.
SwingAdapter
Le package contient les adaptations faites d’après Swing pour obtenir le rendu voulu. En particulier, la gestion du double-clique et la façon d’afficher chaque élément de la liste (en deux couleurs). Dans les autres exemples, tous ces services sont réalisés par du code Jython en utilisant la dérivation d’objets Java.

Le diagramme suivant représente l’organisation en terme de classes :

find class

Utilisation de l’interpréteur

Pour utiliser le composant de recherche python défini dans le fichier (module) pyFind.py, et plus précisement la classe FileFind, il faut récupérer une instance de celle-ci.

Ceci se réalise par plusieurs étapes simples :

importation du module
La classe org.python.core.imp est utilisée pour réaliser l’importation du modulePyObject
findMod = imp.importName("pyFind", true);
création d’une instance
Une instance est créée (par réflexion) de la classe FileFind. Elle est représentée par un PyObject (org.python.core). C’est sur cette instance qu’il faut invoquer des méthodes.
PyObject findClass = findMod.__getattr__("FileFind");
findInstance = findClass.__call__();
passage de paramètres, appel de méthodes
Il suffit d’invoquer une méthode (premier argument) sur l’instance précédemment créée en passant les bons paramètres. Les types de base sont définis dans le package org.python.core. Une chaine de caractères passée comme paramètre est un PyString. Un entier est un PyInteger, un entier long un PyLong, etc…
PyObject res;
// def setPath(self,p):
res = findInstance.invoke("setPath",new PyString(whereText.getText()));
// def setExprFile(self,r,simplified)
res = findInstance.invoke("setExprFile",new PyString(whatText.getText()));
// def process(self):
res = findInstance.invoke("process");
récupération du résultat
Pour retrouver les différentes valeurs résultant de la recherche et stocker dans un tableau python, il suffit d’itérer sur cette liste et les insérer dans le modèle de données Java. Chaque élément est récupéré dans un PyObject, qui fournit la méthode toString.
PyObject item;
for (int i = 0; (item = res.__finditem__(i)) != null; i++) {
dataModel.addElement(item.toString());
}

Distribution

Les fichiers sont regroupés dans des archives, format zip et tarball. Les sources sont sous licence GPL. Le makefile fournit permet de compiler le code java et de lancer l’execution. Les possibilites sont compile,clean, exec. Le ‘make’ sans argument permet de tout enchainer.

make compile
make exec
ou
make

Téléchargement :

Etape 2 : 50/50 Java/Jython

Cette étape permet d’écrire l’application graphique en Jython et non plus en Java. Il s’agit ici de modifier la classe FindGui sans pour autant changer tous les packages.

Le but est ainsi de démontrer qu’il est possible de créér une classe Python dérivant de classe(s) Java, soit par extension, soit par implémentation. Cette classe Python utilise alors des classes Java.

Modele de Find

Migration vers Jython

La syntaxe Python étant plus simple et non typée, le code s’en trouve allégé (un des nombreux avantages du langage Python). Les principales différences sont évoquées ci dessous.

Le déclaration de la fenêtre principale devient :

class FindGui(JFrame, ActionListener):

à la place de :

public class FindGui extends JFrame
          implements ActionListener

La déclaration du constructeur (nommé __init__)

def __init__(self,title):

à la place de :

public FindGui(String title) {

A chaque déclaration d’une méthode Python, il faut passer comme premier argument l’objet lui même, celui ci est représenté par “self” (équivalent au “this” Java). Pour appeler le constructeur de la super classe, il faut explicitement le nommer comme n’importe quel autre appel :

JFrame.__init__(self,title, visible=1)

à la place de :

super(title);

En python, et à fortiori en Jython, les variables membres n’ont pas besoin d’être déclarées. Néanmoins, il est possible de le faire, tout dépend de la façon de programmer.

Les variables membres, au même titre que les méthodes, sont stockées dans un dictionnaire interne de la classe. Donc à chaque fois que l’on fait référence à un self.toto, si dans le dictionnaire, la clé ‘toto’ n’existe pas et qu’il s’agit d’une affectation, une nouvelle clé est insérée ainsi que la valeur associée. Si la valeur n’existe pas dans le dictionnaire et que l’on veut un accès en consultation, une exception est levée.

En prenant deux variables membres au hasard, l’une est déclarée dans le constructeur et affecté à rien (None), l’autre n’est déclarée que lors de l’instanciation du JButton.

self.foundlist = None
self.searchButton = swing.JButton("Recherche")

En Java, il y a d’abord la déclaration, puis l’instanciation (bien que l’on puisse faire les temps en une seule étape) :

// déclaration private JList foundlist;
private JButton searchButton;
// création des objets
foundlist = new JList(dataModel);
searchButton = new JButton("Recherche");

Distribution

Les fichiers sont regroupés dans des archives au format tarball ou zip. Les sources sont sous licence GPL.
Le makefile fournit permet de compiler le code java, de créer un jar, et de lancer l’exécution. Les possibilités sont compile,jar,clean, et exec. Le ‘make’ sans argument permet de tout enchaîner.

Dans cette version, comme il y a du java à compiler, il faut mettre le bytecode dans un fichier jar pour que l’interpreteur jpython puisse trouver les classes.

make compile
make jar
make exec

ou

make

Téléchargement :

Etape 3 : Jython pilote java

Cette version est certainement une des plus intéresssantes, puisque l’ensemble du code écrit est du code Jython. Cela signifie que Jython est utilisé comme glue. Il permet de faire fonctionner les composants Java et/ou Python ensemble sans pour cela avoir besoin de créer un seul fichier à compiler. D’ailleurs, dans les sources, il n’existe plus de Makefile, seul l’interpréteur Jython est nécessaire.

Distribution

Les fichiers sont regroupés dans des archives au format tarball ou zip. Les sources sont sous licence GPL.
Pour lancer l’interface, il suffit de faire :

  cd step3
  jpython findgui.py

Téléchargement :

Java SE 6 met l’accent sur les services Web

Alors que Tiger - Java SE 5 - est disponible depuis peu et que Sun travaille sur GlassFish - Java EE 5 -, la planification des futurs composants de Mustang - Java SE 6 - est déjà disponible. Il s’agit bien sûr que d’une vue prévisionnelle, puisque sa sortie est prévue mi 2006, mais jetons d’ores et déjà un oeil sur les nouveautés, liées à XML, de cette future plate-forme.

Après avoir intégré de nombreuses technologies XML de bases dans les actuelles machines virtuelles Java, Mustang fait le choix de l’intégration des technologies relatives aux services web. Celles-ci, présentes du coté serveur (Java EE), arrivent du côté des applications clientes (Java SE). Ainsi, JAX-WS 2.0 (Java API for XML Web Services) et JAXB 2.0 (Java Architecture for XML Binding) font leur entrée dans Java 6.

Il s’agit là des deux évolutions majeures. Notons cependant que JAXP - Java API for XML Processing - passera en version 1.4, avec l’intégration de l’API d’analyse syntaxique StAX (JSR 173). Celui-ci est déjà inclus dans le WSDP 1.6 - Web Services Developer Pack. La signature numérique des documents XML - JSR 105, XML Digital Signature API - sera également intégré à Mustang.

JAX-WS 2.0 : Java API for XML Web Services
JAX-WS est la nouvelle appellation de JAX-RPC (Java API for XML Based RPC). En effet, JAX-RPC ne convient plus à l’ensemble des concepts couverts. Cet acronyme donne l’impression qu’il s’agit uniquement de technologies synchrones, relatives à l’appel de procédure à distance et non aux services web. De plus l’intégration de JAXB 2.0 pose de nombreux problèmes de compatibilité avec JAX-RPC 1.1. C’est ainsi l’occasion pour Sun de repenser, mettre à jour, améliorer et surtout rationaliser cette brique logicielle en utilisant les dernières nouveautés du langage lui-même, ainsi que les technologies développées en parallèle dans d’autres groupes de travail.

La volonté du groupe de travail est de supprimer les développements spécifiques - indispensables dans les versions antérieures, en raison de contraintes de calendrier - et de s’appuyer sur des composants éprouvés (JAXB) ou des standards (WS-*). Ainsi, si JAX-RPC 1.x utilise sa propre méthode de correspondance entre données XML et objets Java, JAX-WS 2 s’appuie désormais sur JAXB 2.0. JAX-WS 2.0 utilise également les nouvelles facilités du langage Java, introduites dans la version 5. Les annotations (JSR 175) utilisent des concepts, inhérents au langage Java et aux outils associés, qui facilitent le développement de scénarios classiques côté client mais également côté serveur. Elles déchargent le développeur de l’ajout d’informations jusqu’à lors nécessaires pour transformer un service classique en un service web. Certaines méta-données ont d’ailleurs été spécialement définies pour le compte des services web (JSR 181). Elles permettent de remplacer la technique de correspondance Java - WSDL, en annotant directement le code Java. Doug Kohlert - responsable technique de JAX-RPC - estime que ces nouvelles facilités permettent d’économiser une somme importante de code (en taille et en nombre) allant jusqu’à 85% d’économie. Ces facilités sont complétées par la JSR 109 - Implementing Enterprise Web Services - qui permet de déployer, de gérer et d’accéder à un service web par le biais d’un serveur d’application Java. Cette JSR couvre les modèles de programmation côté client - accéder à des services comme des objets distants traditionnels - mais aussi côté serveur - comment les services web peuvent être mis en oeuvre par une servlet ou un EJB.

Elle aborde également la façon de déployer ces services dans un serveur d’application. Pour compléter le tout, la JSR 183 - Web Services Message Security APIs - utilisée par JAX-WS aborde la sécurité des échanges de message SOAP.

La nouvelle mouture de JAX-WS est bien sûr l’occasion d’intégrer les dernières versions des standards utilisés. SOAP 1.2 est désormais supporté étant donné son statut de recommandation. Cependant, le support de SOAP 1.1, largement déployé, est assuré. WSDL 2.0 n’est pas encore une recommandation mais le sera certainement durant la cycle de vie de cette JSR, qui continuera d’offrir le support de WSDL 1.1. WS-I Basic Profile 1.1 supplante la version 1.0, actuellement supportée par JAX-RPC 1.1. Enfin, JAX-WS permet d’utiliser de façon optionnelle les récentes spécifications du W3C liées à l’optimisation de la transmission de données binaires dans des messages SOAP : MTOM/XOP (Message Transmission and Optimization Mechanism/ XML Binary Optimized Packaging).

Par ailleurs, JAX-WS 2.0 ajoute ou améliore certains concepts connexes. Une opération WSDL pourra désormais être asynchrone. Des mécanismes de gestionnaire d’événement (handler) et de consultation asynchrone de la réponse à une invocation (polling) sont mis en place dans cette JSR. JAX-WS 2.0 améliore aussi le développement de gestionnaires - logiques ou SOAP - permettant de suivre les messages échangés - leur contexte, leur sens de circulation - et d’accéder aux informations présentes dans les messages ou en-têtes. Autre point intéressant, la possibilité de gérer des versions d’un service web apparaît. Actuellement, l’évolution d’un service web est coûteux et délicat, cette JSR tente de faciliter l’évolution et le déploiement d’une nouvelle version d’un service web. Enfin, JAX-WS accentue également la séparation entre les données transportées (XML) et la couche transport, permettant ainsi de faire des invocations de services sur un protocole différent de HTTP. De plus, la gestion de session, liée à HTTP dans JAX-RPC 1.1, pourra se faire grâce à des informations présentes dans les messages SOAP.

Tant de changements impliquent des choix. Et JAX-WS en fait de nombreux. La correspondance données-XML est déléguée à JAXB. Il n’est pas prévu de fournir une possibilité évoluée de changer la technologie sous-jacente de “binding”. Cependant JAXB pourra être désactivé ponctuellement pour faire place à une technologie alternative. Contrairement à JAX-RPC 1.x, cette nouvelle version ne prendra pas en charge l’encodage SOAP 1.2. Cet usage est déprécié par WS-I Basic profile. Même si JAX-WS 2.0 offre un certain niveau de compatibilité ascendante, le fonctionnement du code issu de la génération de JAX-RPC 1.x n’est pas assuré. Il est donc nécessaire de modifier le code afin de s’insérer dans ce nouveau cadre. Enfin JAX-WS s’appuie sur de nombreuses fonctionnalités de Java 5 - annotation (JSR 175), génériques (JSR 14), types énumérés (JSR 201) … - le support des machines virtuelles antérieures ne sera donc pas pris en compte.

JAXB 2.0 : Java Architecture for XML Binding
JAXB 2.0 est l’évolution logique de la version 1.0, définie par la JSR 31. JAXB 2.0 supporte désormais l’ensemble des fonctionnalités définies dans XML Schema, ce qui n’avait pas été possible pour des raisons de calendrier dans la version 1 de JAXB. Là où JAXB 1.0 offrait une façon de partir du schéma pour arriver aux classes Java, JAXB 2.0 ajoute la possibilité d’avoir une correspondance bidirectionnelle. Par ailleurs, il est maintenant possible d’avoir une correspondance limitée à un fragment de document XML.

Alors que JAXB 1 n’assurait pas un processus invariable d’aller-retour entre XML et Java - un bean Java transformé en XML qui est de nouveau transformé en bean Java. JAXB 2.0 impose que ces transformations assurent l’invariabilité des données (Java et XML). La prise en compte d’un XML incorrect, aspect non-traité dans JAXB 1, sera définie. Un effort sur la portabilité des classes annotées permettra de conserver des classes issues d’une mise en oeuvre même si celle-ci est amenée à changer. Les classes JAXB 1 issues du schéma XML devaient être compatibles au niveau du code avec les implémentations JAXB 1, celles de JAXB 2 devront également être compatibles au niveau du bytecode. Enfin, l’utilisation des annotations des javabeans existants devrait permettre aux bibliothèques JAXB de générer automatiquement les objets responsables du chargement et de la sauvegarde de ces beans en XML.

A l’instar de JAX-WS 2.0, JAXB 2.0 fait également des choix. La JSR 222 utilise ainsi pleinement les facilités du langage Java 5, avec les conséquences de compatibilité avec les JDK antérieurs que cela engendre. Du côté des grammaires, seuls les schémas XML sont supportés. JAXB 2.0 part du principe qu’il est simple de convertir une DTD en Schéma - par l’intermédiaire de nombreux outils. La validation à la volée des classes java par rapport à des contraintes exprimées dans un schéma, supportée dans JAXB 1, n’est plus d’actualité dans JAXB 2.0. Enfin, à l’image de JAX-WS, JAXB n’utilise plus l’encodage SOAP, qui est remplacé par WS-I Basic Profile.

Cependant, à l’heure actuelle, il reste des points à préciser. JAXB se propose d’explorer les possibilités d’évolution de schémas, tant dans le domaine des applications centrées sur les données (services web) que dans le domaine des applications centrées sur les documents. JAXB 2.0 doit, par ailleurs, clarifier l’intégration et les relations avec StAX (JSR 173).

Sun a affiché très clairement, lors de la présentation des orientations futures de la plate-forme Java à JavaOne, sa volonté de renforcer la pile des technologies XML présentes dans la machine virtuelle et de faciliter le développement des services web. Graham Hamilton évoque que la version suivante (java 7 ou dolphin) poussera plus loin encore l’utilisation des services web en les mariant avec JMX pour offrir de l’administration à distance par le biais de services web. Il évoque également une possible intégration de XML au niveau même du langage Java. Cependant, cela reste à l’état de projet et ne verra pas le jour avant 2008.

Autres articles :

Voir aussi :

Liste des JSR relatives à XML et aux services web :

Hibernate 3.0 ajoute la persistance des documents XML

La nouvelle version d’Hibernate, passé sous le giron de JBoss, permet de prendre en compte, grâce à DOM4j, le traitement et la transformation des documents XML pour rendre leurs données facilement persistantes.

Hibernate est un framework Java de persistance qui permet de faire correspondre des tables de base de données relationnelle avec des objets java simples (POJO ou «Plain Old Java Object»). Une fois la correspondance entre les deux mondes définie, le programme Java peut manipuler toutes les données en utilisant que des JavaBean, masquant alors totalement la base de données sous-jacente et ses spécificités. Le framework assure le remplissage de ces objets et la mise à jour de la base en se basant sur leur contenu. Avant la sortie de la version 3 de ce framework, XML constituait déjà le format de description de la correspondance entre les tables relationnelles et les classes Java.

Hibernate 3 franchit un pas supplémentaire. De la même façon que les POJO permettent de manipuler des objets dont les données sont stockées dans une base de données, cette nouvelle fonctionnalité permet de s’affranchir des solutions XML propriétaires. En effet, chaque fournisseur, se devant de se préoccuper de l’importation/exportation des données XML, fournit une solution qui lui est propre à défaut de se baser sur un standard.

Le framework Hibernate permet d’obtenir une représentation XML du résultat d’une requête. Il permet aussi de rendre persistant, c’est-à-dire d’insérer ou de mettre à jour des données dans la base de données depuis des fragments de document XML de façon très simple et similaire à la manipulation de POJO.

Pour illustrer ces ajouts, prenons l’exemple (extrêmement simple) d’une table contenant une liste de tâches à faire, les fameux TODO. Voici une définition SQL possible de la table TODO_TASK:

CREATE TABLE TODO_TASK (
  TODOID INTEGER NOT NULL PRIMARY KEY,
  SUMMARY VARCHAR(45) NOT NULL ,
  DESCRIPTION VARCHAR(45),
  PRIORITY INTEGER,
  DONE TIMESTAMP);

Hibernate permet non seulement de définir une correspondance entre cette table et un bean Java, mais également entre la table et un document XML. Dans cet exemple, le structure des données XML sera la suivante :

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="bean">
  <class name="TodoTask"
         table="todo_task" node="todo">
    <id name="todoid" node="@id"/>
    <property name="summary" not-null="true" node="sum"/>
    <property name="description" node="descr"/>    <property name="priority" node="@priority"/>
<property name="doneDate" column="done"/>
  </class>
</hibernate-mapping>

Ainsi, Hibernate fera une correspondance automatique entre, par exemple, le contenu du noeud sum, fils du noeud todo et la colonne summary. Par ailleurs, la colonne done sera disponible dans les beans Java (via la propriété doneDate), mais ne le sera pas dans les fragments XML.

La gestion du XML est assurée par DOM4j. Cette librairie très complète offre le support de DOM, SAX et JAXP mais également des requêtes XPath et de XSLT. Ainsi un document provenant au programme sous une forme SOAP par exemple, peut être transformé dans le format XML pivot par le biais d’une transformation XSLT avant d’être pris en compte par Hibernate. Il peut alors être délivré sous une autre forme, comme un format de sortie SVG, par une autre transformation XSLT. L’association DOM4j/Hibernate permet donc de définir le format XML qui sera utilisé par le métier et délivre un environnement complet de transformation et de traitement de l’information.

Le bout de code Java suivant montre comment, à partir d’un fichier XML, contenant une liste de tâches, hibernate met à jour la base de données relationnelle :

SAXReader sr=new SAXReader(false);
Document doc=null;

try {
  doc = sr.read(ClassLoader.getSystemClassLoader().
                getResourceAsStream("todo-ex.xml"));
} catch (DocumentException e} { ...} 

List todo=doc.selectNodes("//todo");

Session session = sessionFactory.openSession();

Session xmlSession = session.getSession(EntityMode.DOM4J);
Transaction tx=session.beginTransaction();

for (Iterator it=todo.iterator(); it.hasNext(); ) {
xmlSession.saveOrUpdate(”bean.TodoTask”,it.next());
}

tx.commit();

session.close();

Le document est lu grâce à un analyseur syntaxique SAX. La requète XPath permet d’obtenir une liste de tâches Todo. Puis, une session est ouverte. Elle est de type «EntityMode.DOM4J», ce qui indique au framework qu’il doit utiliser la librairie XML et que les données se trouvent dans des fragments XML et non dans des POJO. La boucle les parcourt et les fournit à la session XML qui se charge de mettre la base de données à jour. Le fait de spécifier bean.TodoTask lors de l’action sur la base, permet au framework de connaître à quelle correspondance les noeuds «todo» font référence.

De façon similaire, la consultation de la base peut se faire ainsi :

Element root=docFactory.createElement("todolist");
Document doc=docFactory.createDocument(root) ; Session session = sessionFactory.openSession();

Session xmlSession = session.getSession(EntityMode.DOM4J);
List res=(List) xmlSession.createQuery(”from TodoTask”).list();

for (int i=0; i<res.size(); i++){
  Element elt = (Element) res.get(i);
  root.add(elt);
}

session.close();

Un document hôte est créé de façon classique. La racine accueillera les différents éléments issus du résultat de la requête. Pour afficher le document XML, DOM4j fournit une classe XMLWriter :

XMLWriter xw;

try {
  xw = new XMLWriter(System.out, new OutputFormat("  ",true));
  xw.write(doc);
} catch (Exception e) {...}

Avec cette nouvelle version, Hibernate facilite non seulement la persistance en offrant une couche d’abstraction par rapport à la base de données, mais il permet désormais d’intégrer des données provenant de documents XML, de messages SOAP, de messages JMS, etc… Même si Hibernate n’a pas vocation à devenir un framework spécialiste du XML, cette extension au monde XML renforce les possibilités offertes par le framework pour assurer un découplage des objets métier avec les détails de mise en oeuvre du stockage en base de données relationnelle.

voir aussi :

Hibernate 3.0 ajoute la persistance des documents XML - fichiers d’exemple

Le test suivant se propose de tester la nouvelle fonctionnalité de mapping XML d’Hibernate. Voir l’article associé, pour plus d’informations.

Le projet se compose de plusieurs répertoires :

  • cfg : fichiers de configuration d’Hibernate, de propriétés (hibernate et log) et script pour la création de la table de la base de données
  • res : fichier XML de données, qui seront insérées dans la base
  • src : sources Java du test
  • build.xml: fichier Ant de compilation, exécution du test

Initialisation de la base

La base de données utilisée pour ce test, HSQLdb, est 100% Java et très simple à installer. Après l’avoir téléchargé et décrompressée dans un répertoire, il suffit de lancer le serveur et de provisionner la table. Pour plus d’informations, consulter la note à ce sujet.

java -cp lib/hsqldb.jar org.hsqldb.Server

Une fois le serveur démarré, l’insertion se fait à l’aide du DatabaseManager, par lecture et exécution du script SQL (create_todo.sql) suivant :

DROP TABLE TODO_TASK if EXISTS;

CREATE TABLE TODO_TASK (
  TODOID INTEGER NOT NULL PRIMARY KEY,
  SUMMARY VARCHAR(45) NOT NULL ,
  DESCRIPTION VARCHAR(45),
  PRIORITY INTEGER,
  DONE TIMESTAMP);

INSERT INTO TODO_TASK VALUES(001,'faire le cafe',
  'Prendre 7 volumes deau et 7 volumes de cafe', 1, CURRENT_DATE);

Ce script se situe dans le répertoire cfg du projet.

Lancement du test

Le test se lance grâce au script Ant. Il compile les classes et lance le programme Java MappingXML qui réalise 3 opérations :

  • modification de données via la manipulation d’un POJO (scénario classique)
  • lecture d’un fichier XML et insertion de ses données dans la base en utilisant les facilités d’Hibernate
  • consultation de la base, et génération d’un fichier de résultat au format XML
> ant

...
     [java] <?xml version=”1.0″ encoding=”UTF-8″?>

     [java] <todolist>
     [java]   <todo id=”1″ priority=”1″>
     [java]     <sum>faire le cafe</sum>

     [java]     <descr>Prendre 7 volumes deau et 7 volumes de cafe</descr>
     [java]     <doneDate>2005-05-02 00:00:00</doneDate>
     [java]   </todo>
     [java]   <todo id=”2″ priority=”2″>

     [java]     <sum>Faire une pause</sum>
     [java]     <descr>Allez a la cafet, prendre un cafe avec Bob</descr>
     [java]   </todo>
     [java]   <todo id=”4″ priority=”2″>

     [java]     <sum>installer eclipse</sum>
     [java]     <descr>une nouvelle version est disponible</descr>
     [java]   </todo>
     [java]   <todo id=”5″ priority=”1″>

     [java]     <sum>redemarrer le serveur</sum>
     [java]     <descr>une mise a jour du serveur tartenpion necessite un redemarrage</descr>
     [java]   </todo>
     [java]   <todo id=”6″ priority=”3″>

     [java]     <sum>documentation du product</sum>
     [java]     <descr>faire une documentation complete de notre super produit</descr>
     [java]   </todo>
     [java] </todolist>

all:

BUILD SUCCESSFUL

Le bean Java utilisé est bean.TodoTask et son fichier de correspondance Hibernate, Todo.hbm.xml, se trouve dans le répertoire cfg.

Fichiers

En résumé, voici les fichiers utilisés pour ce test :

 |   build.xml
 |
 +—- cfg
 |       create_todo.sql
 |       hibernate.properties
 |       log.properties
 |       Todo.hbm.xml
 |
 +—- res
 |       todo-ex.xml
 |
 \—- src
       |   MappingXML.java
       |
       \—- bean
                TodoTask.java

XOM : XML Object Model 1.0

XML est définitivement une affaire de personnalités ! Après Michael Kay et son processeur Saxon, Tim Bray et genX, Daniel Veillard et libxml, Elliotte Rusty Harold annonce un nouveau parseur Java XML : XOM 1.0.

Elliotte Rusty Harold est un expert des technologies XML. Auteur de plusieurs ouvrages sur le sujet, il s’est penché de près sur les avantages et les inconvénients des différentes API permettant de manipuler des documents XML. Sa conclusion est assez sévère : les API XML (comme SAX ou DOM) ont été écrites par des programmeurs experts qui découvraient XML. Ainsi le produit de leurs travaux n’était pas, toujours selon Elliotte Rusty Harold, d’une grande qualité. Cette arrogance, l’auteur la justifie par le fait qu’elle est construite sur une forte expérience du domaine et sur son expertise démontrée au fil des ans.

Ainsi, il a passé en revue les quatre types d’API : événementielles type push (comme SAX), événementielles type pull (comme XMLPull ou StAX), celles à base de représentation arborescente (comme DOM, JDOM, etc) et enfin celles dites de «Data Binding» (comme Castor ou JAXB). De toutes ces observations, Elliotte Rusty Harold en a tiré une conclusion. Toutes présentent suffisamment d’inconvénients pour laisser la place à une nouvelle qui tenterait d’être plus pertinente. Les objectifs qu’il fixe pour XOM sont prometteurs !

  • produire du XML correct. XOM est une implémentation de XML 1.0 focalisée sur l’impossibilité de produire du XML mal formé,
  • facile à utiliser grâce à une API intuitive évitant de consulter fréquemment la documentation,
  • facile à apprendre : un seul paquetage nu.xom pour toutes les fonctionnalités principales. Tout ce qui se trouve en dehors est optionnel et peut-être ignoré par un utilisateur débutant. XOM ne doit pas surprendre, les méthodes ont des noms explicites. Si XOM surprend, la surprise doit venir de XML lui-même et non de cette mise en oeuvre Java,
  • rapidité d’exécution et taille en mémoire acceptable : ces aspects ne sont clairement pas des priorités pour l’auteur qui préfère se concentrer sur les points précédents, pour offrir un ensemble stable qu’il pourra optimiser par la suite.

Pour construire cette API, Elliotte Rusty Harold a conjugué principes de conception objet, principes liés à Java et à la nature intrinsèque de XML. Ainsi les classes (il n’y a pas d’interfaces, l’auteur les jugeant inadaptées pour une librairie efficace) possèdent des pré-conditions et des invariants sur lesquels l’utilisateur ne peut passer outre. Seules les méthodes ne mettant pas en péril la conformité vis-à-vis de XML peuvent être surchargées. Et à l’instar des réflexions sur DOM Traversal, XOM n’implémente pas non plus le design pattern Visiteur (des données d’une classe pouvant être manipulées de l’extérieur sans contrôle). Car l’obsession de l’auteur est bien d’assurer l’impossibilité pour un utilisateur de produire un document XML mal formé.

Contrairement aux idées reçues, XOM n’a rien à voir avec JDOM. L’auteur a participé au développement de ce dernier et reconnaît avoir beaucoup appris techniquement. Cependant, en désaccord avec de nombreux principes de conception dans JDOM, il hésita à s’en servir de base pour en créer une nouvelle version. Finalement, il abandonna l’idée et repartit d’une feuille blanche. Si XOM est écrit en Java, l’API se distingue donc de JDOM ou de DOM4j en laissant certaines fonctionnalités inhérentes au langage Java volontairement de côté. Ainsi les classes sont pas «serializable» car XML est lui-même un format offrant cette fonctionnalité et est nettement plus inter-opérable que celui de la «serialisation» java. La notion de classe «Cloneable» est également laissée de côté au profit du copie constructeur classique. Les listes de noeuds utilisent une représentation interne à XOM et ne se basent pas sur les «List» Java, jugées pas assez performantes (notamment vis-à-vis des threads). Enfin, les principes de programmation objet sont respectés puisque les accesseurs en écriture ne retourne pas l’objet lui-même mais le type «void». Ce qui contraste avec les facilités de JDOM, qui permet notamment d’écrire, en une seule ligne

new Element(”html”).appendChild(new Element(”head”))

Les fonctionnalités de XOM 1.0 sont les suivantes :

  • libre, pure Java
  • un nouveau modèle de document XML 1.0. XOM ne supporte pas XML 1.1 (délibérément), qualifié d’abomination par l’auteur
  • support de XInclude
  • support de XML canonique (traduction française)
  • des ponts vers SAX et DOM
  • support de TrAX pour les transformations XSLT

Elliote Rusty Harold prévoit les améliorations suivantes :

Pour faciliter son utilisation, l’auteur fournit un tutorial. Par ailleurs, l’absence du support de XPath et le besoin de faire des requêtes sur les documents ont poussé Wolfgang Hoschek à développer Nux, une extension permettant d’utiliser XQuery (et donc XPath 2.0) avec XOM. Cette mise en oeuvre utilise Saxon-B comme moteur de requêtes.

Si XOM est un logiciel libre, il n’en reste pas moins qu’il est l’oeuvre d’un développeur déterminé à garder le contrôle de son oeuvre. Elliotte Rusty Harold insiste beaucoup sur ce point. Même s’il est ouvert aux critiques et suggestions, il proclame XOM comme une république bananière : «XOM is a more-or-less benevolent dictatorship, not a democracy. I am the only committer. This is my API, and it reflects my thoughts and desires». Cela a au moins le mérite d’être très clair ! XOM est disponible depuis le site xom.nu sous licence LGPL.

Autres articles :

DOM 3 : Interroger une implémentation indirectement…

La recommandation DOM Niveau 3 introduit un mécanisme permettant d’agir selon les réponses d’une implémentation. Définie au niveau de l’interface Node, la méthode isSupported() répond true ou false selon la fonctionnalité demandée (en fait un couple (fonctionnalité, version)). La construction de l’évaluateur XPath se fera soit par retypage de l’objet Document (si la réponse à isSupported("XPath", "3.0") est vraie), soit par obtention d’un objet via un appel à getFeature("XPath", "3.0") puis retypage (si la réponse à isSupported("+XPath", "3.0") est vraie. Attention le signe + devant la chaîne “XPath” est très significatif). Toutes ces opérations se déroulent au niveau de l’interface, il n’y a donc aucun lien avec l’implémentation.

Recherche rapide d’informations grâce à XPath

Avec l’avènement de XML, de nombreuses informations se retrouvent dans des fichiers au format texte structuré de façon arborescente, qu’il s’agisse de fichiers de configuration, de données à proprement parler ou de résultats de requête. Si la structure XML apporte lisibilité et robustesse, le problème d’accès à l’information demeure. Nous allons voir comment XPath y apporte une réponse vraiment puissante.

Magazine Login: n°120, septembre 2004 - Frédéric Laurent

De nombreuses techniques permettent de retrouver une valeur noyée au plus profond d’un arbre XML, mais elles ne sont pas toutes aisées à mettre en oeuvre. XPath, langage non XML, spécifié par le W3C, permet de déclarer de façon concise l’information recherchée. Le travail du programmeur est allégé en terme de code mais aussi de maintenance. Il peut en effet se concentrer uniquement sur la formulation de sa requête (le quoi) et non sur la façon d’y accéder (le comment).

Pour illustrer l’article, nous définissons deux types d’information à retrouver dans deux fichiers XML différents. Tout d’abord, nous souhaitons connaître la liste des servlets déclarées dans un fichier de configuration d’une application web J2EE (le fichier web.xml). Les noms de servlet sont définis par la balise <servlet-name>. Le fichier ne contient pas d’espace de noms. L’expression sera donc très simple. Le second exemple, en revanche, est plus complexe. A partir du fichier d’actualités du W3C (au format RSS 1.0, c’est à dire avec le support des espaces de noms), nous souhaitons connaître les annonces des nouveaux documents de travail. Ce qui revient à localiser le texte des balises <description> dont les balises adjacentes <title> contiennent le mot “Draft”. Cet exemple utilise donc les concepts d’axe XPath, d’espace de noms et de fonction XPath.

Différents types d’accès

Plusieurs techniques sont envisageables pour accéder à une information contenue dans un fichier XML. On peut citer la recherche de texte à l’aide des expressions régulières, l’API SAX, le modèle DOM, les librairies de correspondance (désigné par le terme anglais “binding”) XML vers des objets de n’importe quel langage de programmation, et bien sûr XPath.

Utilisation des expressions régulières

Un fichier XML est un fichier texte. Pendant longtemps, l’utilisation des expressions régulières a fait le bonheur des développeurs devant trouver des données dans ces fichiers texte. Cette technique est donc parfaitement applicable pour retrouver notre liste de servlets. En python, une première version naïve serait la suivante :

servletname="<servlet-name>(.*?)</servlet-name>"
webxml = open("WEB-INF\\web.xml").read()
print re.findall(servletname, webxml)
['invoker', 'CompressionFilterTestServlet', 'HelloWorldExample',
 'RequestInfoExample', 'RequestHeaderExample', 'RequestParamExample',
 'CookieExample', 'SessionExample', 'CompressionFilterTestServlet',
 'HelloWorldExample', 'RequestInfoExample', 'RequestHeaderExample',
 'RequestParamExample', 'CookieExample', 'SessionExample']

Pour ce cas simple, la solution semble parfaite. Cependant, il faudra penser à traiter les retours à la ligne entre la balise ouvrante et le texte à proprement dit. Le code se complexifie alors. Mais surtout comment repérer que <servlet-name>invoker</servlet-name> est déclaré ou ne l’est pas car compris entre un début et une fin de commentaire (resp. <!-- et -->) ? Complexifier encore l’expression régulière ? Ajouter du code pour contrôler cet aspect ? Faire une première lecture pour supprimer toutes les parties XML contenues dans des commentaires et travailler sur cette version épurée ? Les solutions sont multiples, mais elles présentent toutes de nombreux inconvénients. En occultant la sémantique du langage XML, le travail devient complexe et difficilement maintenable. Et que dire de notre second exemple…

Utilisation de SAX

SAX permet de répondre de façon plus intéressante que les expressions régulières car le format XML est traité de façon adaptée : les problèmes d’espaces entre balise et texte, ou de balises entre commentaires se résolvent d’eux-mêmes. Si SAX fournit un moyen rapide d’accéder à l’information puisqu’il est possible de ne prendre en compte que les données qui nous intéressent, il n’en demeure pas moins qu’il faut construire un programme pour trouver les différents noms de servlet. La classe dédiée peut être relativement simple, elle a cependant le principal inconvénient de fixer dans le programme la façon d’accéder à l’information. Si le format évolue, le programme doit être changé, recompilé, redéployé (selon le cas, et le langage).

Utilisation de DOM

L’API DOM, spécifiée par le W3C, permet également d’accéder aux informations des fichiers XML. Une fois le document lu en mémoire dans une structure de données standard, l’accès se fait par l’appel aux méthodes définies sur les classes Document, Element, Attribute… A l’image de SAX, cette solution exploite pleinement la spécificité du format XML et règle nombre de problèmes. Cependant, elle ne résout pas la dépendance entre le code du programme et le format du fichier XML.

S’il existe des alternatives à DOM, comme JDOM ou DOM4J par exemple, qui rendent le code plus concis et plus lisible, les inconvénients exposés ci-dessus persistent.

Utilisation du binding

Il s’agit d’obtenir une représentation du fichier XML sous forme de classe. L’accès est simple, cependant encore une fois, la consultation d’une information impose la génération de code (Java, Python ou autre), sa compilation éventuelle, son déploiement… Tout cela étant sujet à modification, et donc difficilement maintenable. De plus, pour accéder à la liste des noms de servlet, il faut coder explicitement l’accès par des appels à des accesseurs de la classe générée.

Utilisation de XPath

XPath : un langage pour intérroger les fichiers XML

La spécification XPath est assez simple. Peu de notions permettent de composer une expression qui localisera, dans le document XML, une simple valeur, ou un ensemble de noeuds. Une expression XPath définit …(lire la suite)

Face à tous ces problèmes de couplage fort entre le format XML et le code du programme, XPath apporte une réponse vraiment satisfaisante. La requête d’accès à l’information est la seule chose à définir. Le codage de l’affichage du résultat reste indépendant (des informations recherchées). Si la structure du fichier source XML change, seule l’expression XPath doit évoluer. Qui plus est, les instructions qui exploitent le résultat de l’évaluation sont vraiment simples. Il s’agit d’un parcours d’un ensemble de noeuds pour les résultats multiples (ensembles de noeuds, ou "node-set") ou la consultation d’une valeur. Enfin, l’utilisation de cette technologie permet également d’obtenir le résultat en tant que noeud DOM d’un document. Lui ajouter un nouveau noeud fils, un attribut ou du texte est donc une formalité. XPath ne se cantonne donc pas à la seule consultation d’information, mais fournit un véritable moyen d’accès à une partie du document XML. Libre au programmeur d’utiliser le résultat comme bon lui semble.

XPath et la gestion des espaces de noms

Lors de la formulation d’une requête XPath, chaque espace de noms doit être explicitement nommé. Chaque élément doit pouvoir être préfixé… (lire la suite)

L’apparition d’une spécification claire pour l’utilisation d’API XPath s’est faite attendre. La conséquence immédiate est le développement par chaque librairie XML de sa propre API. Ainsi pour Java, Saxon, JDOM, Xalan, DOM4j,… fournissent ce service de façon propriétaire. Le W3C progresse sur une recommandation (qui n’est encore qu’un document de travail), et les différents projets comblent peu à peu ce manque de cohérence. Nous allons voir comment accéder aux informations désirées en utilisant d’une part Saxon et d’autre part l’API standard XPath (uniquement implémentée par Xalan, à ce jour).

Le premier exemple permet de manipuler une expression XPath triviale, puisqu’il s’agit d’obtenir la valeur textuelle de tous les noeuds <servlet-name>. L’expression //servlet-name/text() convient parfaitement. Le second exemple est plus ardu. Une des expressions XPath utilisable (il est possible de fournir de nombreuses autres solutions pour accéder à la même information) est :

//dns1:description[contains(preceding-sibling::dns1:title,'Draft')]/text()

ce qui peut se traduire en français par : prendre le texte de toutes les balises <description> (dans l’espace de noms dns1) qui contiennent un noeud frère nommé <title> (dans l’espace de noms dns1) et dont le contenu contient le mot ‘Draft’.

XPath avec Saxon

Le listing 1 présente comment utiliser Saxon pour obtenir notre liste de servlets. Le programme se contente de lire un fichier XML et d’évaluer l’expression XPath. Une fois le fichier lu (depuis le système de fichiers ou depuis une URL), l’objet XPathEvaluator de l’API Saxon est créé avec la référence sur le flux XML. Il servira à évaluer les requètes. Ce service est rendu par la méthode evaluate(). Elle renvoie un objet du type Java classique [List][23] qu’il suffit de parcourir pour afficher l’ensemble des résultats. Saxon fournit pour la représentation des noeuds, une classe [NodeInfo][24], qui offre contrairement à la classe [Node][25] du W3C, une méthode getStringValue() permettant d’en avoir une représentation textuelle. L’affichage est donc grandement simplifié.

Le listing 2 correspond au second exemple. Il est plus complexe puisqu’il faut gérer les espaces de noms. Chaque couple (préfixe, URI de l’espace de noms) doit être déclaré au niveau de l’évaluateur XPath. Enfin, les espaces de noms par défaut spécifiés dans le document XML (par une déclaration xmlns="http://...") doivent également posséder un préfixe au niveau XPath. Ainsi, la constante DEFAULT_NS_PREFIX définit la valeur textuelle du préfixe à laquelle un entier, incrémenté automatiquement, est accolé. Il n’existe pas de moyen prédéfini pour collecter les espaces de noms d’un document XML. Deux solutions relativement simples sont envisageables. La première consiste à utiliser la récursivité de la structure XML et les méthodes d’accès aux informations fournies par DOM. Le parcours récursif teste tous les attributs de tous les noeuds Element afin de trouver ceux qui commencent par "xmlns". La seconde solution est basée sur l’analyse syntaxique SAX en se concentrant uniquement sur les espaces de noms. C’est cette solution qui est retenue dans notre exemple. Ainsi, avant de fournir le flux XML à l’objet [XPathEvalutor][26], il est analysé une première fois par une classe dérivant du [DefaultHandler][27] de SAX 2. Seul le signal startPrefixMapping(prefix,uri) est utilisé. Cette méthode voit passer chaque déclaration d’espace de noms, elle se charge de l’enregistrer dans un objet [StandaloneContext][28] prévu, entre autres, à cet effet dans l’API Saxon.

Utilisation de l’API XPath DOM niveau 3

Les exemples suivants se basent sur des abstractions d’API. Le but recherché est bien sûr d’être indépendant de toute implémentation, afin d’offrir une pérennité et une maintenabilité plus grandes. La première abstraction concerne la lecture du document. Les documents XML sont lus en utilisant l’API JAXP. Définie par Sun, elle permet de ne pas se préoccuper de l’analyseur syntaxique sous-jacent. L’évaluation XPath se fait en utilisant l’ensemble des classes spécifiées par le groupe de travail DOM du W3C. Ainsi, même si actuellement seule Xalan implémente ce document de travail, l’utilisation de l’évaluateur XPath est indépendante. Dès qu’une autre librairie supportera XPath DOM niveau 3, il sera trivial de remplacer Xalan. Le code de l’exemple n’aura pas besoin d’évoluer (on notera d’ailleurs que les imports utilisés ne dépendent pas de Xalan). Il reste cependant un bémol à cette indépendance. Le document est très jeune, et l’implémentation de Xalan n’est pas finalisée. Ainsi, la création de l’évaluateur XPath est un peu différente de ce qu’elle devrait être (et de ce qu’elle sera dans les mois à venir). En effet, elle est effective en faisant appel explicitement à une classe de la librairie Xalan.

XPathEvaluator evaluator = new org.apache.xpath.domapi.XPathEvaluatorImpl(this.doc);

Dans la version finale, il faudra utiliser le mécanisme d’interrogation (les méthodes isSupported() et getFeature() de l’interface Node) de l’implémentation afin de choisir la bonne façon de créer l’objet XPathEvaluator.

Interroger une implémentation indirectement…

La recommandation DOM Niveau 3 introduit un mécanisme permettant d’agir selon les réponses d’une implémentation… (lire la suite)

Enfin, l’écriture sur la sortie standard du résultat de l’évaluation est également indépendante de toute librairie, puisque c’est une transformation XSLT identité qui l’effectue (la transformation identité prend en entrée un document XML et produit en sortie le même document XML).

Le listing 3 permet d’illustrer l’évaluation d’expressions simples, sans espaces de noms. La méthode evaluate() de l’XPathEvaluator produit un résultat qui est parcouru élément par élément. Chaque élément est affiché sur la sortie standard, par un simple println dans le cas d’un noeud Texte, ou par la transformation identité s’il s’agit d’un fragment de document.

Le listing 4 se charge de traiter les espaces de noms. L’analyse des déclarations d’espace de noms se fait de façon similaire à celle présente dans le listing 2. Par contre, la résolution des préfixes se fait de façon différente. Lors de la lecture du document source, un nouveau document DOM est créé. Son seul but est de porter l’ensemble des déclarations d’espace de noms. On peut se demander pourquoi créer un nouveau document, alors que le document RSS du W3C porte déjà toutes les déclarations sur son noeud racine (<rdf:RDF>). Pourquoi alors ne pas l’utiliser directement ? La raison est simple et double: le fichier RSS n’est qu’un exemple et il s’agit donc d’un cas particulier qui ne fonctionne que dans la mesure ou toutes les déclarations sont faites au niveau le plus haut. Si un nouvel espace de noms (par défaut ou préfixé) est déclaré dans les profondeurs de l’arbre, il ne sera pas pris en compte. De plus, cette méthode permet d’associer, de façon claire, un préfixe pour chaque espace de noms par défaut.

Un évaluateur XPathNSResolver est créé par la méthode createNSResolver(). Il sera consulté à chaque fois que le moteur d’évaluation rencontrera un préfixe et sera chargé de fournir l’URI correspondante. Cet objet est construit à partir du document portant toutes les déclarations, mais une autre méthode pourrait être employée. Elle est sans doute plus simple, mais la jeunesse de l’implémentation la rend indisponible pour l’instant. Le programmeur pourra fournir lui-même une classe implémentant XPathNSResolver. Elle ne rendra qu’un seul service (lookupNamespaceURI(String prefix)): donner l’URI exacte correspondant au préfixe qu’elle reçoit en paramètre. Pour autant, la phase de collecte des espaces de noms ne sera pas supprimée, mais la création du document transitoire pourra être évitée puisque cette classe fournira le renseignement.

Pour conclure…

L’utilisation de XPath n’est certes pas encore complètement standard, mais l’arrivée de la recommandation du W3C risque d’accélérer encore le processus. Cela dit, il ne s’agit là que de questions d’abstraction. Si l’indépendance vis-à-vis d’une librairie particulière n’est pas rédhibitoire, vous avez un large panel d’outils déjà disponibles vous permettant d’exploiter pleinement XPath dans vos programmes. L’intégrer sera d’autant plus intéressant que le nombre de requêtes sera important. Avec une classe utilitaire (helper class), l’accès aux informations de vos fichiers XML gagne en efficacité, maintenance, compréhension. Plus de code à maintenir mais simplement des chaînes de caractères décrivant les requêtes. Voila tout l’intérêt d’utiliser XPath dans vos programmes.

Les sources de l’article

La longue marche de JDOM 1.0

Un peu plus de quatre ans après la première discussion entre les deux auteurs, JDOM conclut dix versions bêta par une version 1.0.

A l’automne 2000, Jason Hunter et Brett McLaughlin se rencontrent à Santa Clara lors d’une conférence O’Reilly. Ils échangent leurs frustrations quant à l’utilisation des API DOM et SAX, et décident alors d’en créer une pour les programmeurs Java désireux d’utiliser XML d’une façon très simple. JDOM est né. Jason Hunter, auteur de «Java Servlet Programming» et créateur du site servlets.com, s’occupera de la convivialité d’utilisation pour le programmeur Java. Brett McLaughlin, auteur de «Java and XML», aura la charge du respect de la conformité de l’API avec les spécifications XML.

Après deux versions bêta privées, JDOM bêta 3 devient disponible, le 27 avril 2000. JDOM n’étant pas un produit commercial, la guerre des versions l’épargne. L’API continue donc sa route des versions bêta, incluant toujours plus de fonctionnalités et se répandant largement dans la communauté Java. L’alternative aux spécifications DOM du W3C est d’ailleurs largement décrite dans nombre d’articles techniques liés à Java (javaworld partie 1 et 2 , ibm developerWorks , Oracle Technical Network - partie 1 , 2 et 3, xml.com, …) sur Internet mais également dans les ouvrages traitant de XML (comme Processing XML with Java par exemple). Par ailleurs, JDOM est intégré ou supporté par de plus en plus d’autres briques logicielles. Citons par exemple Saxon, le célèbre processeur XSLT/XPath ; Jaxen, un autre processeur XPath, eclipse, l’idée Open Source Java

Si DOM est une spécification qui définit des concepts indépendants de toute mise en oeuvre et donc de tout langage, JDOM affiche une volonté claire de coller au plus près au langage Java, supprimant de fait de nombreuses lourdeurs inhérentes à DOM. Ce choix délibéré constitue le vrai succès de JDOM. Voici une liste (non exhaustive) de quelques différences :

  • les éléments XML sont représentés par des classes concrètes et efficace pour le programmeur Java et non par des interfaces
  • les noeuds XML peuvent être créés sans référence à un document DOM spécifique. Ils peuvent être rattachés à n’importe quel document par la suite
  • la création des éléments (attributs, texte, …) XML en général est simplifiée et adaptée à Java, donnant un code réduit et plus lisible
  • le déplacement d’un noeud XML (et donc de toute sa descendance) d’un document vers un autre est très simple. Avec DOM, cette manipulation est assez lourde et coûteuse puisqu’il faut demander au document devant accueillir le nouveau noeud d’en faire une copie…
  • l’exportation de l’arbre XML dans un buffer ou dans un fichier de façon est aisée. C’est un des manques de DOM, manque qui sera comblé par l’implémentation des spécifications DOM 3 Load and Save (qui est encore un document de travail)

L’API de JDOM propose les fonctionnalités suivantes :

  • création de document XML
  • lecture de fichiers XML à partir de fichiers, arbres DOM, flux SAX (en réalité, JDOM ne fournit qu’une représentation sous forme d’objets Java, mais ce n’est pas un analyseur syntaxique. Il en utilise un, comme Xerces par exemple, pour la lecture de flux XML)
  • exportation d’arbre XML JDOM sous la forme de fichier, arbre DOM, flux SAX
  • transformation XSLT
  • support de XPath 1.0 (à travers la brique logicielle Jaxen)

Alors si cette API fonctionne depuis longtemps et pour beaucoup de monde, pourquoi une version 1.0 si tardive ? Jason Hunter invoque trois raisons majeures : d’une part, la complexité de XML entraîne de longs efforts pour fournir une API conforme aux spécifications, d’autre part une fois la couverture des fonctionnalités indispensables à l’auteur lui-même atteinte, compléter les aspects dont il n’avait pas besoin ne le motivait que moyennement (d’autant de Brett McLaughlin a quitté le projet fin 2000). Enfin, JDOM est une JSR - soit une spécification Java (Java Specification Request) - soumise et approuvée par le Java Community Process (JCP). La gestion inhérente au processus JCP et la défense des idées de l’auteur face à Sun ont été si longues et fastidieuses qu’il a abandonné cette JSR-102. Par ailleurs, il reconnaît que la bêta 7 aurait pu déboucher sur cette la version stable 1.0, et qu’aujourd’hui il produirait la version 2.0. Mais l’API était sujette aux changements, et il a donc préféré garder ce statut de version temporaire pour quelques années de plus.

Malgré tout, JDOM, avec quatre années d’existence, reste bel et bien une alternative de poids au modèle DOM, et le nombre de développeurs convaincus croît sans cesse. Ces adeptes attendaient depuis longtemps ce changement de statut (question tellement récurrente sur la liste de discussion JDOM qu’elle fait partie de la FAQ !), pour pouvoir justifier l’intégration de la brique logicielle dans leurs projets. Après s’être intéressé à XQuery (création du site xquery.com) et le développement d’une suite de tests de conformité des processeurs XQuery (BumbleBee), Jason Hunter peut donc enfin effacer la mention bêta de JDOM, délivrer une version 1.0 largement éprouvée, et envisager la suite pour construire JDOM 1.1…

Autres articles :

Et sur d’autres sites :

Groovy et BouncyCastle

L’installation de BouncyCastle permet de rajouter une implémentation tierce, Open Source, des algorithmes liés à la crypographie. La simplicité des tests avec Groovy permet de vérifier que tout fonctionne dans l’environnement Java.

Avant d’installer BouncyCastle, un petit test des fournisseurs existants (ceux par défaut)

import java.security.*
p = Security.getProviders()
count=1
p.each { println("[${count++}] ${it.getName()} -> version : ${it.getVersion()}”)}

[1] SUN -> version : 1.42
[2] SunJSSE -> version : 1.42
[3] SunRsaSign -> version : 1.42
[4] SunJCE -> version : 1.42
[5] SunJGSS -> version : 1.0

Après téléchargement de la dernière version, on obtient un fichier zip qui contient un répertoire jars. Celui-ci contient les archives adaptées à chaque JVM. Il faut copier le bon (par exemple bcprov-jdk14-124.jar pour le jdk 1.4) dans le répertoire javahome/jre/lib/ext. (Une autre solution consiste à le fournir à la JVM par le biais de l’argument XBootclasspath)

Ensuite pour indiquer à la JVM de prendre en compte les nouveaux paquetages, il faut éditer le fichier jre/lib/security/java.security et ajouter la ligne suivante :

security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider

Le nombre 6 vient du fait que le dernier index, celui de SunJGSS, était 5. En exécutant de nouveau le script, on note que le fournisseur est bien disponible

[1] SUN -> version : 1.42
[2] SunJSSE -> version : 1.42
[3] SunRsaSign -> version : 1.42
[4] SunJCE -> version : 1.42
[5] SunJGSS -> version : 1.0
[6] BC -> version : 1.24

Pour permettre l’usage d’une librairie tierce concernant la sécurité, il faut télécharger sur le site de Sun deux nouveaux jar qui lèvent des contrôles de sécurité quant aux fournisseurs. Cette archive zip est disponible sur la même page de téléchargement que le JSDK lui-même et se nomme «Unlimited Strength Jurisdiction Policy Files 1.4.2» Une fois téléchargés, les fichiers local_policy.jar et US_export_policy.jar remplacent ceux situés dans le répertoire jre/lib/security.

Il faut également spécifier dans le programme Java le fournisseur, par

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider())

BounceCastle possède «BC» comme nom de fournisseur, il faut donc l’utiliser lors de la récupération de l’instance du KeyGenerator

import javax.crypto.*
import java.security.*

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider())
kg = KeyGenerator.getInstance("DES","BC")
kg.init(new SecureRandom())
key = kg.generateKey()
println(key)
println("format : " + key.getFormat())
println("Key algorithm: " + key.getAlgorithm())

produit le résultat suivant :

javax.crypto.spec.SecretKeySpec@fffe7ab9
format : RAW
Key algorithm: DES

Enfin, un petit test d’encodage avec l’algorithme symétrique DES

import javax.crypto.*
import java.security.*
import java.io.*
import org.apache.commons.codec.binary.Hex

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider())
kg = KeyGenerator.getInstance("DES","BC")
kg.init(new SecureRandom())
key = kg.generateKey()
encrypt = Cipher.getInstance("DES/CBC/PKCS5Padding", "BC")
encrypt.init(Cipher.ENCRYPT_MODE, key)

texteclair = "abracadabrantesque"

println("format : ${key.getFormat()}, algorithme : ${key.getAlgorithm()}")

// affichage du texte en clair
println("texte en clair ${texteclair} [len=${texteclair.length()}]“)
hexRepr = new String(Hex.encodeHex(texteclair.getBytes()))
println(”texte en clair (hex) : ${hexRepr.toUpperCase()} [len=${hexRepr.length()}]“)

// encodage
cryptext = encrypt.doFinal(texteclair.getBytes())

// affichage du texte crypté
hexRepr = new String(Hex.encodeHex(cryptext))
println(”texte encrypte (hex) : ${hexRepr.toUpperCase()} [len=${hexRepr.length()}]“)

produit le résultat suivant :

format : RAW, algorithme : DES
texte en clair abracadabrantesque [len=18]
texte en clair (hex) : 61627261636164616272616E746573717565 [len=36]
texte encrypte (hex) : 7CF8D889EB271236793A4C7002AF3D2BEA6816B3AF36D225 [len=48]

La librairie common.codec d’Apache est bien pratique ici pour afficher sous forme hexadécimale, un tableau d’octets. Si c’est très simple en Python :

>>> for c in texteclair:
...     print hex(ord(c)),
...
0x61 0x62 0x72 0x61 0x63 0x61 0x64 0x61 0x62 0x72 0x61 0x6e 0x74 0x65 0x73 0x71 0x75 0x65

c’est un peu pénible à faire en Java ! :( Merci Apache…

Deux nouvelles versions pour Saxon 8.0 !

Michael Kay annonce la sortie de Saxon 8.0. Cette version marque un tournant dans la vie du célèbre processeur XSLT. En effet, il se décline désormais en deux versions : Saxon-B et Saxon-SA.

En décembre 2003, Michael Kay annonçait qu’il quitterait l’année suivante Software AG, et que Saxon perdrait ainsi un sponsor important. Il évoquait alors son évolution : deux versions du produit, l’une Open Source, l’autre payante (agrémentée de services). En mars 2004, Mike Kay crée Saxonica, et réalise aujourd’hui les deux versions de Saxon :

  • Saxon-B : constitue l’évolution logique des versions précédentes. Réalisée en Open Source, et toujours téléchargeable depuis sourceforge.net, c’est la version de base du processeur XSLT 2.0/XPath 2.0/XQuery.
  • Saxon-SA : est le produit de la société Saxonica, qui ajoute à la version précédente, le support des Schema_s (validation d’un _Schema, validation d’un document par rapport à un Schema, fonctionnalités liées aux schémas utilisées par les processeurs XSLT et XQuery).

Mike Kay veut ainsi par le biais de Saxonica offrir un support plus soutenu du produit (proposant une réponse à tout problème sous 24h, des corrections immédiates, ainsi qu’un support téléphonique), et se basera sur les activités commerciales de la société (support et conseil) pour faire évoluer la version libre et réduite du processeur. La plate-forme commerciale du site n’est pas encore opérationnelle, mais une version d’évaluation de 30 jours de Saxon-SA est disponible sur demande. L’auteur indique que les prix devraient avoisiner £250 pour un simple utilisateur et £60 pour tout utilisateur supplémentaire.

Ajoutons qu’à présent, Saxon reste la seule implémentation Java de XPath 2.0/XPath 2.0. Sans doute, Mike Kay est-il le mieux placé pour fournir une API à jour, puisqu’il est également rédacteur du document de travail XPath 2.0.

Autres articles sur XMLfr: