Les tutoriels de Sashipa

 

Pour apprendre le langage Sashipa, vous pouvez commencer par :

Par la suite, ce sont les HOWTO qui vous seront utiles, en documentation de référence.

 


 

Tutoriel avec approche théorique

Précisions sur les bases de données

Introduction

Bases de données relationnelles

Identifiants, les bonnes manières

Fonctionalités du SGBD à éviter !

Aperçu d'un fichier Sashipa

Environnement

Graphical User Interface

Structure générale

Les composants de la GUI

Conception en Sashipa

Les serveurs Sashipa

Le déploiement généré

Annexes

Glossaire

 

Précisions sur les bases de données

Introduction

Sashipa est un format XML pour décrire des applications interfaces de bases de données relationnelles. Je donne ici quelques précisions sur les bases de données avec lesquelles Sashipa-Melba peut travailler.

Voici un tutoriel pour écrire vos premières applications Sashipa. Il repose sur l'exemple de la base DemoContact. Si vous ne l'avez pas déjà installée, cliquez ici.

Bases de données relationnelles

Une base de données relationnelle est un ensemble de tables composées chacunes de colonnes. Les données sont les lignes. On les appelle aussi enregistrements ou tuples.

Une base est créée, puis interrogée, au moyen d'un langage standard : le SQL.

Voici le script SQL de création de la base des Contacts :

    CREATE TABLE PROFESSION (
      ProfessionId integer NOT NULL PRIMARY KEY,
      ProfessionLabel varchar(100) NOT NULL UNIQUE
    );

    CREATE TABLE CONTACT (
      ContactId integer NOT NULL PRIMARY KEY,
      ContactNom varchar(100) NOT NULL,
      ContactPrenom varchar(100),
      TelPortable varchar(20),
      Email1 varchar(100),
      Email2 varchar(100),
      Commentaire text,
      ProfessionRef integer NOT NULL REFERENCES PROFESSION(ProfessionId),
      FonctionLabel varchar(100),
      UNIQUE (ContactNom, ContactPrenom)
    );

    CREATE TABLE CONTACTADRESSE (
      ContactAdresseId integer NOT NULL PRIMARY KEY,
      ContactAdresseLabel varchar(100) NOT NULL,
      IsProfessionnelle integer NOT NULL,
      AdresseRue varchar(255),
      AdresseCP char(5),
      AdresseVille varchar(255),
      Tel1 varchar(20),
      Tel2 varchar(20),
      Fax varchar(20),
      Email varchar(100),
      ContactRef integer NOT NULL REFERENCES CONTACT(ContactId),
      UNIQUE (ContactRef, ContactAdresseLabel)
    );

Identifiants, les bonnes manières

Chaque table dispose d'une clef primaire, le plus souvent composée d'une unique colonne de type integer (exemple : ProfessionId pour la table PROFESSION). Cette colonne servira exclusivement à identifier les lignes de façon unique au sein de la base. Les données mises dans cette colonne ne devront jamais être modifiées par la suite sous peine de rendre la base non intègre.

En règle générale, les valeurs d'une clef primaire ne sont jamais affichées à l'utilisateur. En effet, si c'était le cas, l'utilisateur les utiliserait pour ses propres besoin (pour ses dossiers papier par exemple) et tôt ou tard aurait besoin de les modifier.

L'utilisateur a besoin, lui aussi, d'identifier chaque ligne de la table. On utilise pour cela la contrainte UNIQUE qui fonctionne comme une clef primaire, sauf qu'elle ne permet pas de faire de liens entre les tables (exemple: ProfessionLabel pour la table PROFESSION).

Pour chaque table, on peut donc distinguer l'identifiant "base de données" (la clef primaire) de l'identifiant "utilisateur" (la contrainte UNIQUE).

Les liens entre les tables sont faits au moyen de clefs étrangères référençant les clefs primaires. Exemple: ProfessionRef dans la table CONTACT référence la colonne ProfessionId de la table PROFESSION. Ceci implique que les valeurs que l'on trouve dans CONTACT.ProfessionRef pointent sur les valeurs de PROFESSION.ProfessionId. De cette manière, on peut retrouver la profession de chaque contact.

