Un programme "CGI" (Common Gateway Interface" est un programme qui sera appelé à la place d'une page web statique (.html) pour créer dynamiquement un contenu. En général ce contenu est du html, mais il peut être tout autre chose. Nous allons voir comment réaliser un programme RPG (IV ILE) pour créer un flux RSS simple affichant les derniers messages de QSYSOPR.
Ce petit didacticiel sera décomposé en 3 parties (3 sujet différents sur le forum) :
- Cette première partie se termine à la réalisation d'un premier programme CGI avec les données en "dur"
- La deuxième partie évoquera la configuration d'Apache pour l"appel du programme au travers d'un navigateur, ainsi que quelques "readers" de flux.
- Enfin la troisième partie sera la réalisation complète de notre programme diffusant les derniers messages de QSYSOPR.
Flux RSS Un flux RSS est un ensemble d'informations, généralement simples, qui est mis à jour régulièrement sur des serveurs ("le feeder") et que l'on peut consulter sur des lecteurs de flux ("reader"). Ces Lecteurs de flux peuvent être des programmes indépendants, mais de plus en plus d'outils intègrent cette technologie permettant de suivre les nouvelles de la presse, les cours de bourse, les résultats de matchs, ou les derniers messages de forums.
Il est ainsi possible d'afficher les flux directement dans les navigateurs, sur les pages de iGoogle (création de compte nécessaire) ou maintenant dans les "widgets" de Vista (pour n'en citer que 3).
Le flux RSS n'est en faite qu'un simple fichier XML. Il peut être statique sur le serveur : il suffit de recréer régulièrement ce fichier dans le répertoire des pages web du serveur HTTP (Apache), mais il peut également être créer dynamiquement par un programme CGI ou un script (PHP, Perl, ASP, ...).
Structure RSS Pour commencer, le mieux est de lire les explication de Wikipedia sur les RSS (et de revenir ensuite

) :
http://fr.wikipedia.org/wiki/RSS_(format)
Pour plus de détails, un des sites de référence est :
http://www.rssboard.org/rss-specification Pour ceux qui n'ont pas eut le courage d'aller s'informer, voici un exemple minimaliste de flux RSS (donné sur Wikipédia) :
<rss version="2.0">
<channel>
<title>Mon site</title>
<description>Ceci est un exemple de flux RSS 2.0</description>
<lastBuildDate>Wed, 27 Jul 2005 00:30:30 -0700</lastBuildDate>
<link>http://www.example.org</link>
<item>
<title>Actualité N°1</title>
<description>Ceci est ma première actualité</description>
<pubDate>Tue, 19 Jul 2005 04:32:51 -0700</pubDate>
<link>http://www.example.org/actu1</link>
</item>
</channel>
</rss>
Cet exemple ne comprend qu'un élément (item) à diffuser. Mais bien sûr le but est d'en mettre plusieurs. Le principe des RSS est de ne mettre qu'un nombre restreint (les dernières infos importantes). En général de 10 à 15.
Nous allons donc faire un programme RPG qui va créer ce texte XML en répétant les blocs "<item>...</item>' pour les 10 derniers messages de QSYSOPR.
Mais avant d'aller chercher les messages de QSYSOPR, faisons un petit programme qui ne fait qu'envoyer l'équivalent de l'exemple ci-dessus.
RPG CGI Un programme RPG CGI est en fait un programme RPG 4 tout ce qu'il y a de plus normal, sauf qu'il va utiliser une API particulière :
QtmhWrStout. Cette API permet de stocker des caractères dans un buffer internes et de les transmettre ensuite au serveur Apache pour qu'il les fournisse au navigateur de l'utilisateur.
D'autres APIS existent pour recevoir les informations ("paramètres") transmis lors de la demande de l'utilisateur, mais nous ne les aborderons pas ici.
Cette api QtmhWrStout a une contrainte : vous l'aurez remarqué, son nom fait plus de 10 caractères. Ce n'est donc pas un programme (*PGM). En effet c'est une procédure d'un service programme (*SRVPGM). Cela signifie que nous devons l'utiliser dans un programme ILE. RPG IV est un langage ILE, RPG/400 (RPG III) ne l'est pas (c'est de l'OPM).
"Cycle" CGI Il est relativement facile pour des développeurs ayant l'expérience du RPG II de comprendre le fonctionnement des programmes CGI. En effet cela s'apparente, dans une certaine mesure, à un fichier écran en "Primaire". Donc, lu et écrit automatiquement par le Cycle RPG.
C'est pourquoi l'on parle souvent de "Cycle" CGI.
En effet, un programme CGI est déclenché par la demande d'une URL (les liens Htt p://www...). Il peut y avoir ou non des paramètres ou des infos saisies par l'utilisateur qui devront être traitées par le programme. Notre programme CGI n'affiche donc pas l'"écran " au démarrage, cela a déjà été fait précédemment.
Tout ce qu'il va devoir faire c'est :
- analyser les infos en entrée, si nécessaire (nous n'aborderons pas ce point),
- puis collecter des données dans le système (Fichiers, dtaaras, appels d'autres programmes... du grand classique !)
- et ensuite créer une grande chaine de caractères mélangeant du HTML et/ou du XML et/ou javascript, etc avec les données récupérées. Cette chaine sera transmise (en une ou plusieurs fois) à l'API QtmhWrStout, qui va stocker le tout dans ses buffer.
ET C'EST TOUT !Car à la fin du programme, et seulement à ce moment là, le système transmettra (après conversion EBCDIC/ASCII si besoin) au serveur apache le fruit de notre labeur.
Notre programme ne reste donc pas actif. C'est là le gros soucis des pages Web. Le protocole HTTP n'est pas conçu pour faire du conversationnel. La notion de session n'existe pas de base. Il faut soit rajouter des mécanismes lourd pour gérer ça (serveurs d'applications) soir le gérer soi même avec plus ou moins d'aide d'Apache. Mais c'est également un autre problème que nous ne développerons pas ici, car cela ne nous concerne pas pour les flux RSS.
Accéder à l'API QtmhWrStout Pour pouvoir utiliser l'API QtmhWrStout, il va falloir indiquer au programme qu'il devra la chercher dans un service programme (QHTTPSVR/QZHBCGI). Nous pourrions indiquer cela dans les paramètres de compilation, mais il faudrait refaire l'opération à chaque compil.
Il y a donc un mécanisme qui permet d'enregistrer dans un "Répertoire de liage" (objet *BNDDIR) les objets nécessaires au programme.
Nous allons donc créer un répertoire de liage dans QGPL (ou ailleurs, du moment que le compilateur à la bib en libl) et enregistrer dedans le nom du SRVPGM. Ce répertoire de liage ne sert qu'à la compil. Pas à l'exécution.
Les commandes sont :
CRTBNDDIR BNDDIR(QGPL/HTTP) TEXT('Apis HTTP')
ADDBNDDIRE BNDDIR(QGPL/HTTP) OBJ((QHTTPSVR/QZHBCGI *SRVPGM)
Ensuite la première ligne de notre programme RPG pourra être une spécification H indiquant ce répertoire de liage (qualifié ou non).
H BNDDIR('HTTP')
Comme l'API est une procédure, nous allons devoir en faire le "prototype". C'est, grosso modo, la liste des paramètres de la procédure. Comme le nom de l'API est trop difficile à mémoriser (en tout cas pour moi...) j'en profite pour lui donner un nom plus parlant : WriteToWeb.
D WriteToWeb PR extProc('QtmhWrStout')
D WebData 32000A Const OPTIONS(*VARSIZE)
D WebDataLen 10I 0 Const
D apiError 16A OPTIONS(*VARSIZE)
Je ne vais pas vous décrire chaque ligne, donc voilà le premier programme CGI simple :
* ---------------------------
* Creation flux RSS. Doc Reference RSS :
* http://www.rssboard.org/rss-specification
* en plus simple : http://fr.wikipedia.org/wiki/RSS_(format)
* ---------------------------
* -- Lien vers les APIs HTTP -----
* Si elle n'existe pas déjà, la BNDDIR doit être créée :
* CRTBNDDIR BNDDIR(QGPL/HTTP) TEXT('Apis HTTP')
* ADDBNDDIRE BNDDIR(QGPL/HTTP) OBJ((QHTTPSVR/QZHBCGI *SRVPGM)
* ---------------------------
H BNDDIR('HTTP')
H Option(*SrcStmt:*NoDebugIO) DftActGrp(*no)
* Prototypes Apis HTTP --------------------------------
* * QtmhWrStout : envoi vers le web
D WriteToWeb PR extProc('QtmhWrStout')
D WebData 32000A Const OPTIONS(*VARSIZE)
D WebDataLen 10I 0 Const
D apiError 16A OPTIONS(*VARSIZE)
D LF C Const(X'15')
D apiError S 16A Inz(*ALLX'00')
D Buffer S 32000A Varying
/Free
*INLR = *ON;
// --- En tête -----------------------------
Buffer = 'Content-type: text/xml' + LF + LF ;
WriteToWeb(Buffer : %len(Buffer) : apiError);
Buffer = '<?xml version="1.0" encoding="iso-8859-1"?>' + LF;
Buffer = Buffer + '<rss version="2.0">' + LF;
Buffer = Buffer + '<channel>' + LF;
Buffer = Buffer + '<title>Flux RSS de test</title>' + LF;
Buffer = Buffer + '<description>'
+ 'La description, blablabla...'
+ '</description>' + LF;
Buffer = Buffer + '<link>http://www.experia.com</link>' + LF;
WriteToWeb(Buffer : %len(Buffer) : apiError);
// --- Lignes ------------------------------
Buffer = '<item>' + LF;
Buffer = Buffer + ' <title>Titre élément </title>' + LF;
Buffer = Buffer + ' <description>Blublublu...</description>' + LF;
Buffer = Buffer + '</item>' + LF;
WriteToWeb(Buffer : %len(Buffer) : apiError);
// --- Fin ---------------------------------
Buffer = '</channel>' + LF;
Buffer = Buffer + '</rss>' + LF;
WriteToWeb(Buffer : %len(Buffer) : apiError);
/End-Free
Il n'y a que 58 lignes, lignes vides et commentaires compris. Pas bien compliqué, donc.

Il y a seulement un point particulier à expliquer.
La première ligne ligne transmise au serveur est un "header" et indique le type de contenu de ce qui va suivre.
Pour une page web normal, ce header est : "Content-type: text/html". Dans notre cas, nous allons envoyer du XML, donc nous mettons : "Content-type: text/xml".
Cette ligne doit
impérativement être suivie de 2 caractères "fin de ligne" qui en hexa sont X'15'.
Comme nous allons mettre des fins de ligne un peu partout pour que notre code xml soit plus présentable, nous définissons une constante :
D LF C Const(X'15')
Vous voyez donc que dans le source nous faisons appel plusieurs fois à l'API. Elle n'affiche rien. Elle ne fait qu'engranger les caractères que nous transmettons. Pour que l'affichage se fasse il faut que le programme se termine.
Tester le programme Une fois compilé, nous avons bien envie de le tester. Il n'est pas possible de l'appeler par le navigateur sans faire un minimum de configuration dans Apache.
Mais nous pouvons cependant appeler notre programme grâce à une petite astuce (en fait, c'est surtout grâce à la richesse de l'AS/400

).
Si vous faites un CALL MONCGI1 en ligne de commande vous allez peut-être (si votre AS n'est pas "trop" rapide) voir apparaitre et disparaitre un écran. Malheureusement il ne reste pas.
Pour voir le résultat de notre programme, il faut l'appeler dans une console "UNIX" (c'est un abus de langage, mais ce n'est pas important).
Pour cela en ligne de commande il faut taper QSH (ou STRSQH) pour arriver sur cette console qui ressemble beaucoup à notre QCMD, mais qui est un "shell" unix.
Nous allons donc appeler notre programme d'ici. Mais ce n'est pas si simple, car il faut indiquer son "chemin" de type "IFS".
Cela va donner quelque chose comme :
/QSYS.LIB/ma-bib.LIB/moncgi1.PGM
mettez le bon nom de bibliothèque à la place de "ma-bib" en gardant le .LIB à la fin et pareil pour le nom de programme.
Faites "entrée" et normalement voici ce qui devrait apparaître :
$
> /QSYS.LIB/ma-bib.LIB/moncgi1.PGM
Content-type: text/xml
<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0">
<channel>
<title>Flux RSS de test</title>
<description>La description, blablabla...</description>
<link>http://www.experia.com</link>
<item>
<title>Titre élément </title>
<description>Blublublu...</description>
</item>
</channel>
</rss>
$
===>

C'est gagné ! le plus dur est fait. Le programme marche !
Pour la suite, revenez nous voir régulièrement

Et pour les remarques, critiques (ou remerciements

) et questions, c'est le lien "Répondre", abusez-en !
Jean-Michel