Accueil | MEET | PFEG | IGC | STG | BTS IG | BTS SIO | Cours | Didactique | Exos | Glossaire | Labo | Sujets | Outils Imprimer cette page



Rechercher
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Cas Alarme - Mise en oeuvre avec Delphi

A/ Présentation de l'application

1. Fonctionnalités

Cette application a pour but de gérer les "post-it virtuels" de l'ensemble des collaborateurs d'une entreprise possédant un réseau d'ordinateurs.

A titre d'exemple :

  • Monsieur Martin veut se souvenir de partir à 17h15 cet après-midi pour son rdv de 18 heures chez le dentiste.
  • Madame Lesieur ne doit pas oublier de rappeler Monsieur Durand vers 10h30 demain matin.
  • Monsieur Allais doit payer la cantine le 25 de ce mois...

L'application doit en conséquence :

  • Permettre à l'utilisateur de s'identifier : je suis Monsieur Martin...
  • Autoriser la saisie d'un "post-it virtuel" (appelé ci-après une ALARME). Cette alarme doit être repérée comme concernant l'utilisateur connecté identifié à l'étape précédente.
  • Envoyer un message d'alerte sur l'écran de l'utilisateur lorsqu'une alarme doit être déclenchée.

2. Interface utilisateur

L'écran ci-dessous permet de s'identifier et de saisir de nouvelles alarmes.

Un simple message d'alerte suffira lors du déclenchement d'une alarme.

3. Architecture technique

Cette application peut être développée de multiples manières. En voici trois, à titre d'exemple...

Solution 1

L'application est mono-poste, développée à l'aide d'Access et installée sur chaque ordinateur du réseau

Avantages

Inconvénients

- Simplicité du développement

- Facilité de l'installation

- Impossible d'évoluer facilement vers la mise en commun des informations (alarmes collectives par exemple)

- Complexité des mises à jour du logiciel

Solution 2

L'application est répartie en deux éléments :

- Un SGBD situé sur un serveur qui gère une base de données contenant les alarmes

- Un programme installé sur chaque poste et accédant à la base de données via ODBC (par exemple)

Avantages

Inconvénients

- Simplicité du développement

- Possibilité d'évoluer vers une mise en commun des informations

- Facilité de sauvegarde des informations

- Complexité des mises à jour du logiciel (chaque amélioration doit être répercutée sur les postes de travail)

Solution 3

L'application est distribuée en 3 parties distinctes

- Le SGDB situé sur un serveur et responsable de la gestion des données concernant les alarmes

- Un programme "serveur" situé sur un autre serveur d'applications qui réalise l'ensemble des traitements (réception et transmission des demandes d'alarmes au SGBD, vérification périodique des alarmes à déclencher,...)

- Un programme "client" installé sur chaque poste qui utilise les services offerts par le programme "serveur" et présente l'interface de l'application à l'utilisateur (identification, saisie des alarmes, messages d'alertes)

Avantages

Inconvénients

- Possibilité d'évoluer vers une mise en commun des informations

- Facilité de sauvegarde des informations

- Possibilité de faire évoluer séparément les différentes composantes (changer de SGBD, améliorer les performances de l'application "serveur", modifier l'interface utilisateur)

- Equilibrage de la charge de travail des postes et des serveurs (avantage inintéressant pour cet exemple)

- Une certaine complexité de développement et d'installation du logiciel

Etant donné le titre de ce document, la solution 3 s'impose... Etant donné le sous-titre, Dcom s'impose...

Nous aurons donc le schéma suivant :

Il faut bien prendre conscience des différences entre les trois solutions et des avantages de la dernière.
L'évolutivité est certainement le plus important de ces avantages : la maintenance est la plaie de l'informatique de gestion...

Considérons un scénario d'évolution possible de cette application :

- Etape 1 : développement de l'application cliente et d'une première version de l'application serveur. Cette version mémorise toutes les informations en mémoire centrale (elle est localisée sur un serveur qui n'est jamais arrêté).

Dès cette première étape, l'ensemble est fonctionnel...

- Etape 2 : craignant de devoir subir une panne de courant accompagnée d'une panne d'onduleur, le responsable informatique demande la mise des alarmes sur disque.

On ne modifie absolument pas l'application cliente. Seul le programme serveur est remanié pour mémoriser ses informations sur disque à l'aide de fichiers.

