Le modèle d'objet INTERFACE
Les composants sont capables de communiquer avec l'extérieur par l'intermédiaire de leur interface. Pour simplifier la programmation, Oxygène fournit un modèle INTERFACE qui prend en charge de manière automatique les mécanismes de connexion et de déconnexion nécessaires à tout dialogue. C'est donc dans l'objet INTERFACE (dérivant du modèle INTERFACE) que le concepteur du composant va décrire l'ensemble des services que le composant est capable de prendre en charge.
Liste des déclarations
BASE | Base de données | ||
TABLE |
Table principale |
||
SOCIETE | Code de la société | ||
MODES |
Modes de connexion et options | ||
TABLE_INTERFACE |
Contexte de travail sur les données de la table d'interface |
Liste des méthodes spécialisées
CONNECTE | Connexion du composant | ||
DECONNECTE | Déconnexion du composant | ||
LECTURE | Lecture suivant l'identifiant | ||
AFFECT_INTERFACE | Affectation des données d'interface | ||
INIT_INTERFACE | Initialisation des données d'interface | ||
LECTURE_CODE | Lecture suivant le code | ||
RECHERCHE_CODE | Recherche suivant le code | ||
RECHERCHE_DESIG | Recherche suivant la désignation | ||
ECRITURE | Ecriture et modification | ||
AFFECT_TABLE | Affectation des données permanentes | ||
ATTRIBUE_NUMERO | Attribution de l'identifiant | ||
DIALOGUE | Méthode pour les messages standards | ||
GESTION | Appel à l'objet GESTION du composant | ||
CHOIX | Appel à l'objet CHOIX du composant | ||
ACCES | Appel à l'objet ACCES du composant | ||
NOM_BASE |
Rend le code de la base de données | ||
NOM_TABLE | Rend le code de la table | ||
TAILLECACHELECTURE | Définit la taille du cache de lecture |
||
TAILLECACHEECRITURE | Définit la taille du cache d'écriture |
||
BASCULERCONTEXTEMEMOIRE | Bascule sur le contexte en mémoire avec copie des données | ||
BASCULERCONTEXTEDISQUE | Bascule sur le contexte disque (sans bascule des données) |
Fonctionnement de l'interface du composant
Une des caractéristiques essentielles de l'interface d'un composant est sa capacité à échanger des informations avec l'extérieur. La programmation classique Oxygène permet déjà d'échanger des données en utilisant l'appel de méthodes avec passage de paramètres. Cependant, ce mécanisme s'avère fastidieux dès que le volume d'informations à transférer est important. Pour pallier ce problème, l'interface des composants dispose d'un nouveau moyen de communication basé sur une structure d'interface décrite dans le descripteur de données d'Oxygène. Cette structure d'interface (appelée aussi table d'interface) décrit l'ensemble des données publiques du composant. Les données d'interface peuvent être le simple reflet des données persistantes du composant ou au contraire le résultat de traitements sophistiqués.
On touche ici une notion fondamentale de la programmation "composant".
Le fait de communiquer les informations par l'intermédiaire d'une structure
d'interface donne la possibilité de faire évoluer le stockage des données
permanentes sans remettre en question le reste du logiciel.
Pour profiter au maximum des automatismes du modèle INTERFACE,
le programmeur doit respecter les conventions suivantes :
- La table principale destinée à stocker les données persistantes du composant doit porter le même nom que le composant.
- Le nom de la structure d'interface est composé de "I_" suivi du nom du composant.
- Le nom des champs les plus fréquents ont également été normalisés. On donne le code "IDENT" à la clé primaire des données permanentes, le code "CODE" à l'identifiant manipulé par l'utilisateur et le code "DESIG" à la désignation de l'entité traitée par le composant.
Le respect de ces quelques conventions permet de minimiser considérablement la programmation puisque les méthodes standards du modèle n'auront pas à être redéfinies.
Les déclarations standards
BASE :
La base est une information indispensable au fonctionnement de l'interface. Sa déclaration peut être effectuée dans l'objet, mais il est conseillé de la déclarer au niveau des déclarations globales du composant.
TABLE :
La déclaration TABLE est facultative dans un objet dérivant du modèle INTERFACE. En effet, le modèle postule que la table principale porte le même nom que le composant. Dans le cas où les données persistantes du composant ne sont pas stockées sur une table disque de la base de données, les automatismes de lecture peuvent être désactivés par la déclaration MODES : "V".
TABLE_INTERFACE :
TABLE_INTERFACE n'est pas une déclaration proprement dite. C'est un contexte de travail qui permet au programmeur d'intervenir sur les données de la table d'interface. Ce contexte se manipule comme un contexte de table mémoire classique. Les instructions Lire, Modifier et InitTampon sont donc utilisables. Néanmoins, les méthodes standards du modèle sont prévues pour que le programmeur n'ait pas à les utiliser.
SOCIETE :
La déclaration SOCIETE permet de forcer la société de travail (on parle aussi de dossier). Cette déclaration est cependant déconseillée dans l'objet INTERFACE, car l'objet utilisateur de l'interface est susceptible de préciser au moment de la connexion la société sur laquelle il travaille. Pour de plus amples informations, consulter la description de l'instruction SocieteComposant.
Les déclarations spécialisées du modèle
La déclaration MODES permet d'agir sur le comportement par défaut de l'interface du composant.
Le mode "virtuel" : (MODES : "V")
Il permet d'inhiber les automatismes de lecture des données permanentes. On l'utilise en général pour des composants qui ne stockent pas leurs données de façon classique (pas de table principale).Le mode "Serveur" : (MODES : "S")
Il influe sur les mécanismes de connexion et de déconnexion. Par défaut, le dialogue établi fonctionne suivant le mode point-à-point&&, cela signifie que l'interface du composant est "instanciée" pour chaque contexte d'utilisation. Le mode "Serveur" permet de travailler sur une interface unique (une seule instance). Cette option doit être manipulée avec précaution en particulier lorsque le composant met à disposition des services qui ne sont pas effectués de manière synchrone. Les risques de conflits et de phases critiques sont particulièrement fréquents et difficiles à résoudre dans ce mode.
Les méthodes spécialisées du modèle
CONNECTE et DECONNECTE
Ces deux méthodes prennent en charge la connexion et la déconnexion. La méthode CONNECTE est appelée automatiquement dès qu'un utilisateur sollicite une des méthodes publiques du composant. La méthode DECONNECTE est appelée lorsque l'utilisateur du composant disparaît.
En pratique, la programmeur a peu d'intérêt à redéfinir ces deux méthodes. Le comportement pas défaut tient compte du mode déclaré. En mode "Serveur", les méthodes CONNECTE et DECONNECTE sont déclenchées pour chaque utilisateur connecté.
La variable héritée 'NbUtil' contient en permanence le nombre d'utilisateurs connectés. L'objet INTERFACE se détruit automatiquement dès que 'NbUtil' passe à zéro, c'est-à-dire lorsque le composant n'est plus utilisé.
LECTURE
Cette méthode est utilisée pour lire les données publiques du composant. Elle reçoit en paramètre l'identifiant unique de l'entité traitée et rend le résultat à l'appelant par l'intermédiaire des données d'interface.
Le comportement par défaut est le suivant :
Si l'identifiant reçu en paramètre n'est pas vide et que l'enregistrement est bien lu (sur la table principale), la méthode AFFECT_INTERFACE est appelée. Dans le cas contraire c'est la méthode INIT_INTERFACE qui est déclenchée.
La structure d'interface est alors mise à jour (Modifier TABLE_INTERFACE) et l'erreur renvoyée par les méthodes AFFECT_INTERFACE ou INIT_INTERFACE est retransmise à l'appelant (ErreurARendre=ErreurRendue).
Remarque : la méthode n'effectue aucun traitement si les conventions ne sont pas respectées. En particulier si le champ IDENT n'est pas un champ de la table principale ou si la table principale n'existe pas (cf : MODES : "V").
La programmation de la méthode LECTURE :
Methode LECTURE
Parametres : Chaine pident
Si pident<>"" Et Lire (TABLE.IDENT, EgalA,
pident) Alors
AppliquerMethode
"AFFECT_INTERFACE"
Sinon
AppliquerMethode
"INIT_INTERFACE"
FinSi
Modifier TABLE_INTERFACE //Contexte
sur les données d'interface
ErreurARendre=ErreurRendue
finObjet
En général, on évite de redéfinir la méthode LECTURE. Les méthodes INIT_INTERFACE et AFFECT_INTERFACE décrites ci-dessous sont conçues pour traiter les cas particuliers.
INIT_INTERFACE
Elle est appelée par la méthode LECTURE (Voir ci-dessus). Elle initialise les données d'interface et renvoie l'erreur 1 (ErreurARendre=1) à l'appelant pour indiquer que la fiche n'a pas été lue. Cette méthode est en général redéfinie lorsque l'initialisation par défaut ne convient pas. On peut par exemple modifier ici la valeur par défaut des champs de la table d'interface.
Methode INIT_INTERFACE
AppliquerDefaut //Indispensable
TABLE_INTERFACE.CODE="<Aucune famille>"
TABLE_INTERFACE.DESIG="Famille non définie"
FinMethode
- La mise à jour de la table d'interface par l'instruction modifier ne doit pas être effectuée ici, c'est la méthode LECTURE qui s'en charge.
- L'utilisation de l'instruction InitTampon TABLE_INTERFACE est interdite, car la table d'interface contient des informations complémentaires qu'il ne faut pas initialiser. Ces informations permettent la gestion du dialogue, elles sont automatiquement initialisées par le modèle ; l'utilisation de l'instruction AppliquerDefaut est donc indispensable.
AFFECT_INTERFACE
Elle est appelée par la méthode LECTURE. Par défaut, elle remplit les champs de la table d'interface par ceux de la table principale qui ont le même code et rend l'erreur 0. Il faudra redéfinir cette méthode si la table d'interface contient des informations calculées ou provenant d'une autre source que la table principale.
Methode AFFECT_INTERFACE
AppliquerDefaut
TABLE_INTERFACE.STOCK_VIRTUEL=TABLE.QTE_STOCK-TABLE.QTE_A_LIVRER
FinMethode
LECTURE_CODE, RECHERCHE_CODE et RECHERCHE_DESIG :
Ces méthodes fonctionnent de manière identique à la méthode LECTURE. Elles différent simplement par le critère de recherche et/ou l'opérateur utilisé. Le premier paramètre reçu n'est pas l'identifiant de l'enregistrement recherché, mais son code ou sa désignation.
Méthode Requête effectuée
LECTURE_CODE Lire TABLE.CODE, EgalA, pcritere
RECHERCHE_CODE Lire TABLE.CODE, DebutePar, pcritere
RECHERCHE_DESIG: Lire TABLE.DESIG, DebutePar, pcritere
(pcritere représente ici le paramètre reçu à l'appel)
Le mécanisme standard d'appel aux méthodes INIT_INTERFACE et AFFECT_INTERFACE est utilisé. Les données de l'enregistrement trouvé sont rendues par l'intermédiaire de la table d'interface. La variable système ErreurRendue est également renseignée.
ECRITURE
Cette méthode est utilisée pour modifier ou créer un enregistrement dans le composant. Si le composant possède une table principale, on utilise le premier paramètre (passé par référence) comme identifiant de l'enregistrement à écrire ou à modifier.
Si ce paramètre est vide, il s'agit alors de la création d'un nouvel enregistrement. Cette méthode appelle alors la méthode ATTRIBUE_NUMERO qui va remplir le champ IDENT par une valeur unique.
Si, en revanche, le premier paramètre est non vide, celui-ci est utilisé pour se positionner sur un enregistrement existant. Si l'enregistrement n'existe pas, la méthode DIALOGUE est appelée pour signaler l'erreur et ErreurARendre est positionnée à 1.
Si aucune anomalie n'est détectée, la méthode AFFECT_TABLE est appelée et l'opération (création ou modification) est effectuée.
Une fois l'enregistrement des données permanentes faites, la méthode AFFECT_INTERFACE est appelée et ErreurARendre est mis à zéro. Après l'appel à ECRITURE, l'appelant peut donc exploiter les données d'interface directement sans rappeler la méthode LECTURE.
AFFECT_TABLE
Cette méthode est appelée par la méthode ECRITURE et reçoit en paramètre une chaîne lui indiquant le contexte d'appel. La chaîne contient la lettre "C" lors d'une création et la lettre "M" lors d'une modification. Par défaut, elle remplit les champs de la table principale par les données d'interface qui ont le même code et ErreurARendre est positionnée à 0.
Cette méthode doit être redéfinie pour initialiser les données non publiques du composant, en particulier lorsque l'interface n'est pas le reflet exact de la table disque. C'est également l'endroit idéal pour mettre à jour des tables en lien car, dans le cas d'une création et bien que l'enregistrement ne soit pas encore créé, l'identifiant (IDENT) est déjà significatif.
ATTRIBUE_NUMERO
ATTRIBUE_NUMERO est utilisée par la méthode ECRITURE pour attribuer un identifiant unique lors de la création d'un nouvel enregistrement. Elle reçoit un paramètre par référence qui rend à l'appelant l'identifiant attribué. Par défaut, l'attribution de l'identifiant unique fait appel aux services du composant OXYNDOC qui est fournit en standard dans OXYGENE.
La programmation standard de ATTRIBUE_NUMERO :
Methode ATTRIBUE_NUMERO
Parametres : Chaine Reference numero_attribue
AppliquerMethodeComposant "OXYNDOC"."ATTRIBUE_NUMERO"
(ndocumbase,"NUMEROS",ndocumid,ndocumprefx,ndocumlong,numero_attribue)
AppliquerMethodeComposant "OXYNDOC"."VALIDE_NUMERO"
(ndocumbase,"NUMEROS",ndocumid,ndocumprefx,ndocumlong,numero_attribue)
FinMethode
Les variables 'nDocumBase', 'nDocumId', 'nDocumPrefx', 'nDocumLong' sont des variables héritées du modèle INTERFACE. Le programmeur peut donc intervenir sur l'attribution de l'identifiant sans redéfinir la méthode. Ces variables ont les valeurs par défaut suivantes :
NDocumBase = Base du composant
NDocumID = Nom du composant
NDocumPrefx = vide par défaut
NDocumLong = zéro par défaut
Il est fréquent de redéfinir cette méthode pour adapter dynamiquement le préfixe de numérotation. On modifie pour cela la variable héritée 'nDocumPrefx' avant d'appeler l'implémentation standard par l'instruction AppliquerDefaut.
Dans certains cas, le logiciel souhaite que les numéros soient complétés à gauche par des zéros (pour obtenir par exemple 001, 002, 003 &). Il faut dans ce cas préciser la longueur du numéro attribué en modifiant la valeur par défaut de la variable héritée 'nDocumLong'.
La
table NUMEROS doit être une table définie
dans le descripteur de données d'Oxygène. Pour plus d'informations
sur la structure de la table NUMEROS et du composant OXYNDOC.
Méthode DIALOGUE
La méthode est appelée avec deux paramètres : le premier fournit un code de message et le deuxième (passé par référence) permet de renvoyer le choix de l'utilisateur. Le code du message peut être :
INFOS_MANQUANTES : si les informations relatives à la numérotation sont incomplètes.
IDENT_INCORRECT : si l'identifiant du composant est incorrect (méthode ECRITURE utilisée avec un identifiant ne correspondant à aucun enregistrement).
Cette méthode est redéfinissable pour permettre de personnaliser les messages de manière à faciliter la maintenance du logiciel.
Méthode GESTION
Cette méthode a pour fonction d'appeler l'objet GESTION du composant. Le premier paramètre est la valeur de l'identifiant qui permettra un positionnement automatique sur l'enregistrement ainsi désigné. Le deuxième paramètre est la valeur de la déclaration MODES à passer à l'objet.
Si la méthode est appelée de manière synchrone (en utilisant l'instruction AppliquerMethodeComposant), l'objet est lui-même appelé de manière synchrone par l'instruction AppelerObjet. Si, au contraire, la méthode est appelée par un EnvoyerMessageComposant, l'objet est "instancié" par un CreerObjet.
La
méthode GESTION transmet tous les paramètres qu'elle reçoit à l'objet
GESTION. Il est donc inutile de la redéfinir pour ajouter des paramètres
complémentaires.
C'est l'instruction ModeAppel du
langage qui permet de déterminer si l'appel est effectué de manière synchrone
(valeur rendue égale à 0) ou asynchrone (différent de 0).
Méthode ACCES
La méthode ACCES fonctionne de façon similaire à la méthode GESTION. Elle effectue un appel (synchrone ou asynchrone) de l'objet ACCES du composant. Elle ne prévoit qu'un seul paramètre standard qui correspond à l'identifiant de l'enregistrement souhaité.
Méthode CHOIX
Cette méthode appelle en synchrone l'objet CHOIX du composant. Le premier paramètre, passé par référence, permet de récupérer l'identifiant de l'enregistrement choisi. Ce choix est en général effectué par l'intermédiaire d'une liste à l'écran.
Si l'utilisateur a effectivement choisi un enregistrement, la variable système ErreurRendue est positionnée à 0 et les données d'interface sont renseignées par l'appel à la méthode LECTURE (qui elle-même appelle AFFECT_INTERFACE).
Si l'utilisateur a abandonné, ErreurRendue est positionnée à 1 et les données d'interface reste inchangées. Si le choix "AUCUN" a été effectué, ErreurRendue est mis à 2 et les données d'interface sont réinitialisées par l'appel à la méthode LECTURE avec un identifiant à vide (provoquant l'appel de INIT_INTERFACE).
Pour récupérer le résultat,
il est nécessaire d'appeler cette méthode de manière synchrone grâce à
l'instruction AppliquerMethodeComposant.
Comme la méthode GESTION, la méthode CHOIX transmet tous les paramètres
qu'elle reçoit à l'objet CHOIX. Cependant, l'objet CHOIX attend en deuxième
paramètre un entier (passé par référence) destiné à récupérer l'action
de l'utilisateur. Il faut bien comprendre que le paramètres n°2 de la
méthode CHOIX correspond au paramètre n°3 de l'objet CHOIX et ainsi de
suite.
Méthode NOM_BASE
Rend le code de la base de données du composant.
Méthode NOM_TABLE
Rend le code de la table du composant.
Méthode TAILLECACHELECTURE (Réservée SQL)
PARAMETRES : Double ptaille
TailleCacheLecture(TABLE) = ptaille
Définit la taille du cache de lecture.
Méthode TAILLECACHELECRITURE (Réservée SQL)
PARAMETRES : Double ptaille
TailleCacheEcriture(TABLE) = ptaille
Définit la taille du cache d'écriture.
Méthode BASCULERCONTEXTEMEMOIRE (Réservée SQL)
CreerContexteMemoire(TABLE)
PeupleContexteMemoire TABLE, ""
BasculerContexteMemoire(TABLE)
Bascule sur le contexte en mémoire avec copie des données.
Méthode BASCULERCONTEXTEDISQUE (Réservée SQL)
BasculerContexteDisque(TABLE)
Bascule sur le contexte disque (sans bascule des données).