Net.Data est un programme CGI livré avec l'OS/400 qui permet d'intégrer des requêtes SQL (et leurs résultat) dans des pages HTML. Net.data est un standard DB2 (disponible donc sur OS/400, OS/2, NT, AIX et système 390) Vous devez d'abord copier le programme DB2WWW de la bibliothèque QTCP dans votre bibliothèque CGI. Puis accorder les droits *USE à *PUBLIC ou au profil QTMHHTP1. et enfin paramètrer votre configuration HTTP par WRKHTTPCFG avec (WWWCGI est donné à titre d'exemple) : ................................................................ : map /netdata/* /QSYS.LIB/WWWCGI.LIB/DB2WWW.PGM/* : : : : exec /QSYS.LIB/WWWCGI.LIB/* : :..............................................................: |
la configuration standard d'un serveur WEB (IBM) étant : ....................................................................... : # nom du serveur WEB : : hostname web1 : : # n'être à l'écoute que sur cette adresse IP (celle de web1) : : BindSpecific ON : : : : # emplacement du pgm DB2WWW (format IFS) : : map /netdata/* /QSYS.LIB/WWWCGI.LIB/DB2WWW.PGM/* : : # autorisation de lancer les pgms situés dans cette bibliothèque : : exec /QSYS.LIB/WWWCGI.LIB/* : : # emplacement des pages HTML : : map /* /html/* : : # autorisation de servir les fichiers de ce répertoire : : pass /html/* : : # page d'accueil : : welcome home.htm : :.....................................................................: |
Pour un serveur APACHE (extrait) : ................................................................... : DocumentRoot /www/apachedft/htdocs : : : : ScriptAlias /netdata /QSYS.LIB/QSYSCGI.LIB/DB2WWW.PGM : : : : <Directory /> : : order deny, allow : : deny from all : : </Directory> : : : : <Directory /QSYS.LIB/QSYSCGI.LIB> : : Options +ExecCGI : : order allow,deny : : allow from all : : </Directory> : :.................................................................: |
Vous pouvez ensuite créer un fichier d'initialisation (facultatif) par CRTSRCPF WWWCGI/INI RCDLEN(240) et ajouter un membre DB2WWW contenant : MACRO_PATH path un ou plusieurs chemin dans lesquels chercher les macros INCLUDE_PATH path un ou plusieurs chemin pour les fichiers %include() EXEC_PATH path localisation de vos routines (pgm entreprise à lancer) DTW_SQL_NAMING_MODE qualification sous SQL (SYSTEM_NAMING = "/", sinon "." ) |
sinon, ces variables d'environnement peuvent être renseignées dans chaque macro par : nom-du-paramètre=valeur dans une section %define. vous pouvez aussi, préciser les environnements suivants : - DTW_REXX emplacement des routines REXX - DTW_SQL emplacement des routines SQL - DTW_SYSTEM emplacement des programmes "maison" à chaque fois que vous voudrez utiliser des paramètres spécifiques. exemple : ........................................................................... : MACRO_PATH /html/macros : : : : ENVIRONMENT(DTW_SQL) /QSYS.LIB/QTCP.LIB/QTMHSQL.SRVPGM : : (IN DATABASE, LOGIN, PASSWORD, TRANSACTION_SCOPE, SHOWSQL, : : DB_CASE, OUT DTWTABLE, SQL_CODE) : :.........................................................................: DATABASE, LOGIN, PASSWORD, etc.. sont des variables qui peuvent être définies dans vos macros par : %DEFINE LOGIN="QUSER" |
Un fichier Netdata (Macro) contient plusieurs sections indépendantes : > chaque section représente soit une page HTML (à afficher donc) %html(un-nom){ section HTML représentant une page HTML virtuelle, peut faire référence à une fonction par @le-nom %} > soit une fonction (un traitement) %function(type) le-nom() { section de type fonction représentant un traitement %} à réaliser. les types admis sont DTW_SQL : contient du code SQL DTW_SYSTEM : pgm à appeller DTW_REXX : procédure REXX à lancer |
%MACRO_FUNCTION un-nom(IN paramètre1, OUT paramètre2) { l'équivalent NetData des sous programmes. les paramètres peuvent être IN en entrée , OUT en sortie INOUT en entrée sortie pour appeller la fonction @un-nom , dans le code. %} %DEFINE { définition de variables %} %{ et des commentaires, bien sur! %} |
| page HTML simple : | Macro NETDATA (nommée mac01.d2w, par exemple) ---------------- | ------------- | | %html (test) { | | <HTML> | <HTML> <HEAD> | <HEAD> <title> titre </TITLE> | <title> titre </TITLE> </HEAD> | </HEAD> | <BODY> | <BODY> | essai HTML | essai HTML le @DTW_rDATE("E") | ^ | ...!................. | : fonction : </BODY> | </BODY> : DATE DU JOUR : </HTML> | </HTML> :...................: | %} la page est invoquée par "http://as400/netdata/chemin/mac01.d2w/test" |
Exemple : (sections de type HTML, mais contenant du code [ou script].) %DEFINE { OK = "NETDATA" %} %HTML(INPUT) { <HTML> <BODY> <FORM ACTION="RESULTAT"> <P>Entrez le langage de votre choix <BR> <INPUT TYPE="text" NAME="lang"> <INPUT TYPE="submit"> </FORM> </BODY> </HTML> %} |
%HTML(RESULTAT) { <HTML> <BODY> <H2>Voici le résultat de votre choix:</H2> %IF ($(lang) == "") <P>Attention, vous n'avez rien saisi ! %ELIF ($(lang) == $(OK)) <P>bravo, vous avez saisi $(OK), le meilleur ! %ELSE <P>Désolé $(lang) n'est pas un bon choix ! %ENDIF </BODY> </HTML> %} vous remarquerez l'appel à RESULTAT lors de la définition <FORM ...> ainsi que le champ lang automatiquement transmis en tant que variable $(lang): c'est en fait une variable d'environnement. |
Dans le cas d'une fonction DTW_SQL, elle doit être structurée comme suit: %function(DTW_SQL) query() { votre ordre SQL %report{ <------------------------ traitement du résulat ! global (entête) ! %row{ <---- ! ! traitement pour ! ! chaque ligne ! %} <---! ! ! pied de liste ! ! %} <-----------------------! %message{ <--- n°message: "texte à afficher" :CONTINUE ! gestion des erreurs (SQLCODE) %} <--- %} |
page html à afficher : %html (result) { <html> <head> <title>Liste des clients</title> </head> <body> <p align="center"> <font size="5" face="Arial"><b>LISTE Clients<br></b></font> </p> @query() <BR> </body> </html> %} qui fait référence à la fonction query [ @query() ] |
%function(DTW_SQL) query() { select RAISOC, INTERLOC, CDPST, VILLE, CODACT from clients where etat='A' order by raisoc ############################### # # %report{ # ATTENTION, journalisez # <table border="1"> # vos fichier si vous # <tr> # utilisez d'autres ordres # <th>client</th> # que SELECT ! # <th>Code Pst</th><th>ville</th> # # <th>Activité</th> ############################### <th>Interlocuteur</th> </tr> %row{ <tr> <td><b>$(V1)</b><td>$(V3)</td> <td>)$(V4)</td><td>$(V5)</td><td>$(V2)</td> </tr> %} |
</table> %} %message{ 100: "aucun client dans le fichier":CONTINUE %} %} ATTENTION, nous vous conseillons de ne pas mélanger des sections HTML et des fonctions dans votre code: placez d'abord la section %define puis toutes vos fonctions (%function) et enfin vos pages html [ dans l'ordre d'apparition ?] |
Vous devez ensuite faire référence à une page html (une section ou block) dans un fichier macro, par: <a href="/netdata/html/macros/db2w01.d2w/result">CLIENTS le mot CLIENTS fait référence à la section result [ %html(result){ ... %} ] dans le fichier db2w01.d2w du répertoire html/macros . vous noterez l'appel à la routine DB2WWW qui sera remplacé par "/QSYS.LIB/WWWCGI.LIB/DB2WWW.PGM" grace à la ligne, map /netdata/* /QSYS.LIB/WWWCGI.LIB/DB2WWW.PGM/* ou ScriptAlias /netdata /QSYS.LIB/WWWCGI.LIB/DB2WWW.PGM Autre exemple avec une page d'appel (saisie d'une clé), puis liste : |
tout d'abord, définition de quelques variables locales par %DEFINE la variable fichier s'utilise sous la forme $(fichier) dans le code HTML %define { fichier ="af4cours" %} Query est une fonction contenant du code SQL (placée AU DESSUS !) %function(DTW_SQL) query() { select MODULE, NOM, TEXTE from BIBLIO.$(fichier) where sujet LIKE '%$(sujet)%' %report constitue le résultat affiché. |
on fait référence à - une zone par $(Vx) ou x est le n° dans le select ou bien par $(V_nom) ou nom est le nom du champ. - une entète de colonne par $(Nx) ou x est le N° - la ligne en cours par %row{ ... %} %report{ <table border=1> <tr><th> $(N1) </th><th> $(N2) </th><th> $(N3) </th></tr> %row{ <tr><td> $(V1) </td><td> $(V2) </td><td> $(V_TEXTE) </td></tr> %} </table> %} la fonction %message indique l'action et le texte à afficher en cas d'erreur ici le code SQL0100 qui indique qu'il n'y pas d'enregistrement, et default pour toutes les autres erreurs. %message{ 100 : "Aucun cours ... $(sujet)":CONTINUE default: "Erreur generale, consultez votre administrateur":CONTINUE %} |
les actions possibles sont CONTINUE EXIT %Include (nom d'un fichier à afficher) %include_url (ref. d'une URL à activer, pour lancer une autre requête) %} -> fin de %function ... Puis la section input, il s'agit de code HTML standard faisant référence à la section result (dans le même source) grace au formulaire. %html(input){ <html> <head> <title>Exemple net.data</title> </head> <body> <h1>requete sur le fichier $(fichier)</h1> <p>Entrez un SUJET: </p> <form action = "result" > |
<p><input type=text size=30 name="sujet"> </p> <p><input type=submit> <input type=reset> </p> </form> </body> </html> %} %html(result){ <html> <title>resultat de votre requete</title> <body> <h1>Requete sur $(fichier) - Liste des cours</h1> <p>Votre critere <b>$(sujet) </b></p> ################################# <p> @query() </p> # <-- le résultat affiché est # <p><a href="input">Autre requete</a></p> # renvoyé par la "fonction" # <p> # QUERY ci-dessus # </body> ################################# </html> %} |
Syntaxe Net.data : Eléments du langage %DEFINE : définition d'une variable et assignation d'une valeur %define cpt="0" ou bien %define { cpt = "0" flag = "1" %} la variable peut être modifiée à tout moment par : @DTW_ASSIGN(flag, "0") |
%define { REMOTE_ADDR= %ENVVAR %} cette dernière syntaxe permet de récuperer toute variable d'environement du serveur (particulièrement celles disponibles pour CGI) ......................................................................... : Votre adresse IP d'origine est <B>$(REMOTE_ADDR)</B> : :.......................................................................: %IF (condition1) n'importe quel instruction [%HTML, %FUNCTION, %DEFINE, ...] %ELIF (condition2) idem ################################ # les opérateurs sont : # %ELSE # # # == , > , <, != (différent) # %ENDIF ################################ |
exemple : %IF (NOCOL < "100") <p>le fichier n'est pas plein... %ELIF (ROW_NUM == "100") <p>le fichier est plein... %ELSE <p>le fichier est en dépassement de capacité %ENDIF %WHILE (condition) { ... %} %WHILE (loopCounter <= "100") { @dtw_add(loopCounter, "1", loopCounter) %} |
Remarques concernant les variables - toute variable non initialisée contient NULL ("" soit chaîne vide) - toute constante est placée entre " " (même numérique) - les variables doivent être notées : + $(variable) dans un contexte HTML (affichage) [ N° de la ligne est: $(compteur) ] + variable (nom simple) dans une expression Net.DATA ou une fonction [ %IF (compteur > "100") ] [ @dtw_assign(cpt, "0") ] |
Quelques fonctions intégrées : la plupart des fonctions ont deux écritures, ° @DTW_ADD(facteur1, facteur2, résultat) ^ cette syntaxe modifie la zone --! ° @DTW_rADD(facteur1, facteur2) cette syntaxe retourne le résultat (l'affiche à la place) Nous avons donc : @DTW_ADD(F1 , F2, ZR) et @DTW_rADD(F1 , F2) @DTW_SUBTRACT(F1 , F2, ZR) et @DTW_rSUBTRACT(F1 , F2) @DTW_MULTIPLY(F1 , F2, ZR) et @DTW_rMULTIPLY(F1 , F2) @DTW_DIVIDE(F1 , F2, ZR) et @DTW_rDIVIDE(F1 , F2) @DTW_DIVREM(F1 , F2, ZR) et @DTW_rDIVREM(F1 , F2) (le RESTE) |
pour faire des pages à partir de listes SQL avec beaucoup de lignes , il vous faudra utiliser des variables spécifiques (et réservées). %define { START_ROW_NUM = "1" <- première ligne (la première fois) RPT_MAX_ROWS = "25" <- nombre de lignes DTW_SET_TOTAL_ROWS = "YES" <- charger la variable TOTAL_ROWS %} vous indiquerez en début de liste les lignes affichées(en début de %report) ............................................................ : : : @DTW_ADD(START_ROW_NUM, RPT_MAX_ROWS, suivant) : : @DTW_SUBTRACT(START_ROW_NUM, RPT_MAX_ROWS, precedent) : : : : Affichage des lignes $(START_ROW_NUM) à : : @DTW_rSUBTRACT(suivant, "1") : :..........................................................: Puis en fin de liste (après %ROW{ ... %} ) il vous faudra prèvoir un lien "suivant | précédent" |
........................................................................ : : : %IF (START_ROW_NUM > RPT_MAX_ROWS) : : <a href="page1?START_ROW_NUM=$(precedent)">PAGE PRECEDENTE</a> | : : %ELSE : : PAGE PRECEDENTE | : : %ENDIF : : %IF (suivant < TOTAL_ROWS) : : <a href="page1?START_ROW_NUM=$(suivant)">PAGE SUIVANTE</a> : : %ELSE : : PAGE SUIVANTE : : %ENDIF : : : : (nombre total de lignes : $(TOTAL_ROWS) ) : : : :......................................................................: c'est dans le lien, que vous forcerez la nouvelle valeur de la variable START_ROW_NUM (page1 étant le nom de la section %html). |
Chaînes de caractères : | @DTW_CONCAT(ch1, ch2, ZR) et @DTW_rCONCAT(ch1, ch2) | concatenation | @DTW_LENGTH(chaine, ZR) et @DTW_rLENGTH(chaine) | retourne la lg. | @DTW_LOWERCASE(ch1, ch2) et @DTW_rLOWERCASE(chaine) | cvt en minuscules | @DTW_UPPERCASE(ch1, ch2) et @DTW_rUPPERCASE(chaine) | cvt en MAJUSCULES | @DTW_STRIP(ch1 , ch2) et @DTW_rSTRIP(chaine) | élimine les blancs | @DTW_SUBSTR(O, d, l, ZR) et @DTW_rSUBSTR(O, d, l) | extrait dans O | L car. depuis D | mais aussi (toujours avec l'équivalent @DTW_r...) | @DTW_POS(ch1, ch2, debut, ZR) retourne la première occurence de ch2 @DTW_LASTPOS(ch1, ch2, debut, ZR) retourne la dernière occurence de ch2 @DTW_INSERT(ch1,ch2,d,l,ZR) insert ch2 dans ch1 à partir de D sur l. @DTW_REPLACE(chaine,c2,c3,ZR) remplace c2 par c3 dans chaine |
et enfin le type DTW_SYSTEM permettant de lancer une commande OS/400 : %FUNCTION(DTW_SYSTEM) sys1 () { %EXEC { /QSYS.LIB/ADDLIBLE.CMD MALIB %} %MESSAGE { default: "" : continue %} %} %HTML(cmd1) { <P>Ajout d'une bibliotheque @sys1() <P>maintenant la bibliotheque MALIB fait partie de la liste. Vous pouvez continuer le traitement. %} |