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

MODES :

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).