- Etape 3 : le responsable du personnel souhaite pouvoir interroger simplement l'ensemble des alarmes stockées (même si cela se discute...). La solution adoptée est de modifier l'application serveur pour mémoriser les données à l'aide d'Access dont le QBE est facile à utiliser. Encore une fois, l'application cliente n'est pas modifiée. C'est la première apparition du troisième niveau...

- Etape 4 : l'entreprise fait l'acquisition du SGBDR Oracle et décide d'y transférer l'ensemble des bases de données existantes. La notre n'échappe pas à la règle... Seul le niveau "données" est concerné par cette évolution. Le programme serveur et le programme client ne sont pas modifiés.

Si vous avez du temps, n'hésitez pas à refaire l'ensemble du parcours... et même imaginer des étapes supplémentaires.

4. Phases de développement prévues

Dans le cas contraire, je vous propose de développer directement la dernière version. Nous pratiquerons en trois phases successives :

Phase 1: les utilisateurs

  • Données version 1 : les utilisateurs
  • Serveur version 1 : fournir la liste des utilisateurs au client
  • Client version 1 : permettre l'identification de l'utilisateur

L'identification sera très simpliste : choix dans une liste déroulante.

Phase 2: saisie des alarmes

  • Données version 2 : ajout des informations concernant les alarmes
  • Serveur version 2 : possibilité d'ajouter une alarme dans le système
  • Client version 2 : interface de saisie d'une nouvelle alarme

Phase 3 : exploitation des alarmes

  • Données : pas de modification
  • Serveur version 3 : délivrance des alarmes à déclencher au client, possibilité de supprimer une alarme
  • Client version 3 : interrogation périodique du serveur et message d'alerte lors du déclenchement d'une alarme

Remarques :

- Le SGBD utilisé importe peu.

- L'outil de développement utilisé est Delphi Professionnel version 6.

B/ Les utilisateurs

1. Base de données

a. Comment s'y prendre

Les utilisateurs seront mémorisés dans la table UTILISATEUR ( idUtilisateur, nomUtilisateur)

Etant donnée la rareté des mises à jour, les informations seront directement saisies au niveau du SGBD.

b. A vous de jouer

  • Constituez votre base de données et saisissez les 3 utilisateurs choisis pour le test de l'application :

    1 Lucien
    2 Marcel
    3 Robert

  • Créez ensuite une source de données ODBC permettant d'exploiter votre base.

2. Programme serveur

a. Approche algorithmique

> Principe

Le composant serveur est formé d'une interface et d'une classe implémentant cette interface :

Le programme client fait appel aux services du composant en manipulant un objet de type CoGestAlarme via l'interface IgestAlarme.

> Interface IgesAlarme

Il faut fournir un accès à la liste des utilisateurs recensés dans la base de données (ceci permettra notamment aux programmes clients d'afficher la liste déroulante prévue dans l'interface utilisateur).

