![]() |
Mon site perso a changé d'adresse. Si rien ne se passe cliquez sur le lien ci-dessus. |
|
|
|
|
|
|
Développons en Java v 0.85 béta | |
| Copyright (C) 1999-2005 Jean-Michel DOUDOUX |
![]() |
![]() |
![]() |
JDO (Java Data Object) est la spécification du JCP n° 12 qui propose une technologie pour assurer la persistance d'objets Java dans un système de gestion de données. La spécification regroupe un ensemble d'interfaces et de règles qui doivent être implémentées par un fournisseur tiers.
La version 1.0 de cette spécification a été validée au premier trimestre 2002. Elle devrait connaître un grand succès car le mapping entre des données stockées dans un format particulier (bases de données ...) et un objet a toujours été difficile. JDO propose de faciliter cette tâche en fournissant un standard.
Ce chapitre contient plusieurs sections :
Les principaux buts de JDO sont :
Le développement avec JDO se déroule en plusieurs étapes :
JDBC et JDO ont les différences suivantes :
JDBC |
JDO |
| orienté SQL | orienté objets |
| le code doit être ajouté explicitement | code est ajouté automatiquement |
| gestion d'un cache | |
| mapping réalisé automatiquement ou à l'aide d'un fichier de configuration au format XML | |
| utilisation avec un SGBD uniquement | utilisation de tout type de format de stockage |
JDO est une spécification qui définit un standard : pour pouvoir l'utiliser il faut utiliser une implémentation fournie par un fournisseur. Plusieurs implémentations existent et le choix de l'une d'elle doit tenir compte des performances, du prix, du support des cibles de stockage des données, etc ... L'intérêt des spécifications est qu'il est possible d'utiliser le même code avec des implémentations différentes tant que l'on utilise uniquement les fonctionnalités précisées dans les spécifications.
Chaque implémentation est capable d'utiliser un ou plusieurs systèmes de stockage de données particulier (base de données relationnel, base de données objets, fichiers, ...).
Attention : tous les objets ne peuvent pas être rendu persistant avec JDO.
Les exemples de cette section ont été réalisés avec Lido Community Edition version 1.4.5. de la société Libelis.
Cette version est librement téléchargeable après enregistrement à l'url : http://www.libelis.com
Pour lancer l'installation, il suffit de double cliquer sur le fichier LiDO_Community_1[1].4.5.jar ou de saisir la commande :
| Installation de Lido community edition de Libelis |
|