Pour une explication détaillée, voir l'article Clefs et base de données, les bonnes manières.

Fonctionalités du SGBD à éviter !

Attention : concernant les clefs primaires auto-incrémentées par le SGBD, cette fonctionnalité n'est pas supportée pour tous les SGBD. Mais vous pouvez remédier facilement à ça, cf la HOWTO. Vous pouvez aussi déclarer une clef primaire comme un simple 'integer' et une valeur sera automatiquement générée par l'application lors d'un ajout.

Deuxième problème : les applications générées disposent d'un cache pour mémoriser les derniers enregistrements chargés. Ce cache est rafraichi lorsque la partie serveur (la servlet) signale une modification faite par une de ses applications clientes. Donc vous aurez des problèmes de cache non à jour si vous faites des modifications par triggers ou si un programme tiers accède à la base sans passer par la servlet.

 

Aperçu d'un fichier Sashipa

Vous trouverez le source ici.

Voici pour commencer le squelette de l'application DemoContact en Sashipa.

    <?xml version='1.0' encoding='ISO-8859-1' ?>

    <!DOCTYPE application SYSTEM 'resources/sashipa.dtd' [
      <!ENTITY br '&#xA;'>
      <!ENTITY nbsp '&#x20;'>
      <!ENTITY frenchDefinition SYSTEM 'resources/SashipaFrench.xml'>
      <!ENTITY englishDefinition SYSTEM 'resources/SashipaEnglish.xml'>
    ]>


    <application name='AppliContacts'>

    <!--........ environment ........ -->

    <environment>
    <!-- ... description des SGBD et de leurs bases ... -->
    </environment>

    <!--........ graphicalUserInterface ........ -->

    <graphicalUserInterface name='guiContact'>
    <!-- ... description de l'interface utilisateur ... -->
    </graphicalUserInterface>

    <!--........ servers ........  -->

    <serverSet guiType='application'>
    <!-- ... description of the Sashipa servers and connections
                to DBMS ... -->
    </serverSet>

    <!--........ architecture ........  -->

    <architecture>
    <!-- ... description of deployment and used language ... -->
    </architecture>

    </application>

Les principales parties de ce fichier XML sont :

  • La description de la structure de l'environement serveur et de sa base de données DemoContact
  • La description de l'interface utilisateur (GUI pour Graphical User Interface)
  • La description des serveurs.
  • La description de déploiementde votre application.

 

Environnement

La première partie d'un fichier Sashipa est la description de l'environnement serveur. Le nom réel du serveur est stocké dans <physicalName>.

Remarque : le nom 'dbmsMain' est interne au fichier Sashipa et sert quand des éléments du fichier font référence à ce serveur. Notez que c'est un point commun à chaque élément dans Sashipa : l'attribut "name" d'un composant sert uniquement à l'identification de celui-ci au sein du fichier Sashipa et ne correspond pas au nom réel.

    <environment>
      <dbmsSet>
      <dbms name='dbmsMain'>
        <physicalName>localhost</physicalName>
        <databaseSet>

        <!-- ... description des bases de données  ... -->

        </databaseSet>
      </dbms>
      </dbmsSet>
    </environment>