Il nous faut donc concevoir un mécanisme permettant d'obtenir l'ensemble des utilisateurs. Voici une possibilité (ce n'est pas la seule) :

  • Une méthode premierUtilisateur(var p_id : entier, var p_nom : chaine) qui retourne l'identificateur et le nom du premier utilisateur s'il existe, 0 et la chaîne vide sinon.
  • Une méthode utilisateurSuivant(var p_id : entier, var p_nom : chaine) qui retourne l'identificateur et le nom de l'utilisateur suivant s'il existe, 0 et la chaîne vide sinon.

Ces deux méthodes permettent effectivement aux programmes clients de parcourir la liste des utilisateurs, elles constituent un itérateur.

L'interface IgestAlarme peut donc être décrite par :

Interface IgestAlarme

procédure premierUtilisateur(var p_id : entier, var p_nom : chaine)

procédure utilisateurSuivant(var p_id : entier, var p_nom : chaine)

Fin interface

> Classe CoGestAlarme

Il s'agit d'implémenter l'interface IgestAlarme. Le principe est simple : accéder à la base de données pour réaliser les deux méthodes prévues.

Classe CoGestAlarme (implémente IgestAlarme)

lesUtilisateurs : jeu d'enregistrements

procédure init

début

se connecter à la base de données

établir le lien entre lesUtilisateurs et la table utilisateurs

fin

procédure libérer

début

se déconnecter de la base de données

fin

procedure premierUtilisateur(var p_id: interger;var p_nom: chaine)

début

lesUtilisateurs.premier

si non (lesUtilisateurs.fin) alors

p_id ß lesUtilisateurs.valeur("idUtilisateur")

p_nom ß lesUtilisateurs.valeur("nomUtilisateur")

sinon

p_id ß 0

p_nom ß ""

fin de si

fin

procedure utilisateurSuivant (var p_id: interger;var p_nom: chaine)

début

lesUtilisateurs.suivant

si non (lesUtilisateurs.fin) alors

p_id ß lesUtilisateurs.valeur("idUtilisateur")

p_nom ß lesUtilisateurs.valeur("nomUtilisateur")

sinon

p_id ß 0

p_nom ß ""

fin de si

fin

Fin Classe

b. Mise en ouvre avec Delphi

> Création de l'application et du composant serveur (Interface IgestAlarme et CoClasse CogestAlarme)

Revoir si nécessaire le document "initiation aux objets distribués" : Delphi doit créer une classe TgestAlarme sur laquelle nous travaillerons effectivement.

> Accès aux données

Les objets de la CoClasse doivent pouvoir accéder aux données de la base. Il faut pour cela créer un module de données comportant un composant TDataBase et un composant TTable. Cette démarche est classique... Appelons ce module "dm" : Delphi crée un type Tdm et une variable dm de type Tdm.

Mais attention : chaque objet devra posséder son propre accès à la base ! Il faut donc ajouter un membre privé de type Tdm dans la classe TgestAlarme : appelons-le "dmPrive".

> Problème des sessions

Chaque composant orienté données existe et travaille à l'intérieur d'une "Tsession". Une session correspond à une connexion de l'application à une base de données (le concept est sensiblement le même que celui d'une session utilisateur lors d'une connexion interactive, mis à part le fait que l'identification n'est pas du ressort de la session, mais du composant database). Une session par défaut est définie automatiquement et chaque composant lui est rattachée. Cette session se nomme tout simplement "session".

Il existe des cas où l'on ne peut pas se contenter d'une seule session. En effet, il est impossible d'effectuer deux accès simultanés à la base à l'intérieur de la même session. Considérons notre application : si deux clients se connectent en même temps, il y aura création de deux objets de type TgestAlarme, donc de deux Tdm "dmPrive", un pour chacun d'entre eux. Supposons que les deux clients demandent en même temps la liste des utilisateurs pour l'afficher, il y aura deux accès simultanés à la base : il nous faut donc deux sessions. Pour les obtenir, rien n'est plus simple : il suffit d'ajouter un composant Tsession sur notre module de données et d'y lier les autres composants. Chaque objet possédant son propre Tdm (dmPrive), il possédera sa propre session.

Il reste un problème à régler : à l'intérieur d'une même application, il est impossible de gérer deux sessions portant le même nom. Comment appeler notre composant Tsession ? Une solution serait de lui attribuer un nom à la création du Tdm dmPrive (donc à la création de l'objet). En mémorisant le dernier numéro de session créée, on pourrait imaginer quelque chose comme :

numSession ß numSession+1

nom ß "session" + IntToStr(numSession)

Cette opération de "nommage automatique" est un peu complexe, il faudrait encore lier les composants du Tdm dmPrive à la session, cette liaison se faisant à l'aide du nom...

Delphi vient à notre secours, cette opération peut être automatisée : il suffit d'attribuer la valeur "true" à la propriété "autoSessionName" du composant Tsession et le tour est joué :

  • Chaque nouvelle session aura un nouveau nom (session1, session2, ...).
  • Tous les composants du module de données seront automatiquement reliés à cette session.

> Construction et destruction des objets

Chaque objet du type TgestAlarme représente la connexion d'un client et possède une propriété dmPrive de type Tdm. Cette propriété est de type classe et doit donc :

  • Etre construite par : dmPrive:=Tdm.Create(fm_servAlarme)

// fm_servAlarme est le nom de la fiche principale de l'application serveur, cette fiche sera donc propriétaire de tous les modules de données créés lors de l'exécution.

  • Etre détruite par : dmPrive.Free.

Classiquement, ces opérations se font en redéfinissant le constructeur et le destructeur de la classe de base de TgestAlarme (directive override). Or ici il est impossible de redéfinir le constructeur car la classe de base de toute classe d'objets COM (TComObject) possède un constructeur Create non virtuel.

Bien sûr, ce besoin d'initialisation des objets COM a été prévu, le constructeur de TComObject appelle systématiquement la méthode Initialize, virtuelle celle-là. Initialize ne fait rien... mais ne demande qu'à être redéfinie.

Il n'y a par contre aucun problème avec le destructeur Destroy, il peut être redéfini.

c. A vous de jouer

  • Créez l'application serveur : fiche principale ficheServAlarme.pas, projet servAlarme.dpr.
  • Ajoutez un module de données (nom dm, fichier datat.pas) contenant un composant TSession, un composant TDataBase et un composant TTable.
  • Ajoutez un objet ServeurAutomation (CoClasse gestAlarme) et créez les deux méthodes de son interface IgestAlarme : premierUtilisateur et utilisateurSuivant (WideString est le type à utiliser pour les paramètres de type chaîne des méthodes d'objets DCOM).
  • Complétez la classe TgestAlarme en ajoutant la propriété dmPrive, la rédéfinition de la méthode Initialize et celle du destructeur Destroy.

3. Programme client

a. Approche algorithmique

Il faut d'une part remplir la liste déroulante avec les informations fournies par l'objet alarme et mémoriser l'utilisateur sélectionné. Il est évident que l'on a intérêt à mémoriser l'identificateur de l'utilisateur sélectionné et non l'ensemble des informations.

> variables utilisées

alarme : IgestAlarme // l'objet distant

cb_utilisateur : comboBox // la liste déroulante

idUtilisateurConnecte : entier // le numéro de l'utilisateur connecté

> Au lancement de l'application

Il faut effectuer le traitement suivant :

  • créer l'objet distant
  • se servir de cet objet pour obtenir la liste des utilisateurs
  • remplir la liste déroulante

alarme ß CoGestAlarme.CreateRemote('192.168.210.2')

alarme.premierUtilisateur(id,nom);

tant que (id<>0) faire

cb_utilisateur.ajouter(id, nom);

alarme.utilisateurSuivant(id,nom);

fin tant que

> Lors du choix dans la liste déroulante

idUtilisateurConnecte ß cb_utilisateur.valeur("id")

b. Mise en ouvre avec Delphi

> Déclenchement des opérations

  • L'objet alarme doit être créé lors de la création de la fiche principale. C'est également à ce moment qu'il y a lieu de remplir la liste déroulante. Chaque ligne de la liste est la concaténation du numéro et du nom d'un utilisateur.
  • L'événement OnChange de la liste déroulante doit déclencher l'extraction et la mémorisation de l'identificateur de l'utilisateur sélectionné.

> L'application

La création de l'application ne pose pas de problème particulier. L'utilisation du composant serveur est décrite dans le document "initiation aux objets distribués".

c. A vous de jouer

  • Créez l'application (fiche principale fm_clientAlarme enregistrée sous ficheClientAlarme.pas, projet clientAlarme). L'objet distant pourrait s'appeler "alarme", la liste déroulante "cb_utilisateur".
  • Ajouter une propriété idUtilisateurConnecte à la classe de la fiche principale.
  • Mettez en place la création de l'objet distant alarme et le chargement de la liste à la création de la fiche principale.
  • Ecrivez la procédure de gestion de l'événement OnChange de la liste cb_utilisateur.
  • Testez l'ensemble : c'est le moment de vérité...

C/ Les alarmes

1. Base de données

a. Comment s'y prendre

Voici le schéma de la table à utiliser :

ALARME ( idAlarme, momentAlarme, libelleAlarme, utilisateur#)

L'attribut momentAlarme est de type DateHeure.

b. A vous de jouer

La seule difficulté est à venir : le type DateHeure du SGBD utilisé sera-t-il compatible avec le type correspondant dans l'outil de développement utilisé (TDateTime pour Delphi) ? Ce problème est récurrent, l'absence de normalisation est un frein important au développement des architectures distribuées.

2. Programme serveur

a. Approche algorithmique

Cette seconde phase est beaucoup plus simple que la première :

  • Il faut fournir une méthode setAlarme permettant aux clients d'ajouter une alarme (moment et libellé de l'alarme, utilisateur concerné).
  • Il faut mémoriser les alarmes envoyées par les clients dans la table précédemment créée.

b. A vous de jouer

  • Ajoutez le composant TTable nécessaire au module de données.
  • Modifier l'interface de la CoClasse pour ajouter la méthode setAlarme.
  • Compléter l'implémentation de la classe TgestAlarme pour fournir le code de cette méthode.

3. Programme client

a. Approche algorithmique

Lorsque l'utilisateur clique sur le bouton "Ajouter l'alarme", le programme client transmet les informations saisies à l'objet distant alarme en appelant sa méthode setAlarme.

b. Mise en ouvre avec Delphi

Les zones de saisie date et heure sont des composants TDateTimePicker. Ce composant est paramétrable et peut donc représenter une date (TDate) ou une heure (TTime).

Pour obtenir une valeur de type DateHeure (TDateTime), il suffit en fait d'ajouter une valeur de type date et une valeur de type heure. En effet, une valeur de type TDateTime est un réel dont la partie entière représente la date et la partie décimale représente l'heure.

c. A vous de jouer

  • Ajoutez et paramétrez les contrôles nécessaires à la saisie (composant date dtp_date, composant heure dtp_heure, tous les deux de type TDateTimePicker).
  • Rédigez la procédure déclenchée par un clic sur le bouton "ajouter". Il vous faut notamment calculer le moment de l'alarme. Il suffit pour cela d'affecter la valeur "Time" du composant "dtp_heure" à la propriété "Time" du composant "dtp_date". A l'issue de cette affectation, la propriété "DateTime" du composant "dtp_date" contiendra le moment complet saisi par l'utilisateur.
  • Testez le tout en ajoutant des alarmes et en vérifiant leur présence dans la base de données.

D/ Le réveil sonne

1. Base de données

a. Comment s'y prendre

Il n'y a rien à faire !!!

b. A vous de jouer

Aucun problème si vous avez lu le paragraphe précédent...

2. Programme serveur

a. Approche algorithmique

Il faut offrir aux clients la possibilité de récupérer sur demande la (ou les) alarme(s) éventuelle(s) à déclencher en fonction de l'heure système du serveur.

Le fonctionnement pourrait être le suivant :

  • Le client contacte régulièrement le serveur en demandant les alarmes à déclencher pour l'utilisateur connecté.
  • Le serveur lui fournit les alarmes à déclencher en utilisant un mécanisme d'itérateur comparable à ce qui a été réalisé pour la liste des utilisateurs. Pour rechercher les alarmes éventuelles, le serveur se base sur sa propre horloge système.
  • Le client affiche à l'utilisateur les éventuelles alarmes obtenues et demande au serveur de les supprimer.

b. A vous de jouer

  • Ajouter les méthodes premiereAlarme et alarmeSuivante à l'interface IgestAlarme et rédigez leurs implémentations dans la classe TgestAlarme. Vous pouvez utiliser un composant TQuery paramétré pour interroger la base de données.
  • Vous devez également fournir une méthode permettant de supprimer une alarme de la base.

3. Programme client

a. Approche algorithmique

Le programme client doit interroger régulièrement le serveur. A chaque interrogation, le traitement consiste à récupérer les éventuelles alarmes :

demander la première alarme à l'objet distant

tant qu'il y a une alarme faire

afficher le libellé de l'alarme à l'utilisateur

demander sa suppression à l'objet distant

demander l'alarme suivante à l'objet distant

fin tant que

b. A vous de jouer

  • Ajoutez un composant TTimer à votre fiche principale (ce composant génère un événement OnTimer à intervalles réguliers). Réglez-le pour un déclenchement toutes les minutes.
  • Rédigez la méthode déclenchée par l'événement OnTimer : il suffit d'écrire une boucle dans laquelle on demande une alerte au serveur, on l'affiche à l'utilisateur puis on demande sa suppression au serveur.
  • Testez votre application sur au moins un serveur et deux clients correspondant à des utilisateurs différents.

Pour aller plus loin...

Il est possible d'envisager plusieurs évolutions de cette application (liste non exhaustive !) :

  • Le temps de référence pour les alarmes est celui du serveur : il serait possible de permettre le choix à l'utilisateur : temps du serveur ou temps de sa station.
  • Un mot de passe pourrait être attribué à chaque utilisateur pour son identification.
  • On pourrait permettre à l'utilisateur de reprogrammer une alarme qui vient d'être déclenchée (rappeler dans 3 jours, dans deux heures, ...).
  • Un autre programme client pourrait permettre à un chef de service de fixer une alarme pour un ensemble de personnes (pour rappeler une réunion prévue par exemple).
   

_____________________________________________  
© - Réseau C E R T A 

Ministère de l'Éducation Nationale