L'installation s'opère simplement en suivant les diffentes étapes de l'assistant.
Le premier exemple permet simplement de rendre persistant un objet instancié dans une base de données MySQL.
Pour faciliter la mise en oeuvre des différentes étapes, un script batch pour Windows sera écrit tout au long de cette section et exécuté. Ce script débute par une initialisation de certaines variables d'environnement.
| Début du script |
|
Le début du script initialise 4 variables :
Pour des raisons de facilité, le répertoire courant "." est ajouté dans le CLASSPATH. Le pilote JDBC pour MySQL est aussi ajouté à cette variable.
Le code de cet objet reste très simple puisque c'est simplement un bean encapsulant une personne contenant des attributs nom, prenom et datenaiss.
| Exemple : |
|
Cet objet va utiliser des objets JDO pour réaliser les actions sur les données. Dans l'exemple ci dessous, une seule action est codée : l'enregistrement dans la table des données du nouvel objet de type Personne instancié.
| Exemple : |
|
Les deux classes définies ci dessus doivent être compilées normalement en utilisant l'outil javac.
| La suite du script : compilation des classes |
|
Le fichier metadata est un fichier au format XML qui précise le mapping à réaliser.
| Exemple : metadata.jdo |
|
Pour assurer une bonne exécution, il faut enrichir l'objet Personne compilé avec du code pour assurer la persistance par JDO. Lido fourni un outil pour réaliser cette tâche. Cet outil est complètement dépend de l'implementation qui en est faite par le fournisseur de la solution JDO.
| La suite du script : enrichissement |
|
Le fichier Personne.class est enrichi (sa taille passe de 867 octets à 9693 octets)
Lido fournit un outil qui permet de générer les tables de la base de données contenant les tables pour le mapping des données plus des tables "techniques" nécessaires aux traitements.
Les paramètres nécessaires à l'outil de Libelis pour définir le schéma de la base de données doivent être rassemblés dans un fichier .properties.
| Exemple : propriété pour une base de données de type MySQL |
|
Il suffit alors d'utiliser l'application DefineSchema fournie par Lido en lui passant en paramètre le fichier .properties et le fichier .jdo
| La suite du script : création du schéma de la base de données |
|
Il est facile de vérifier les traitements effectués par l'outil DefineSchema :
| Exemple : |
|
| Exemple : |
|
A l'issu de l'exécution, un enregistrement est créé dans la table qui mappe l'objet Personne.
| Exemple : |
|
L'API de JDO se compose de deux packages :
Le package javax.jdo contient essentiellement des interfaces ainsi que quelques classes notamment la classe JDOHelper et les diverses exceptions utilisées par JDO. Les interfaces définies sont : Extent, PersistenceManager, PersistenceManagerFactory, Query etTransaction.
Les exceptions définies par l'API JDO sont : JDOCanRetryException, JDODataStoreException, JDOException, JDOFatalDataStoreException, JDOFatalException, JDOFatalInternalException, JDOFatalUserException, JDOUnsupportedOptionException et JDOUserException.
Cette interface définit les méthodes pour l'objet principal de l'API JDO pour les développeurs.
Certaines méthodes permettent de gérer le cycle de vie d'une instance d'un objet de type PersistenceCapable.
| void close() | fermer |
| Transaction currentTransaction() | renvoie la transaction courante |
| void deletePersistent() | permet de détruire dans la source de données l'instance encapsulée |
| Extent getExtent(Class, boolean) | renvoie une collection d'instance encapsulant les données dans la source de données |
| void makePersistent() | permet de rendre persistante les données encapsulées dans l'instance en créant une nouvelle occurence dans le système de gestion de ressources |
| void evict() | permet de préciser que l'instance n'est plus utilisée |
| Query newQuery() | renvoie un objet de type Query qui permet d'effectuer des sélections dans la source de données |
| void refresh() | permet de redonner à une instance les valeurs contenues dans le système de gestion de ressources |
Cette interface propose aussi deux méthodes possédant de nombreuses surcharges de la méthode newQuery() pour obtenir une instance d'un objet de type Query.
Un objet qui implémente cette interface à pour but de fournir une instance d'une classe qui implémente l'interface PersistenceManager. Un tel objet doit être configuré via des propriétés pour instancier un objet de type PersistenceManager. Ces propriétés doivent être fournies à la fabrique avant l'instanciation du premier objet de type PersistenceManager. Il n'est dès lors plus possible de changer la configuration de la fabrique.
Cette interface possède une méthode nommée getPersistenceManager() qui permet d'obtenir une instance de la classe PersistenceManager.
Cette interface doit être implémentée lors de son enrichissement par la classe qui va contenir des données. Cette classe avant son enrichissement ne doit pas implémenter cette interface : c'est lors de cette phase d'enrichissement que la classe implémentera cette interface et que seront définies les méthodes déclarées par cette interface nécessaires à la persistence des données. Cet enrichissement peut se faire de deux façons :
Les méthodes définies dans cette interface sont à l'usage de JDO : une fois la classe enrichie, il ne faut surtout pas appeller directement ces méthodes : elles sont toutes préfixées par jdo.
Une classe qui implémente l'interface PersistenceCapable est nommé instance JDO.
Cette interface définit des méthodes qui permettent d'obtenir des instances représentant des données issues de la source de données.
L'interface définit plusieurs surcharges de la méthode execute() pour exécuter la requête et renvoyer un ensemble d'instances.
La méthode compile() permet de vérifier la requête et préparer son exécution.
La méthode setFilter() permet de préciser un filtre pour la requête.
Une instance d'un objet implémentant l'interface Query est obtenue en utilisant une des nombreuses surcharges de la méthode newQuery() d'un objet de type PersistenceManager.
Cette interface définit les méthodes pour la gestion des transactions avec JDO.
Elle possède trois méthodes principales qui sont classiques dans la gestion des transactions :
Une classe qui implémente cette interface permet d'encapsuler toute une collection contenant tous les objets d'un type PersistenceCapable particulier. La méthode iterator() renvoie un objet de type Iterator qui permet de parcourir l'ensemble des éléments de la collection.
L'interface Extent ne prévoit actuellement aucun moyen de filter les éléments de la collection et il est uniquement possible d'obtenir toutes les occurences.
La méthode close(Iterator) permet de fermer l'objet de type Iterator passé en paramètre.
La classe JDOHelper permet de faciliter l'utilisation de JDO grâce à plusieurs méthodes statiques pouvant être regroupées dans plusieurs catégories :
| Nom | Rôle |
| boolean isDeleted(Object) | renvoie un booléen qui précise si l'instance JDO fournie en paramètre vient d'être supprimée dans le système de gestion de ressources |
| boolean isDirty(Object) | renvoie un booléen qui précise si l'instance JDO a été modifiée dans la transaction courante |
| boolean isNew(Object) | renvoie un booléen qui précise si l'instance JDO fournie en paramètre vient d'être rendue persistante en créant une nouvelle instance dans le système de gestion de ressources |
| boolean isPersistent(Object) | |
| boolean isTransactional(Object) |
| Nom | Rôle |
| PersistenceManager getPersistenceManager(Object) | renvoie l'objet de type PersistenceManager utilisé pour rendre persistante l'instance JDO fournie en paramètre |
| getObjectId(Object) | |
| makeDirty(Object, String) | |
| PersistenceManagerFactory getPersistenceManagerFactory(Properties) |
La mise en oeuvre de JDO requiert plusieurs étapes :
Une telle classe se présente sous la forme d'une bean : elle représente une occurence particulière dans le système de stockage des données.
Cette classe n'a pas besoin ni d'utiliser ni d'importer de classes de l'API JDO.
Pour la classe qui va contenir des données, JDO impose la présence d'un constructeur sans argument. Celui ci est automatiquement ajouté à la compilation si aucun autre constructeur n'est défini, sinon il faut ajouter un constructeur sans argument manuellement.
Cette classe va réaliser des traitements en utilisant JDO pour accéder et/ou mettre à jour des données.
![]() |
|
La suite de ce section sera développée dans une version future de ce document
|
Toutes les classes écrites doivent être compilées normalement comme toutes classes Java.
Pour indiquer à JDO quelles classes doivent être persistantes et préciser des informations concernant ces dernières, il faut utiliser un fichier particulier au format XML. Ce fichier désigné par "Metadata" dans les spécifications doit avoir pour extension .jdo.
Il est possible de définir un fichier de description pour chaque classes persistantes ou un fichier pour un package concernant toutes les classes persistantes du package. Dans le premier cas, le fichier doit se nommer nom_de_la_classe.jdo, dans le second nom_du_package.jdo.
Le fichier commence par un prologue :
<?xml version="1.0" encoding="UTF-8" ?>
Le fichier contient ensuite la DTD utilisée pour valider le fichier : soit une URL pointant sur la DTD du site de Sun soit une DTD sur le système de fichier.
<!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" "http://java.sun.com/dtd/jdo_1_0.dtd">
Le tag racine du document XML est <jdo>. Ce tag peut contenir un ou plusieurs tags <package> selon les besoins, chaque tag package concernant un seul package.
Chaque tag <package> contient autant de tags <class> que de classes de type instance JDO utilisées. L'attribut "name", obligatoire, permet de préciser le nom de la classe.
Les tags <jdo>, <package>, <class> et <field> peuvent aussi avoir un tag <extension> qui va contenir des paramètres particuliers dédiés à l'implémentation de JDO utilisée. Il faut un tag <extension> pour chaque implémentation utilisée.
Cette phase permet d'ajouter du code à chaque classe encapsulant une instance JDO. Ce code contient les méthodes définies par l'interface PersistenceCapable.
Le ou les outils fournis par le fournisseur sont particuliers pour chaque implémentation utilisée.
Un objet qui implémente l'interface Extent permet d'accéder à toutes les instances d'une classe encapsulant des données.
Un objet de type Extent est obtenu en appellant la méthode getExtent() d'un objet PersistentManager. Cette méthode attend deux paramètres : un objet de type Class qui est la classe encapsulant les données et un booléen qui permet de préciser si les sous classes doivent être prise en compte.
Un objet de type Extent ne permet qu'une seule opération sur l'ensemble des instances qu'il contient : obtenir un objet de type Iterator qui permet le parcours séquentiel de toutes les occurences. La méthode iterator() permet de renvoyer cet objet de type Iterator : les méthodes hasNext() et next() assurent le parcours des occurences.
L'appel de la méthode close() une fois que l'objet de type Iterator fourni en paramètre n'a plus d'utilité est obligatoire pour permettre de liberer les ressources allouées par l'objet pour son fonctionnement. La méthode closeAll() permet de fermer tout les objets de type Iterator instanciés par l'objet de type Extent.
| Exemple : Afficher tous les données de la table personne |
|
| Exemple : Contenu de la table au moment de l'exécution |
|
| Exemple : Contenu de la table au moment de l'exécution |
|
Avec JDO, les requêtes sont mises en oeuvre grâce à un objet de type Query. Les requêtes appliquent un filtre sur un ensemble d'objets encapsulant des données sous la forme d'un objet de type Extent ou d'une collection.
Un filtre est une expression booléenne appliquée à chacune des occurences : la requête renvoie toutes les occurences pour laquelle le résultat de l'évaluation de l'expression est vrai. Les expressions sont exprimées avec un langage particulier nommé JDO Query Langage (JDOQL)
Un instance d'un objet qui implemente l'interface Query est obtenu en utilisant la méthode newQuery() d'un objet de type PersistanceManager.
| Exemple : afficher les occurences dont le prénom est Jean |
|
| Résultat : |
|
![]() |
|
La suite de ce chapitre sera développée dans une version future de ce document
|
|
|
|
|
|
|
Développons en Java v 0.85 béta | ||
| Copyright (C) 1999-2005 Jean-Michel DOUDOUX |