C'est ici, notamment, qu'est décrite la base de données DemoContact. Je donne ci-dessous la description de la table "PROFESSION" ainsi que de la colonne CONTACT.ProfessionRef pour un exemple de clef-étrangère.

    <database name='dbContact'>
      <physicalName>DemoContact</physicalName>
      <singularName>Base des Contacts</singularName>
      <schemaTableSet>

      <!-- ............. PROFESSION ............. -->

      <schemaTable name='tableProfession'>
        <physicalName>PROFESSION</physicalName>
        <singularName>Profession</singularName>
        <pluralName>Profession(s)</pluralName>
        <schemaColumnSet>
        <schemaColumn name='pro_ProfessionId' type='integer'
                      notNull='yes' pk='yes'>
          <physicalName>ProfessionId</physicalName>
          <singularName>Identity</singularName>
        </schemaColumn>
        <schemaColumn name='pro_ProfessionLabel' type='text' notNull='yes'
                      maxCharacters='100'>
          <physicalName>ProfessionLabel</physicalName>
          <singularName>Profession</singularName>
          <guiConfigSchemaColumn letterCount='20' sort='asc' />
        </schemaColumn>
        </schemaColumnSet>
        <userKey>
          <userKeyColumn schemaColumn='pro_ProfessionLabel' />
        </userKey>
      </schemaTable>

      <!-- ............. CONTACT ............. -->

      <schemaTable name='tableContact'>
        <schemaColumnSet>
          ...
        <schemaColumn name='cta_ProfessionRef'
                      type='integer' notNull='yes'>
          <physicalName>ProfessionRef</physicalName>
          <singularName>Profession</singularName>
        </schemaColumn>
          ...
        </schemaColumnSet>
        <schemaFkSet>
          <schemaFk name='fk_cta_Profession'
                    targetSchemaTable='tableProfession'>
            <schemaColumnRef schemaColumn='cta_ProfessionRef' />
          </schemaFk>
        </schemaFkSet>
      </schemaTable>

      </schemaTableSet>
    </database>

 

Graphical User Interface

Structure générale

Voici la structure générale d'une GUI Sashipa.

    <graphicalUserInterface name='guiContact'>

    <resourceName>Contact</resourceName>

    <mainTitle>[Contact]</mainTitle>
    <separatorTitle> - </separatorTitle>
    <size w='800' h='600' />

    <guiStarting>
      <loadingScreen>
      <mainScreenRef screen='SMMain' />
    </guiStarting>

    <screenSet>
    <!-- ... liste des Screens ... -->
    </screenSet>

    <formSet>
    <!-- ... liste des Forms ... -->
    </formSet>

    </graphicalUserInterface>

Important : le bloc <resourceName> contient le nom de la classe principale de l'application. La commande de lancement de votre application généré sera donc "java Contact" dans notre cas.

Le bloc <mainScreenRef> précise le premier écran qui sera affiché lors du lancement de l'application.

Les composants de la GUI

L'apparence de l'interface d'une base de données est fortement liée au schéma (la structure) de sa base de données. Sashipa distingue trois niveaux dans les composants de cette interface : les Screens, les Forms et les Fields.

Je ne donne pas d'exemple de code XML pour les composants de la GUI. Je recommande au lecteur de se référer au code source pour visualiser concrètement ce qu'il lit.

Les Screens

Une application interface de base de données affiche une succession d' écrans : ce sont les Screens. L'application n'affichera qu'un unique Screen à la fois.

Les Forms

Un Screen est un conteneur de formulaires. Pour chaque table, on aura les formulaires suivant :

  • Une fiche de consultation / modification qui travaille ligne par ligne dans la table. C'est le CardForm.
  • Une liste pour afficher un sous-ensemble ou la totalité de la table. C'est le ListForm.
  • Un formulaire de recherche pour retrouver des enregistrements dans la table. C'est le ResearchForm et il utilise lui-même le ListForm pour afficher les résultats de la recherche.
  • Dans le cas des tables comportant beaucoup d'enregistrements qu'il faut référencer : un formulaire pour sélectionner l'enregistrement. C'est le SelectRecordForm. Celui-ci se base sur le ResearchForm.

De plus, on crée les menus avec les MenuForm. Les menus sont indépendants des tables. Un menu permet d'ouvrir d'autres Screens.

Les Fields et FkFields

Les formulaires CardForm et ResearchForm contiennent un ensemble de champs. Il existe deux catégories de champs :

  • Les champs simples (Fields) affichant la valeur d'une colonne de la table du formulaire.
  • Les champs de clefs étrangères (FkFields) permettant à l'utilisateur de sélectionner une ligne de la table liée référencée par la clef étrangère.

