Le projet Sashipa-Melba n'est plus maintenu depuis 2005. Ceux qui souhaiteraient le reprendre en téléchargeront les sources.
Je suis désormais Webmestre : je crée des sites Web depuis le Bénin.
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.
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.
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)
);
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.
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.
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 '
'>
<!ENTITY nbsp ' '>
<!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 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>
Voici la structure générale d'une GUI Sashipa.
<graphicalUserInterface name='guiContact'>
<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.
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.
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.
Un Screen est un conteneur de formulaires. Pour chaque table, on aura les formulaires suivant :
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 formulaires CardForm et ResearchForm contiennent un ensemble de champs. Il existe deux catégories de champs :
Voici la liste des Fields disponibles :
Et la liste des FkFields :
Voici quelques notions théoriques sur comment déduire une interface graphique d'un schéma de base de données.
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 :
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.
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 :
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 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.
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.
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. |