Gestion d'une bibliothèque
Projet BIB-CCI
Projet L&P - DESS CCI 1999-2000
Sara Bouchenak - Edmond Boyer - Fabienne Dechamboux - Christian
Lenne
1. Présentation
générale du stage
Le stage a pour objectif la réalisation
d'un logiciel de gestion d'une bibliothèque,
appelé BIB-CCI.
Il se déroule sur une période
bloquée durant laquelle votre présence est obligatoire. Il
sera réalisé par équipes de 3 personnes.
Le stage sera évalué
sur les aspects suivants :
-
Le degré d'avancement dans les
différentes étapes.
-
La qualité du logiciel produit
: organisation modulaire, fichiers de tests fournis, qualité du
code source (présentation, clarté, cohérence des noms,
commentaires).
-
La qualité de la documentation
(conception, utilisation).
Ces aspects seront évalués
lors d'une démonstration d'environ 15 minutes qui sera effectuée
par chaque équipe en fin de stage. Cette démonstration permettra
de tester l'application et de présenter une synthese du stage (difficultés
rencontrées, organisation mise en oeuvre dans la répartition
des taches, choix de programmation effectués, etc).
En outre, il est demandé
de laisser un accès en lecture au code source de votre projet.
Enfin, il est également demandé de rendre un document d'utilisation
(1 ou 2 pages) précisant quelles sont les commandes et les options
permettant de manipuler l'application BIB-CCI.
2. Présentation
générale du projet BIB-CCI
La bibliothèque que l'on souhaite informatiser
comporte un ensemble d'adhérents
(personnes membres de l'association bibliothécaire),
et gère
un ensemble de livres. Pour chaque livre, il peut exister plusieurs
exemplaires, sans dépasser une limite fixée, soit NMex
(nombre maximum d'exemplaires). Cette limite est la même
pour tous les livres.
L'emprunt d'un livre par une personne
n'est possible que si les règles suivantes sont toutes respectées
:
-
la personne doit être
adhérente de l'association,
-
le livre doit apparaitre dans le catalogue
et au moins un exemplaire du livre doit être
disponible en bibliothèque,
-
le nombre de livres empruntés
par une personne à un instant donné ne peut dépasser
une limite fixée, soit NMEmp (nombre maximum d'emprunts).
Cette limite est la même
pour tous les adhérents,
-
la personne ne possède pas d'emprunts
en cours pour lesquels elle aurait un retard ; on supposera qu'un
livre emprunté doit être
rendu à la bibliothèque dans un délai de 15 jours
après la date d'emprunt.
Pour gérer les prêts
de la bibliothèque, on considère deux ensembles d'informations,
la catalogue des livres et le répertoire des adhérents.
Le catalogue décrit
l'ensemble des livres acquis par la bibliothèque. Deux livres distincts
diffèrent par leur titre et / ou par leur auteur. Pour chaque
livre, on dispose des informations suivantes :
-
le titre du livre,
-
le nom et le prénom de l'auteur,
-
le nombre total d'exemplaires acquis
par la bibliothèque - chaque exemplaire étant identifié
par un numéro
-
le nombre d'exemplaires qui sont indisponibles
(pretés à un adhérent).
Le nombre total de livres , ainsi que
le nombre total d'auteurs de livres gérés par la bibliothèque,
sont a priori illimités. L'ajout de nouveaux livres est une opération
relativement courante, au contraire de la suppression. Par ailleurs, on
souhaite pouvoir accéder aux éléments du catalogue
selon un auteur, ou bien un titre donné.
Le répertoire décrit
les adhérents de l'association. Deux adhérents distincts
doivent avoir au moins un attribut qui diffère parmi les trois suivants
: nom, prénom et adresse. L'emploi de numéros d'adhérents
(identificateurs uniques) devra permettre de distinguer simplement les
adhérents. Pour chaque adhérent, on dispose des informations
suivantes :
-
le nom et le prénom de l'adhérent,
-
le numéro de l'adhérent,
-
le nombre de livres empruntés
par l'adhérent,
-
la liste (éventuellement vide)
des livres empruntés par l'adhérent, avec la date d'emprunt.
Le nombre total de d'adhérents
gérés par la bibliothèque est limité a NMAdh.
L'ajout et le retrait d'adhérents sont des opérations courantes,
de même que la consultation
des livres empruntés par un adhérent. On considère
qu'une personne peut emprunter plusieurs exemplaires d'un même
livre.
3 Représentation
et manipulation des informations
On essaiera de représenter les
informations à l'aide des mécanismes de structuration fournis
par le langage C qui sont le plus adéquat en fonction des caractéristiques
des données à gérer, énoncées en 2.
L'organisation modulaire du programme de gestion de la bibliothèque
devra cependant permettre de réaliser un développement incrémental,
au cours duquel on pourra utiliser des structures de données temporaires.
En outre, lorsque des fonctions identiques sont requises en divers points
du programme, on veillera à regrouper celles-ci dans un même
module.
Les fonctions principales qui sont
attendues sont décrites ci-après. L'ensemble de ces fonctions
constitue la partie visible de l'application BIB-CCI, qui sera accessible
aux utilisateurs au travers d'une interface graphique (voir 5).
Il peut être intéressant
d'étoffer cet ensemble de fonctions pour offrir des capacités
additionnelles, telles que la possibilité pour la bibliothèque
de conserver l'historique des emprunts dans un fichier, et de réaliser
des statistiques sur les demandes des adhérents.
Adhésion d'une nouvelle
personne.
La fonction enregistre un nouvel
adhérent, en vérifiant que celui-ci n'est pas déja
présent dans le répertoire.
Supression d'un adhérent.
La fonction supprime un adhérent
du répertoire, en vérifiant que celui-ci a bien rendu tous
les livres qu'il a emprunté.
Consultation d'un adhérent.
La fonction renvoie les informations
relatives à un adhérent donné (livres empruntés,
date d'emprunt).
Consultation de la liste des adhérents.
Cette fonction renvoie les informations
relatives aux adhérents, organisées sous la forme d'une liste
ordonnée sur les noms d'adhérents. Il est envisageable
de découper la liste en deux
parties, l'une concernant les informations
relatives aux adhérents ayant du retard et l'autre donnant les informations
sur les autres adhérents.
Acquisition d'un nouveau livre
par la bibliothèque.
La fonction enregistre un nouveau
livre dans le catalogue, dont les caractéristiques (titre, auteur,
mots-clés, nombre d'exemplaires, etc) sont données.
Suppression d'un livre.
La fonction supprime tous les exemplaires
d'un livre donné, en vérifiant que ceux-ci ne sont pas empruntés.
Consultation d'un livre.
La fonction renvoie les informations
relatives à un livre donné (nombre d'exemplaires, nombre
d'exemplaires disponibles, personnes ayant emprunté ce livre, etc).
Consultation des livres d'un auteur
donné.
Etant donné un nom d'auteur,
la fonction renvoie les informations relatives aux livres écrits
par l'auteur et gérés par la bibliothèque.
Consultation des livres ayant
un titre donné.
Etant donné un titre, la
fonction renvoie les informations relatives aux livres gérés
par la bibliothèque et ayant ce titre.
Consultation de tous les livres.
Cette fonction renvoie les informations
relatives aux livres gérés par la bibliothèque, organisées
sous la forme d'une liste ordonnée sur les titres.
Emprunt d'un livre par un adhérent
donné.
Cette fonction vérifie que
l'emprunt est possible, et enregistre les informations nécessaires
dans la base.
Retour d'un livre par un adhérent
donné.
Cette fonction vérifie que
le livre a bien été emprunté, et enregistre le fait
qu'il est maintenant rendu à la bibliothèque.
Consultation de l'historique des
emprunts et affichage de statistiques.
4
Propriétés de l'application
de gestion de la bibliothèque
4.1 Persistence des données
Les données manipulées
par l'application BIB-CCI sont de nature persistente, c'est à dire
qu'elles doivent survivre à l'exécution de l'application.
Pour assurer la persistence de ces données, nous proposons de les
sauvegarder dans des fichiers Unix. Le principe consiste alors à
restaurer (c'est à dire charger) ces données depuis leur
sauvegarde lors du lancement de l'application. Nous supposerons
qu'au lancement de l'application BIB-CCI, la totalité
des données, c'est à
dire la base complète,
est chargée en mémoire.
Un choix doit être fait pour
décider des moments auxquels auront lieu la sauvegarde des données
sur disque. Plusieurs politiques sont possibles :
-
chaque sortie de l'application provoque
au préalable une sauvegarde des données sur disque
-
l'interface utilisateur offre
un choix dans son menu qui permet de provoquer une sauvegarde
Dans tous les cas, la persistence des
données implique de mettre en oeuvre deux nouvelles fonctions :
sauver_donnees, et restaurer_donnees.
4.2 Cohérence des données
garantie en présence de panne
Les données manipulées
par l'application BIB-CCI sont supposées être cohérentes.
Par exemple, le nombre d'exemplaire libre d'un livre donné doit
être cohérent par rapport aux emprunts qui ont été
effectués de ce livre. L'application doit déja assurer que,
sans la présence de pannes, les données qu'elle manipule
sont cohérentes.
On souhaite garantir la cohérence
des données même en présence de pannes. Ceci signifie
que, si une panne provient à un instant t, alors la derniere
sauvegarde des données doit être récupérable.
Pour ce faire, l'opération de sauvegarde des données sur
disque doit garantir la propriété d'atomicité
:
-
soit la sauvegarde Si est réalisée
entièrement, et devient alors disponible
-
soit la sauvegarde Si est interrompue
par une panne, et on doit garantir que la sauvegarde Si-1
est disponible.
Le principe de mise en oeuvre d'une
sauvegarde atomique est le suivant. Soit un fichier pour lequel on souhaite
effectuer des sauvegardes atomiques. Autrement dit, on veut réaliser
une fonction atomic_save(données, fichier), qui garantit
que, à l'issue de la fonction :
-
soit la totalité
des données est sauvegardée
dans le fichier
-
soit le fichier conserve son ancien
contenu
Pour ce faire,
diverses méthodes sont envisageables, et on pourra essayer
d'en imaginer quelques unes. Une méthode simple consiste à
effectuer la sauvegarde dans un fichier temporaire (f.bak par exemple),
et à utiliser ensuite la commande mv d'Unix (cette commande
est atomique) pour copier ce fichier temporaire dans le fichier de sauvegarde.
On utilisera la fonction system du langage C pour appeler la commande
mv depuis un programme C.
Ces principes de mise en oeuvre pourront
être utilisés au niveau des fonctions de sauvegarde et de
restauration pour garantir la cohérence des données de l'application
BIB-CCI même en présence de pannes.
4.4 Gestion de la reprise après
panne
Lorsqu'une panne arrive à un
instant t, il existe une sauvegarde disponible (voir section précédente).
Cependant, le travail effectué sur les données entre la date
à laquelle a été réalisée la derniere
sauvegarde et le moment auquel a lieu la panne est perdu. Nous dirons que
l'application fournit une procédure de reprise après panne
si elle fournit un moyen qui permet de récupérer le travail
effectué entre la derniere sauvegarde et l'instant auquel a lieu
une panne.
Un moyen simple, mais très
peu efficace, de fournir cette propriété consiste à
obliger l'utilisateur à provoquer une sauvegarde après chaque
modification des données. On réfléchira à d'autres
moyens plus performants, tels que par exemple l'utilisation d'un journal
comme expliqué ci-après.
Un journal est un fichier qui contient
des informations sur les modifications effectuées sur les données
depuis leur dernière sauvegarde. Soit E1 l'état initial
des données lorsque l'utilisateur lance l'application BIB-CCI. Supposons
que ce dernier effectue une série d'opérations Op1, .. ,
Opn sur les données, et qu'une panne apparaisse durant l'opération
Opn. Supposons également que l'état des données en
mémoire à la suite de l'opération Opn-1 soit E2.
Les informations contenues dans un
journal doivent être suffisantes pour pouvoir rétablir les
données dans l'état E2. Pour ce faire, on écrira dans
le journal les états des seules données modifiées
(personnes, livres) par les opérations effectuées.
Lorsque l'utilisateur souhaite effectuer une sauvegarde de la base, deux
cas sont possibles :
-
la sauvegarde se passe sans problème,
il faut ensuite "vider" le journal dont le contenu ne sert plus a rien
-
la sauvegarde est soumise a une panne,
il faut alors qu'au relancement de l'application BIB-CCI, le journal soit
utilisé pour rétablir l'état des données.
Plus précisement, voici un déroulement
possible pour une utilisation de l'outil BIB-CCI :
Session de travail avec
BIB-CCI:
Ecrire dans le journal : start_session
Op1
Ecrire dans le journal les données modifiées par Op1
Op2
Ecrire dans le journal les données modifiées par Op2
...
Opn
Ecrire dans le journal les données modifiées par Op1
Effectuer une sauvegarde atomique de la base
Ecrire dans le journal : end_session
|
La session de travail commence toujours
par l'écriture dans le journal du mot-clé start_session,
indiquant qu'une nouvelle session de travail avec l'application BIB-CCI
démarre. Ensuite, chaque opération effectuée par l'utilisateur
provoque la sauvegarde de l'état des données modifiées
dans le journal. Enfin, lorsque la session de travail se termine, une sauvegarde
de la base est effectuée. Si tout se passe bien, le mot-clé
end_session est écrit dans le journal. En cas de panne :
-
si la panne arrive juste après
l'écriture de end_session dans le journal, alors il n'y a
pas besoin de reprise après panne puisque la base a eu le temps
d'etre sauvegardée.
-
si le journal ne contient pas le mot-clé
end_session, alors on supposera que la panne a pu influencer la
sauvegarde de la base, et on procedera à une reprise après
panne.
La procedure de reprise est la suivante
:
Charger la base en mémoire
Parcourir le journal, et mettre
a jour les données modifiées dans la base en mémoire
Sauvegarder la base
Ecrire dans le journal : end_session |
Toute panne survenant durant la procédure
de reprise provoquera à nouveau l'exécution de la procédure
de reprise.
5
Mise en oeuvre de l'interface utilisateur du systeme de gestion de la bibliothèque
La partie gerant l'interface utilisateur
de l'application est fournie aux etudiants. Cette partie utilise un langage
de script appelé Tcl-TK permettant de réaliser une interface
graphique simple et rapide. Bien qu'il ne soit pas necessaire de comprendre
le fonctionnement de l'interprete, nous donnons ci-apres le schema de principe
de ce fonctionnement pour information.
Dans la partie fournie, vous trouverez
les fichiers suivants :
-
bib_cci.tk
: ce fichier contient le script Tk de gestion des evenements graphiques
-
bib_cci.c
: ce module C contient les fonctions C appelees par l'interface graphiques.
Ces fonctions sont pour l'instant vides, et devront etre completees.
-
bib_cci.h
: fichier include associe a bib_cci.c
-
bib_cci_main.c
: programme principal, qui lance l'interface graphique.
-
makefile
Pour lancer l'application, il faut taper
bib_cci bib_cci.tk
Principe de fonctionnement
de TK
La communication entre un programme C et un script Tcl-TK permet d'ajouter
au programme C une interface graphique programmée
en Tcl-Tk. Le schéma d'interaction entre la partie interface en
Tcl-Tk, et la partie du programme écrite en C est le suivant :
Les composants (modules) écrits
en C comportent une partie d'initialisation (module définissant
la fonction main), ainsi qu'une partie qui contient les fonctions
et procédures constituant l'application proprement dite. Le module
d'initialisation a une structure standard, donnée ci-après
:
-
associer chaque événement
de l'interface graphique avec une fonction C de traitement de l'événement
-
créer un interprete Tcl-Tk qui
va gérer la partie interface graphique
-
exécuter les initialisations
propres a l'application
-
exécuter les initialisations
de Tcl et Tk
-
exécuter le scritpt Tcl-Tk fourni,
et entrer dans une boucle d'attente d'evénements
Pour illustrer cette structure, voici un exemple très
simple dans lequel l'application écrite
en C imprime le carré d'un nombre saisi dans une fenetre. Le programme
C comporte une seule fonction square, que l'on associe à
une commande Tcl-Tk appelée square_com (autrement dit, lorsque
l'interprete Tcl_Tk appelle la commande com_Square, alors automatiquement
la fonction Square est appelee et les parametres sont transmis).
Les paramètres des commandes
Tcl, et donc également ceux des fonctions C auxquelles sont associées
les commandes Tcl, sont forcément des chaines de caractères.
Pour transformer ces chaines en d'autres types (entier, réél,
etc), on utilisera les fonctions de la librairie C (atoi, atof, etc).
Dans l'exemple suivant, nous ne prenons
pas en compte le traitement des erreurs :
/* module C : square.c */
square.h
#include <stdio.h>
extern int square...
#include<stdlib.h>
#include<tcl.h>
int square (ClientData clientData,
Tcl_Interp *interp,
int argc, char *argv[]) {
double v;
if (argc != 2) return TCL_ERROR;
v = atof(argv[1]);
sprintf(interp->result, "%.5f", v*v);
/* pour communiquer un résultat
depuis C vers Tk */
return TCL_OK;
} |
Le module principal est donné
ci-dessous :
/* module C : square_main.c */
#include <tk.h>
#include "square.h"
long main (int argc, char
* argv[]) {
Tk_Main(argc, argv, Tcl_AppInit);
exit(0);
}
int Tcl_AppInit(Tcl_Interp
*interp) { /* Tcl-AppInit est appelée par Tk_Main
*/
if (Tcl_Init(interp) == TCL_ERROR)
/* avant l'entrée dans la boucle d'attente */
return TCL_ERROR;
if (Tk_Init(interp) == TCL_ERROR)
return TCL_ERROR;
/* association entre commandes
Tk et fonctions C */
Tcl_CreateCommand(interp,
"square_com", /* associe la cde square_com a la
fonction square */
square,
(ClientData)Tk_MainWindow(interp),
(Tcl_CmdDeleteProc *)NULL);
...
RETURN TCL_OK;
} |
Le script Tk est le suivant :
label .l -text "Entrez un nombre"
creation label
entry .e -textvariable val
creation zone de saisie
pack .l .e -side left
affichage
bind .e <Return> {square_com $val}
appel commande square_com
bind .e <Control-C> {exit} |
L'application est compilée
par :
gcc -o square square-main.c
square.c -ltk -ltcl -lm -lX11 -lsocket
6.
Etapes de réalisation
On distingue trois parties principales
dans la réalisation de l'application BIB-CCI, parties qui peuvent
être implantées et testées séparément
dans un premier temps, puis intégrées ensuite. L'intégration
comportera des tests d'intégration, permettant de valider l'ensemble
de l'application.
7.1 Manipulation des données
bibliothécaires
Cette partie consiste à définir
les structures de données utilisées, et à implanter
les fonctions de manipulation des données de la bibliothèque
énoncées en X. Bien entendu, il est possible de réaliser
des fonctions additionnelles dont l'utilité sera jugée pertinente.
La gestion des dates (accès à la date courante, calcul de
la date de retour d'un livre, etc) utilisera les fonctions fournies par
la librairie C (fonction gettimeofday par exemple).
7.2 Gestion des sauvegarde de la base
Cette partie consiste tout d'abord à
réaliser les fonctions de sauvegarde et de restauration des données,
depuis ou vers des fichiers. Cette première étape implique
de définir les formats de stockage des données sur disque
(organisation en fichiers, contenu des fichiers), ainsi qu'à implanter
les fonctions de translation des données en mémoire vers
des données persistentes, et inversement.
Il s'agit ensuite de rendre l'opération
de sauvegarde des données sur disque atomique, selon les principes
énoncés en 4.
7.3 Procédure
de reprise après
panne
Enfin, et si le temps le permet,
on cherchera à fournir une procédure de reprise après
panne en gérant un journal comme indiqué en 4.
Pour tester la procédure,
on utilisera le signal Ctrl-C, qui permet d'interrompre un processus Unix
dans son exécution.