Voici la liste des Fields disponibles :

  • Le champ qui affiche une valeur sous forme de texte. C'est le champ textField.
  • Le champ qui affiche une valeur textuelle sur plusieurs lignes. C'est le champ textAreaField.
  • Le champ pour afficher une valeur booléenne. C'est le champ checkBoxField.

Et la liste des FkFields :

  • Le champ affichant la liste des lignes sélectionnables. C'est le champ comboBoxFkField. L'équivalent du Combo-box.
  • Le champ affichant la liste des lignes sélectionnables et permettant en outre de saisir une valeur existante. C'est le champ writeChoiceFkField.
  • Le champ affichant la ligne référencée sans permettre de la modifier. C'est le readOnlyTextFkField. Ce champ est à utiliser en association avec un SelectRecordForm. C'est la solution lorsque la liste des enregistrement à choisir est trop importante.

Conception en Sashipa

Voici quelques notions théoriques sur comment déduire une interface graphique d'un schéma de base de données.

Incidence des clefs étrangères sur l'interface graphique

Prenons comme exemple les tables CONTACT et CONTACTADRESSE. La table CONTACTADRESSE possède une clef étrangère composée d'une unique colonne ContactRef référençant la colonne CONTACT.ContactId .

Une interface classique pour cette base sera :

Screen 1 : Un menu (MenuForm) avec entre-autres un bouton menant au Screen 2.

Screen 2 : Un ListForm contenant la totalité des lignes présentes dans la table CONTACT. Si l'on double-clique sur une des lignes, on ouvre le Screen 3.

Screen 3 :

  • Un CardForm pour afficher la fiche du contact
  • Un ListForm pour afficher la liste des adresses de ce contact. Si l'on double-clique sur une des lignes, on ouvre le Screen 4.

Screen 4 : Un CardForm pour afficher la fiche de l'adresse (une ligne de CONTACTADRESSE). De plus, dans ce CardForm, on aura un FkField pour afficher / choisir le contact auquel cette adresse est liée.

Plus généralement, une clef-étrangère implique :

  • Pour la table cible, dans le Screen de son CardForm, une liste des enregistrements dans la table dépendante.
  • Pour la table dépendante, un FkField dans sa CardForm.

Notion de filtres

Quand l'application ouvre un Screen, elle lui propose une liste ordonnée de filtres ainsi que le filtre courant. Un filtre est, au sens Sashipa du terme, la valeur d'une clef primaire. Le Screen gère ensuite le passage d'un filtre à l'autre dans la liste ordonnée avec les boutons Précédents et Suivants.

