Introduction▲
Le Context est sans doute l'objet le plus obscur et pourtant non moins important de l'architecture XMLRAD. Il est central dans le sens où quasiment toutes les données passent à travers lui et de ce fait on l'utilise en permanence. Il est donc important de bien comprendre son mécanisme, sa fonction et sa portée.
Nous allons donc expliquer le Context dans le cadre d'un exemple de transmission de valeur d'une page à une autre. Nous allons construire une petite application à partir du moins d'assistants possible pour bien comprendre les tenants et les aboutissants de l'utilisation du Context et de XMLRAD pour développer des applications web.
Context : un melting pot de données !▲
Le Context est un objet du framework XMLCLX qui peut être assimilé a une sorte de pot de données. Nous y versons, ou bien le framework le fait pour nous, des données provenant de sources diverses: Paramètres HTTP, cookies, enregistrements de base de données, variables, constantes, etc. Mais techniquement qu'est-ce que c'est ?
C'est une liste d'association de noms et de valeurs. Par exemple on a: Nom=Bempel, Prenom=Jean-Philippe, etc. Nom et Prénom sont les noms ou clés et Bempel et Jean-Philippe sont les valeurs.
Pour ceux qui ont déjà travaillé avec les conteneurs Java ou C++, le Context est une Map. Graphiquement le Context peut être représenté par un tableau :
Clé |
Valeur |
---|---|
Nom |
Bempel |
Prenom |
Jean-Philippe |
ORG_ID |
101 |
Lorsque l'on ajoute une nouvelle valeur, il faut toujours faire référence à la clé associée pour l'ajouter ou la modifier. Les clés et valeurs sont toujours des chaînes de caractères. Mais on verra plus tard que l'on peut associer d'autres objets.
Concrètement, lorsque l'on veut mettre une valeur dans le Context, on appelle la méthode SetValue:
Context.SetValue('Prenom'
, 'Jean-Philippe'
);
Context.SetValue
(
"Prenom"
,
"Jean-Philippe"
);
Context.
SetValue
(
"Prenom"
,
"Jean-Philippe"
);
context.setValue
(
"Prenom"
, "Jean-Philippe"
);
Si la clé Prenom n'existe pas, une nouvelle entrée (=association Clé/Valeur) sera créée, et aura pour clé Prénom et valeur Jean-Philippe.
Si une entrée possédant déjà cette clé, la valeur de cette entrée sera écrasée par Jean-Philippe.
Pour récupérer une valeur, on utilisera la méthode GetValue en spécifiant la clé.
Value := Context.GetValue('Prenom'
);
Value =
Context.GetValue
(
"Prenom"
);
Value =
Context.
GetValue
(
"Prenom"
);
Value =
context.getValue
(
"Prenom"
);
On spécifie ici, la clé Prenom, la méthode va donc chercher l'entrée qui a comme clé Prenom et renvoie dans la variable Value, la valeur Jean-Philippe, précédemment ajoutée.
Pour un souci de performance, la recherche de l'entrée contenant la clé spécifiée dans GetValue utilise un système de hachage. Le temps de recherche n'est donc pas dépendant du nombre d'entrées stockées dans le Context.
Du point de vue fonctionnel, le Context représente l'ensemble des données correspondant à l'exécution et au traitement de la requête HTTP. C'est le Context d'exécution. Pour chaque requête (XMLRequest), un Context est créé et lui est associé.
Il est libéré une fois que la requête est traitée et que le contenu de la réponse est renvoyé au client. Il a donc la même durée de vie que la requête HTTP. Il n'y a pas de Context globaux, chaque requête a son propre Context indépendant des autres.
Toutes données susceptibles d'être utilisées dans le traitement de la requête HTTP sont stockées dans le Context. On y retrouve donc :
- les paramètres HTTP ;
- les cookies ;
- des valeurs initialisées par le framework. (XMLC_Date) ;
- des constantes (GlobalParams) ;
- des champs d'enregistrement (DBExtract) ;
- des variables utilisées pendant le traitement de gestionnaires d'événements ou de méthodes internes au framework.
Le Context peut stocker dans une entrée une valeur sous forme de chaîne de caractères, mais aussi un objet via la propriété Objects et/ou une interface via la propriété Unknowns.
Construction de l'application exemple▲
Nous allons créer une nouvelle application MyTraining en utilisant la base de données Training qui est au format Access. Créez un nouveau projet et configurez votre DataSource pour pointer sur la base qui se trouve dans C:\Program Files\e-delos\XMLComponents\Demos\Training\Data\Training.mdb
Nous allons créer tous nos écrans à partir d'une fiche vide (Empty Form). Créons donc notre première fiche ListORGANIZATION en utilisant l'assistant de création Empty Form. On nomme donc le XMLService ListORGANIZATION.
Une fois la structure de base de l'écran comprenant le XMLGram et le XSL en place, il nous faut décrire dans le XMLGram l'extraction des données que l'on retrouvera dans le document XML.
Dans l'éditeur de XMLGram, on va sélectionner une instruction DBExtract, la nommer ORGANIZATION, et l'insérer après l'instruction Params qui se trouve déjà dans le XMLGram.
On tombe sur l'assistant classique de sélection de données. Après le choix de la datasource et de la table ORGANIZATION, nous sélectionnons les champs ORG_ID en tant que clé et ORG_NAME en tant que champ visuel.
Puis nous ajoutons dans la requête un tri alphabétique sur le champ ORG_NAME avec la clause ORDER BY ORG_NAME. L'extraction est maintenant complètement paramétrée.
Nous allons jeter un œil sur le document XML qui doit normalement contenir nos données extraites.
Passons maintenant à l'édition du XSL pour afficher ces données. Dans XSLStudio, Sélectionnez dans la prévisualisation de l'écran, le texte de la fiche. Vous devez voir dans la partie XSL en bas.
Sélectionnez le composant DataTable dans la palette Data et insérez-le après la balise <p> du texte de la fiche.
Lors de l'insertion, un assistant vous aide à paramétrer le composant. Sélectionnez en premier lieu, l'ensemble de données en choisissant l'élément conteneur des enregistrements (ORGANIZATIONS).
Puis sélectionnez l'élément conteneur du premier enregistrement (ORGANIZATION). Enfin, parmi les champs de l'enregistrement indiquez ce que vous voulez ou non afficher et l'élément clé.
Il nous faut maintenant ajouter un lien sur le nom de chaque ORGANIZATION pour pouvoir afficher un autre écran avec le détail de l'ORGANIZATION sélectionnée.
Pour cela, sélectionnez dans la prévisualisation, le premier enregistrement de la table. (normalement Better-Office). Sélectionnez le composant Hyperlink dans la palette HTML, puis sélectionnez le <td> dans la partie XSL. Insérez l'hyperlink en tant que fils du <td> (Insert as child).
Dans la balise <a>, il y a un nœud texte contenant "Click here…". nous allons effacer ce texte puis sauvegarder (CTRL+S) pour retirer ce nœud texte.
Il nous faut déplacer le xsl:value-of qui se trouve au-dessus du lien pour le mettre à la place du nœud texte. Coupez le xsl:value-of et insérez-le en tant que fils de la balise <a>. Le nom de l'ORGANIZATION est maintenant sous contrôle d'un lien hypertexte. Il ne nous reste plus qu'à paramétrer ce lien.
Dans l'attribut href, la valeur entre {} va être remplacée à la transformation du XML par l'alias de votre application. Dans notre cas ce sera "http://localhost/ProjectsBin/MyTraining/MyTraining.dll/".
Nous voulons que le lien pointe sur l'écran suivant qui va s'appeler FormORGANIZATION. Il nous faut aussi transmettre l'ID de l'ORGANIZATION que nous voulons voir apparaitre dans l'écran suivant. Pour cela nous rajoutons dans le lien le paramètre ORG_ID avec la valeur contenue dans l'enregistrement courant. ce qui donne :
{/document/Aliases/MyTrainingDLL}FormORGANIZATION?ORG_ID={ORG_ID}.
Maintenant nous allons créer l'écran FormORGANIZATION qui affichera le contenu détaillé d'une ORGANIZATION. Nous créons donc un nouveau XMLService en utilisant Form Empty.
Nous allons rajouter une instruction DBExtract nommée ORGANIZATION en dessous de l'instruction Params existante. Dans l'assistant de paramétrage de l'instruction, nous allons modifier la requête SQL pour filtrer sur une ORGANIZATION. Nous rajoutons la clause WHERE suivante :
WHERE ORG_ID = :ORG_ID
En réexécutant la requête avec la nouvelle clause, (Run This Query) XMLRAD détecte le nouveau paramètre, donne par défaut le type Integer et récupère la valeur du premier enregistrement pour donner une valeur utilisée lors de la conception (valeur exemple).
Vérifions dans le XML que nos données se trouvent bien là.
Nous voyons que nous avons un élément conteneur ORGANIZATIONS comme pour une liste, or nous n'avons qu'un seul enregistrement ORGANIZATION. Modifions dans le XMLGram le type d'extraction (Extract Kind) en spécifiant la valeur Single.
Attachons-nous au XSL. Après la balise <p>, insérez un composant Form de la palette HTML form, modifiez l'attribut Action de <form> pour faire pointer vers le XMLService UpdateORGANIZATION que nous créerons plus tard. Puis à l'intérieur et au-dessus du <br> insérez un composant GridLayout (palette HTML).
Dans la première colonne, on y mettra les noms des champs et dans la deuxième on va insérer des composants DataTextBox (palette Data) qui pointeront sur les champs de l'enregistrement. Astuce pour l'édition du XSL: En appuyant sur echap dans la partie XSL, on remonte d'un niveau d'imbrication.
Nous pouvons maintenant tester notre application exemple. Le fait de cliquer sur une des organisations va transmettre une valeur de paramètre ORG_ID différente au XMLService FormORGANIZATION et donc afficher l'organisation correspondante. Mais comment cela se passe en interne ?
La transmission automatique des paramètres▲
Lorsque l'on clique sur le lien (http://localhost/ProjectsBin/MyTraining/MyTraining.dll/FormORGANIZATION?ORG_ID=101) d'une organisation à partir de l'écran ListORGANIZATION, on appelle le XMLService FormORGANIZATION avec un paramètre HTTP ORG_ID ayant la valeur 101.
Donc au début de l'exécution du XMLService, le Framework décode les paramètres HTTP et les remplit dans le Context. Notre Context contient donc la clé ORG_ID associée à la valeur 101.
Le XMLGram s'exécute.
Arrivé à l'instruction ORGANIZATION, le framework prépare la requête SQL, et assigne les paramètres. Pour notre requête nous avons qu'un seul paramètre nommé ORG_ID. le framework essaye alors de récupérer une valeur dans le Context dont la clé est le nom du paramètre c'est-à-dire ORG_ID. Or comme le Context contient le paramètre HTTP qui nous a été transmis le framework va pouvoir assigner la valeur 101 contenue dans le Context au paramètre de la requête.
La requête s'exécutant, le résultat va être ajouté dans le document XML de sortie (OutputDoc). Puis le XSL s'applique sur ce dernier finissant de construire notre page.
Comme vous le constatez, tout se joue sur le nommage des paramètres. Le nom du paramètre HTTP doit correspondre au nom du paramètre de la requête SQL. On a ici choisi le nom du champ parce que cela nous permet à tout moment de savoir que cette valeur correspond à la valeur de la base de données.
La technique du Context permet ainsi de transmettre des valeurs sans avoir à taper une seule ligne de code. À la condition de respecter le nommage adéquat, nous n'avons pas besoin de nous préoccuper de l'assignation des paramètres à une requête SQL, travail répétitif et fastidieux n'apportant aucune valeur ajoutée. Il nous suffit de nous assurer que la donnée est au bon endroit et que la requête SQL, le cœur du métier, est correcte.
Pour aller plus loin : Mise à jour▲
Nous allons finir notre application exemple en permettant de mettre à jour les données sur une ORGANIZATION.
Le gros du travail est déjà fait: la fiche FormORGANIZATION va nous servir de point de départ pour la mise à jour. En validant le formulaire, nous allons envoyer les données à notre application sous forme de paramètres HTTP. Chaque valeur contenue dans les inputs sera envoyée au XMLService sous forme de paramètres HTTP.
Il nous faut tout d'abord nous assurer que les noms des inputs sont corrects, car ces noms seront utilisés comme nom des paramètres HTTP et donc seront les clés des valeurs dans le Context.
Encore une fois nous allons utiliser les noms des champs ORG_NAME, ORG_ADDRESS1, ORG_ZIP, etc. Dans le XSL de FormORGANIZATION, modifiez l'attribut name de chacun des inputs.
Pour mettre à jour une organisation nous avons besoin de savoir quel est son ORG_ID. il faut donc que cette valeur se trouve dans les paramètres HTTP.
Or nous ne voulons pas l'afficher à l'écran. Il nous faut donc rajouter un Input de type hidden dans le formulaire de FormORGANIZATION. Cet Input aura bien sûr le nom ORG_ID.
Assurez-vous que le formulaire pointe bien sur le XMLService UpdateORGANIZATION. L'attribut action de la balise <form> doit être du genre : action="{/document/Aliases/MyTrainingDLL}UpdateORGANIZATION"
Créons maintenant le XMLService UpdateORGANIZATION. Pour cela nous allons choisir de créer seulement un XMLGram (XMLGram only, Section XMLGram).
Nous rajoutons dans ce XMLGram une instruction DBBatch nommée ORGANIZATION en dessous de Params.
L'assistant va générer une requête Update (par défaut) avec en paramètres tous les champs sélectionnés. Notez au passage que les noms des paramètres sont ceux des noms de champs.
Comme vous l'avez compris, pour que ces paramètres soient assignés correctement, il faut que dans le context se trouvent les bonnes clés avec les bonnes valeurs. C'est pour cela que les inputs du formulaire doivent être corrects.
Enfin, notre XMLService UpdateORGANIZATION ne renvoie pas de page HTML, donc il nous faut rediriger vers le XMLService FormORGANIZATION qui effectuera une nouvelle requête pour récupérer les données fraichement mises à jour et les afficher à l'écran, ce qui nous permettra de vérifier que la mise à jour s'est effectuée correctement.
Pour cela il nous suffit de paramétrer la propriété NextAction du XMLService UpdateORGANIZATION avec la valeur FormORGANIZATION.
Mais où qu'elle est ma donnée ?▲
Il arrive que la donnée se perde en cours de route entre les paramètres HTTP et la page HTML suivante. Comment savoir où le processus s'est mal passé ?
Pour résoudre le problème, nous allons procéder dans le sens inverse du chemin parcouru normalement par la donnée.
- La première chose à vérifier c'est de regarder dans le code source de la page HTML générée si notre donnée ne s'y trouve pas déjà, mais sous une forme qui n'est pas rendue dans le navigateur.
- Nous passons ensuite au XSL: est-ce que l'on a bien effectué un xsl:value-of pour insérer la donnée dans la page HTML. Vérifier ensuite que la template match est bien déclenchée et que le XPath est correct.
- L'étape suivante consiste a regarder dans le document XML (à l'aide du paramètre XMLC_OutputFormat=XML) si la donnée s'y trouve bien, et au bon endroit par rapport à la sélection qui est faite dans le XSL. La donnée peut être insérée dans le document XML de plusieurs façons : soit par extraction de la base de données avec un DBExtract, soit par recopie depuis le Context avec l'instruction Assign, ou bien encore par l'ajout à partir du code d'un gestionnaire d'événement.
- La partie la plus délicate consiste à vérifier que la donnée se trouve dans le Context. On peut vérifier cela par du code dans un gestionnaire d'événement en essayant de récupérer cette valeur.
- Finalement, il faut s'assurer que les paramètres HTTP sont transmis correctement soit par paramètre d'URL en méthode GET soit par Input en méthode POST.
La prochaine version de XMLRAD (XMLRAD 2005) offrira un débogueur de haut niveau permettant de visualiser le contenu du Context et du document XML à tout moment dans l'exécution d'un XMLService. Ceci permettra de faciliter grandement la compréhension du Context et la mise au point des applications.
Conclusion▲
Après avoir décrit techniquement et fonctionnellement le Context, nous avons vu comment développer une simple application et comment transmettre une donnée d'une page à une autre.
En comprenant comment fonctionnent le Context et le mécanisme de transmission automatique des paramètres, vous pouvez maintenant sentir toute la puissance de ce framework de développement web qui vous permet de vous concentrer au maximum sur l'aspect fonctionnel de votre application.