Base de données d'objets persistants
Année 2006-2007
Enseignants: G. Blin(), E. Duris, R. Forax
gblin at univ-mlv.fr, duris at univ-mlv.fr, forax at univ-mlv.fr
Présentation générale
Le but de ce projet est de réaliser une base de données objet (pas relationnelle)
permettant de stocker des objets Java en binaire.
De plus il vous est demandé de developper un petit frontal graphique permettant
de visualiser facilement le contenu de la base de données.
Travail demandé
On souhaite pouvoir obtenir la persistance des objets d'une application
entre deux lancements successifs. Pour cela les données des objets
seront sauvegardées et restaurées entre deux exécutions.
De façon plus fine, la base de données devra être capable de gérer la notion
de transaction. Une transaction est un contexte associé à un thread dans lequel
les objets peuvent être chargés, modifiés puis sauvegardés
une fois le contexte terminé (lors d'un commit).
La base de données doit supporter un environnement multi-threadé,
de telle sorte que si plusieurs threads effectuent des modifications
en concurrence sur un même objet, l'état de ce dernier est forcément
dans un état correspondant à une des transactions l'ayant modifié.
Sémantique des transactions
On vous demande de supporter les sémantiques suivantes :
- FAT_LOCK,
L'ensemble des transactions est protégé par un verrou unique au niveau de
la base de données. Chaque transaction prend le verrou lors de sa création
et le libère lors d'un commit ou d'un rollback.
- LIGHT_LOCK,
Lors d'une lecture ou d'une écriture sur un objet un verrou propre à cet
objet est pris et celui-ci ne sera rendu que lors d'un commit ou d'un rollback.
De plus, une détection de deadlocks (détection de cycle) évite ceux-ci et permet
au gestionnaire de la base de données
d'effectuer un rollback de la transaction à l'origine du deadlock.
- OPTIMISTIC
Lors de la première modification d'une valeur d'un objet par la transaction courante l'ancienne
valeur est sauvegardée. Lors du commit, il faut vérifier que toutes les valeurs de tous
les objets modifiés par la transaction courante n'ont pas été changées par d'autres threads.
Dans ce cas, l'ensemble de ces valeurs est modifié de façon atomique.
Dans le cas contraire, un rollback est effectué.
Quelque soit la sémantique, le gestionnaire de la base de données doit garantir
que toute transaction s'effectue en totalité ou pas du tout.
Il est possible pour l'utilisateur de mixer les sémantiques, i.e. de demander la création de deux
transactions avec des sémantiques différentes.
Attention, ce n'est qu'une demande de l'utilisateur.
Le gestionnaire de sémantiques peut, le cas échéant, refuser la création d'un transaction
avec une sémantique donnée (e.g. si cette dernière n'est pas compatible avec celles des transactions
en cours) et proposer alors une sémantique adéquate.
De plus, il est demandé de gérer la création de transactions imbriqués, i.e.
une transaction créée dans une autre.
Rollback
Un rollback correspond à ne pas appliquer à la base de donnée l'ensemble
des modifications d'une transaction. Il y a deux types de rollback :
- rollback explicite : c'est l'utilisateur qui, par l'appel
de la méthode rollback sur une transaction donnée, provoque le rollback
- rollback implicite : c'est le gestionnaire de la base de données
qui, afin de garantir l'intégrité de la base, doit effectuer un rollback
sur une transaction donnée. Ce type de rollback peut intervenir
à des moments différents en fonction de la sémantique de la transaction
(et la sémantique des transactions environnantes).
Tout rollback conduit à la levée d'une exception RollbackException afin de permettre au code utilisateur d'effectuer la reprise sur cette erreur.
Persistence
Nous considérons, dans un premier temps, que les objets que l'on souhaite pouvoir sauvegarder ne sont composés que de champs de types primitifs. Vous pouvez optionnellement gérer les String et les champs de référence vers des objets persistants.
Afin de pouvoir gérer les objets à sauvegarder, le gestionnaire d'objets impose que
- Le type de l'objet soit défini par une interface taggée via l'annotation @Persistent. Le gestionnaire ne considère donc pas des objets Java mais plutôt des objets ayant des champs virtuels dont les valeurs sont sauvegardées dans un ou plusieurs fichiers.
- L'interface devra contenir uniquement des accesseurs (couples getter/setter) permettant d'accéder aux valeurs des champs de l'objet.
- Pour identifier l'objet, un getter particulier de type long
devra être annoté par @Id. La valeur retournée par ce getter
correspond à un identifiant unique de l'objet
(on parle souvant de clé primaire).
Il ne devra pas y avoir de setter pour ce getter particulier.
Par exemple, l'interface suivante déclare un type d'objet correspondant à
un point en 2 dimensions.
@Persistent public interface Point2D {
/*
* Getter and Setter for all fields except id
*/
public int getX();
public void setX(int x);
public int getY();
public void setY(int y);
/*
* Getter for id
*/
@Id
public long getId();
}
|
Opérations
Sur une transaction, il est possible d'effectuer les opérations suivantes :
- Création d'un objet persistant à partir d'une interface
- Obtention d'un objet persistant par son identifiant unique
- Obtention de l'ensemble des objets persistants par leur type
- Demande de suppression d'un objet de la base de données
- Un commit ou un rollback
De plus, sur le gestionnaire de base de données, il est possible de :
- Créer des transactions
- Lister tous les types d'objets persitents présents
- Supprimer tous les objets d'un certain type
Votre implantation devra faire en sorte d'effectuer ces opérations le plus
rapidement possible et sans effectuer d'opérations/allocations inutiles.
Rappelons que les opérations de modifications ont un impact sur la base de données uniquement lors
d'un commit de la transaction.
Tous les objets persistants sont mis-à-jours dans la base de données,
insérés en cas d'absence, m-à-j sinon.
Le frontal graphique
Le frontal graphique est une petite application swing permettant
d'afficher le contenu de la base de données.
Cette application devra :
- Etre indépendante d'une implantation d'une base de données
i.e. marcher avec l'implantation du voisin.
- Permettre de lister l'ensemble des types de la base de données
sous forme d'un arbre à gauche de l'application.
Un menu contextuel devra permettre la suppression de tous les objets
d'un type selectionné.
- Permettre de lister l'ensemble des objets pour un type donné
(au préalablement choisi dans la partie gauche)
dans la partie droite sous forme d'une table dont chaque
colonne indique les propriétés d'un objet et chaque ligne
correspond à un objet particulier.
De plus, il devra être possible de supprimer des objets sélectionnés
et de modifier les valeurs d'un objet particulier.
Détail du rendu
Ce projet est à faire en binôme (cela veut dire deux personnes pas trois ni une),
un seul groupe de 3 personnes est admis.
Le rendu s'effectuera par mail sous forme d'une pièce jointe au format ZIP contenant
l'ensemble des programmes et documents. Le mail devra être envoyé avant minuit aux
trois adresses données au début de ce document.
Le fichier s'appellera nom1_nom2.zip - nom1 et nom2 étant les noms respectifs des personnes formant le binôme triés dans l'ordre alphabétique - et devra être envoyé au plus tard le 4 mars à 23h59:59.
Voici les noms des répertoires et fichiers qui doivent être contenus dans l'archive zip.
- un fichier readme.txt indiquant comment compiler le programme,
comment exécuter le frontal, où se trouve la documentation, etc.
- un fichier Ant build.xml permettant de compiler les sources du programme,
et de créer le jar javaodb-impl.jar ainsi que le jar exécutable javaodb-ui.jar dans bin.
- un répertoire src contenant l'ensemble des sources (.java),
en utilisant un ou plusieurs paquetages.
- un répertoire test contenant l'ensemble des tests unitaires (.java)
au format JUnit 4 (junit.org),
en utilisant un ou plusieurs paquetages.
Il doit y avoir au moins un test pour chaque stratégie que vous avez implantée.
- un répertoire classes contenant l'ensemble des classes (.class)
correspondant aux sources et aux tests.
- un répertoire lib contenant les jars javaodb-lib.jar, javaodb-impl.jar
et javaodb-ui.jar
- un répertoire docs contenant deux documents au format PDF :
- La documentation utilisateur user.pdf contenant en plus des informations
classiques (comment compiler, exécuter, etc.) une description de
l'application graphique, et comment l'utiliser.
- La documentation développeur dev.pdf contenant :
- Une diagramme de classe (UML) de chaque paquetage
- Les stratégies que vous avez utilisées dans votre implantation
- pour gérer les différentes sémantiques
- pour gérer le mixage des sémantiques
- pour gérer les transactions imbriquées
- pour gérer les drops des classes si des transactions existent déjà.
Vous profiterez de la description de chaque stratégie
pour fournir une description détaillée de chaque classe que vous
avez implantée.
Evitez les copier/coller de la javadoc, essayer plutôt de décrire en
français les classes par leur responsabilité (ce qu'elles font et comment elles le font)
et dans un ordre logique.
Pour expliquer les enchaînements d'appels entre les objets,
vous utiliserez des diagrammes de séquences (UML).
- Une liste des bugs connus (s'il y en a) détaillant le scénario
permettant de générer un bug ainsi que la raison pour laquelle celui-ci
se produit.
En plus des deux documents, le répertoire docs devra contenir un sous répertoire
api contenant la documentation complète du logiciel au format javadoc.