Lorsque le Screen dispose d'un nouveau filtre, il le signale à ses formulaires. Ceux-ci réagissent de façon différente :

  • Le CardForm attend un filtre clef-primaire de sa table. C'est en fait l'identifiant de la ligne dont il va afficher le contenu dans ses champs. Si le filtre est absent, la fiche se met en mode 'Ajout'. Si le filtre est présent mais ne correspond pas à la clef primaire de sa table, une erreur est générée. De plus le filtre est transféré aux FkFields.
  • Le ListForm attend une valeur de clef-primaire référencée par l'une des clefs-étrangères de ses tables. Ou bien une valeur de l'une des clefs-primaires de ses tables. A défaut, le filtre est ignoré (donc la liste n'est pas filtrée).
  • Le ResearchForm se contente de transmettre le filtre à sa ListForm résultat et ses FkFields. Ceci induit que un ResearchForm filtré effectue sa recherche dans un sous-ensemble de la table.
  • Le SelectRecordForm transmet le filtre au ResearchForm sur lequel il est basé. Donc même remarque.
  • Le MenuForm passe le filtre comme paramètre d'ouverture au Screen que l'utilisateur choisie d'ouvrir.

Les champs FkFields sont aussi sensibles aux filtres, de la même manière qu'un ListForm.

Remarque: ces comportements par défaut peuvent être paramétrés au moyen de CastFilter.

 

Les serveurs Sashipa

Les informations sur les servlets et les connexions aux bases de données utilisées sont décrites ici.

    <serverSet>
      <server name='srvDemoContact' type='servlet'>
        <dbConnection database='dbDemoContact' type='odbc' dbmsType='MySQL'>
          <dbConnectionString>
              DRIVER=MySQL;HOST=localhost;DB=DemoContact
          </dbConnectionString>
          <user>root</user>
          <password></password>
        </dbConnection>
        <configStorage>
          <configDbStorage database='dbDemoContact' sashipaConfigStorage='cfgMain' />
        </configStorage>
        <logStorage>
          <mainLog><logFileStorage>
            <uri>Melba_DemoContact_Main.log</uri>
          </logFileStorage></mainLog>
          <updateLog><logFileStorage>
            <uri>Melba_DemoContact_Update.log</uri>
          </logFileStorage></updateLog>
        </logStorage>
        <specificToServlet>
          <servletResourceName>DemoContactServlet</servletResourceName>
          <servletUrl>
            http://localhost:8080/servlet/DemoContactServlet
          </servletUrl>
        </specificToServlet>
      </server>
    </serverSet>

L'attribut type='servlet' signifie que l'architecture de l'application générée est client-servlet-base de données. Pour construire une architecture client-base de données, il suffit de modifier ceci en type='embeddedInGui'.

L'attribut database='dbDemoContact' fait référence à la base décrite dans la partie Environment.

Note : le bloc <specificToServlet> n'est utilisé que pour une architecture avec servlet. Sinon il est ignoré. On y trouve le nom de la classe de la servlet, ainsi que l'url utilisée par la partie cliente pour accéder à la servlet.

Les fichiers journaux de votre application, gérés par la couche d'accès au données, sont précisés ici aussi.

 

Le déploiement généré

Toutes les informations spécifiques au déploiement des interfaces utilisateurs sont décrites ici :

    <architecture guiType='application'>
      <guiInstance gui='guiDemoContact' type='application'>
        <guiResourceName>GuiDemoContact</guiResourceName>
        <usedConfigStorage server='srvDemoContact' />
        <usedServerForDatabase server='srvDemoContact' database='dbDemoContact' />
      </guiInstance>

      <languageDefinitionSet mainLanguageDefinition='french'>
        &frenchDefinition; &englishDefinition;
      </languageDefinitionSet>
    </architecture>

On remarque l'attribut type='application' qui signifie qu'une application sera générée. Pour générer une applet, il suffit de le changer en type='applet'.

Enfin, vous choisissez la langue dans laquelle votre application travaillera.

 

J'espère que cette technologie vous sera utile.

Bon courage,

Thomas.

 

Annexes

Glossaire

Base de données relationnelle

Ensemble logique de tables interdépendantes. Elles sont stockées dans un SGBD/R. Elles sont interrogeables au moyen de requêtes SQL.

GUI

Graphical User Interface. Interface Utilisateur.

SGBD/R

Système de Gestion de Base de Données (/ Relationnel). Logiciel fonctionnant sur un serveur et stockant des bases de données. L'accès à ces bases se fait au moyen du langage SQL.

SQL

Structured Query Language. Langage d'interrogation de bases de données relationnelles. C'est un standard.

Intégrité référentielle

Dans une base de données relationnelle, les clefs étrangères permettent à une donnée de référencer une autre donnée. L'intégrité référentielle est le mécanisme qui assure que la donnée référencée existe bien. (par exemple que toutes les AdressePersonne référencent un identifiant de Personne existant)

Clef étrangère

Dans une base de données relationnelle, les clefs étrangères sont un ensemble de colonnes d'une table référençant la clef primaire d'une autre table (ou de la même).

Clef primaire

Dans une base de données relationnelle, la clef primaire d'une table est l'ensemble de colonnes de la table identifiant de manière unique chaque lignes. C'est à dire que pour chaque ligne insérée, les valeurs affectées aux colonnes de la clef primaire doivent être un ensemble unique.