Service Web - Client
Pré-requis : exemple 1.
Exemple 2 : Météo
Nous allons maintenant faire appel à un service totalement extérieur, correspondant à un cas d’appel réel. La démarche est la même que l’exemple 1, mais nous allons avoir à gérer plus de complexité.
Nous avons choisi un service web qui donne la météo d’une ville (US uniquement) à partir du code postal. La description du service est disponible ici : http://ws.cdyne.com/WeatherWS/Weather.asmx?WSDL.
Pour vous assurer de la neutralité du choix, vous pouvez voir le site de la société américaine qui héberge le service : http://www.cdyne.com.
Le zip disponible contient l’intégralité des sources décrits ci-dessous : exemple 2. Vous pouvez le télécharger et le regarder directement, ou effectuer vous-même les manipulations décrites.
Récupérez le fichier wsdl, enregistrez le sous le nom Weather.wsdl et testez le web service avec l’outil de votre choix.
Ici nous avons utilisé l’explorateur de services web d’Eclipse/RDi SOA/RDPS

On remarque que la structure du fichier wsdl est plus complexe.
En effet, un fichier wsdl décrit un service web, et ce service web peut contenir plusieurs opérations utilisables via plusieurs protocoles. C’est le cas ici :
- Weather : nom du service web
- GetCityWeatherByZIP, GetWeatherInformation et GetCityWeatherByZIP : opérations du service web (communément WebMethod)
- WeatherHttpPost, WeatherSoap, WeatherHttpGet et WeatherSoap12 : liaisons (port). Cela représente les différents protocoles utilisables pour l’appel du service web.
Ici, l’ensemble des trois opérations est utilisable par l’ensemble des quatre liaisons.
Remarque : l’éditeur de wsdl d’Eclipse/RDi SOA/RDPS propose une vision structurée de ces informations :

Revenez au test du service web : vous allez utiliser la liaison Soap qui est la seule supportée par le Client de Service Web ILE.
Choisissez l’opération « GetCityWeatherByZIP », ajoutez un paramètre et renseignez un code postal US :

Cliquez sur OK, le résultat suivant s’affiche, vous donnant la météo local pour le jour même :

Via le bouton « Source », vous pouvez visualiser le contenu complet des flux SOAP qui ont été émis/reçus :

Nous allons maintenant réaliser un client RPG ILE.
- Enregistrer dans votre répertoire IFS /home/vous/demows le fichier WSDL disponible ici : http://ws.cdyne.com/WeatherWS/Weather.asmx?WSDL, sous le nom « Weather.wsdl ».
- Il vous faudra également un répertoire /home/vous/demows/module.
- Se mettre dans le shell : commande QSH ou STRQSH
- Tapez la commande de génération des stubs :
o /QIBM/prodData/OS/webservices/v1/client/bin/wsdl2ws.sh -lc -o/home/vous/demows/module /home/vous/demows/Weather.wsdl
o Vous obtenez le message suivant :

o La commande « ls » permet de voir quels sont les fichiers générés (ceux présents dans le sous-répertoire module) :

o On s’aperçoit ici que de nombreux fichiers sont générés :
|
WeatherSoap.c |
Contient l’ensemble des procédures nécessaires pour créer la connexion et l’appel pour les trois opérations du service web |
|
WeatherSoap.h |
Contient les prototypes des procédures de WeatherSoap.c |
|
WeatherReturn.c |
Contient les procédures qui permettent de manipuler les paramètres retour du service web, pour l’opération « GetCityWeatherByZIP » |
|
WeatherReturn.h |
Contient les déclarations qui représentent les données en retour du service web, pour l’opération « GetCityWeatherByZIP » Contient également les prototypes de procédures qui permettent de manipuler ces structures |
|
ArrayOfWeatherDescription.c |
Contient les procédures qui permettent de manipuler les paramètres retour du service web, pour l’opération « GetWeatherInformation » |
|
ArrayOfWeatherDescription.h |
Contient les déclarations qui représentent les données en retour du service web, pour l’opération « GetWeatherInformation » Contient également les prototypes de procédures qui permettent de manipuler ces structures |
|
ForecastReturn.c |
Contient les procédures qui permettent de manipuler les paramètres retour du service web, pour l’opération « GetCityForecastByZIP » |
|
ForecastReturn.h |
Contient les déclarations qui représentent les données en retour du service web, pour l’opération « GetCityForecastByZIP » Contient également les prototypes de procédures qui permettent de manipuler ces structures |
|
Autres |
Ce sont des sous-structures utilisées par les différentes structures de retour ci-dessus |
Le nom et le nombre de sources générés dépendent de la description du service présente dans le fichier WSDL.
Important : la commande wsdl2ws.sh ne gère qu’un port unique. Si plusieurs ports sont déclarés dans le fichier wsdl, seule le premier sera traité.
Ici, dans le fichier Weather.wsdl, quatre ports sont définis :

Seul le premier est traité : WeatherSoap. Toujours dans le wsdl, ce port est défini ainsi :
![]()
Cela correspond au protocole du langage WSDL 1.1, langage SOAP 1.1 pour protocole de transport HTTP.
- Les éléments que nous allons utiliser sont systématiquement les mêmes :
o Création et destruction du stub
o Invocation du service web
o Destruction du résultat pour libérer les ressources allouées
Soit :
o dans le fichier « WeatherSoap.h » :

o dans le fichier « WeatherReturn.h »

Nous appliquons la même démarche que dans le 1er exemple : créer un module RPG qui va utiliser les procédures C que l’on vient de générer.
Pour cela nous avons besoin de prototyper toutes les procédures à utiliser, mais également de définir des structures de données RPG qui concordent avec les déclarations C.
o Commencez par créer un fichier « GetCityWeatherByZIPClient.rpgle » dans le répertoire IFS « /home/vous/module »
o Fichier « WeatherSoap.h » :

Que nous pouvons exprimer en RPG sous cette forme :

o Fichier « WeatherReturn.h » :

Que nous pouvons exprimer en RPG sous cette forme :

Remarque
Type xsdc__boolean : le type boolean n’existe pas en C. Le type xsdc__boolean défini par AXIS est en réalité un int (du C). Il est considéré comme « false » (*off) si sa valeur est 0. Toute autre valeur est considérée comme vrai (*on).
Le programme : Vous pouvez télécharger l’archive des sources directement ici : exemple 2.
Afin de simplifier la lecture du code, nous avons créé une procédure principale « main », ainsi qu’une procédure spécifique au parcours du résultat du service web : « parseResult »
- Procédure principale :

o La mécanique est la même que pour l’exemple 1.
o Le parcours du résultat est délégué à la procédure « parseResult ».
- Procédure « parseResult » :

o Pas de difficulté particulière : parcours des différentes valeurs de la structure TWeatherReturn :
§ Nécessite la fonction intégrée %str pour convertir une chaine de caractères C (terminaison nulle) en caractères RPG.
Le source RPG est prévu pour une compilation en V6R1 (version de disponibilité du client de service web). Cela nécessite donc une adaptation pour une compilation en V5R4.
Compilation des modules :
- CRTCMOD MODULE(QTEMP/WETCLIM1) SRCSTMF('/home/vous/demows/module/temp.c') DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTCMOD MODULE(QTEMP/WETCLIM2) SRCSTMF('/home/vous/demows/module/ArrayOfForecast.c’) DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTCMOD MODULE(QTEMP/WETCLIM3) SRCSTMF('/home/vous/demows/module/ArrayOfWeatherDescription.c’) DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTCMOD MODULE(QTEMP/WETCLIM4) SRCSTMF('/home/vous/demows/module/Forecast.c’) DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTCMOD MODULE(QTEMP/WETCLIM5) SRCSTMF('/home/vous/demows/module/Forecast_Array.c’) DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTCMOD MODULE(QTEMP/WETCLIM6) SRCSTMF('/home/vous/demows/module/ForecastReturn.c’) DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTCMOD MODULE(QTEMP/WETCLIM7) SRCSTMF('/home/vous/demows/module/POP.c’) DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTCMOD MODULE(QTEMP/WETCLIM8) SRCSTMF('/home/vous/demows/module/WeatherDescription.c’) DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTCMOD MODULE(QTEMP/WETCLIM9) SRCSTMF('/home/vous/demows/module/WeatherDescription_Array.c’) DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTCMOD MODULE(QTEMP/WETCLIM10) SRCSTMF('/home/vous/demows/module/WeatherReturn.c’) DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTCMOD MODULE(QTEMP/WETCLIM11) SRCSTMF('/home/vous/demows/module/WeatherSoap.c’) DBGVIEW(*SOURCE) ENUM(*INT) INCDIR('/qibm/proddata/os/webservices/v1/client/include')
- CRTRPGMOD MODULE(QTEMP/MAIN) SRCSTMF('/home/vous/demows/module/GetCityWeatherByZIPClient.rpgle') DBGVIEW(*ALL)
Création du programme
- CRTPGM PGM(maLib/WETHCLIENT) MODULE(QTEMP/MAIN QTEMP/WETCLIM1 QTEMP/WETCLIM2 QTEMP/WETCLIM3 QTEMP/WETCLIM4 QTEMP/WETCLIM5 QTEMP/WETCLIM6 QTEMP/WETCLIM7 QTEMP/WETCLIM8 QTEMP/WETCLIM9 QTEMP/WETCLIM10 QTEMP/WETCLIM11) BNDSRVPGM((QSYSDIR/QAXIS10CC))
Exemple d’appel en ligne de commande :

Conclusion
Nous avons vu comment réaliser un client. La démarche sera toujours la même, seule la complexité des paramètres en entrée et en sortie va augmenter.
Toutefois, nous remarquons des éléments positifs ou négatifs :
- Négatifs
o Dans notre cas, le fichier wsdl décrit trois opérations : « GetWeatherInformation », « GetCityForeCastByZIP » et celle que nous avons utilisé « GetCityWeatherByZIP » :
§ La commande wsdl2ws.sh génère les modules C nécessaires à ces trois opérations. Il nous faut donc compiler et lier dans un programme l’ensemble de ces modules, même si nous n’utilisons au final que des procédures de « WeatherSoap.c » et de « WeatherReturn.c »
§ Une solution consiste à modifier manuellement le fichier wsdl avant d’appeler la commande wsdl2ws.sh :
· Ne garder que l’opération que l’on souhaite utiliser, ainsi que le port nécessaire. Supprimer tout le reste. Ainsi, nous aurons moins de code généré, moins de code à compiler et surtout il sera plus simple de se repérer dans les sources.
· L’exemple est fourni ici : exemple 2 avec wsdl simple. Le module RPG est strictement identique ; seuls les modules C nécessaires sont conservés (2 modules sur 11).
o Le transtypage des données est la principale difficulté :
§ Le fichier wsdl contient des informations sur les types de paramètres du service web sous la forme de définitions xsd. Le domaine de valeur possible est alors défini par la norme xsd.
§ Lors de la génération du client, il y a une expression des types xsd vers des types et des structures C correspondantes. Cette conversion est explicitée dans la documentation Axis (disponible sur votre AS400 dans \QIBM\ProdData\OS\WebServices\V1\client\docs\api\index.html)
§ Nous devons ensuite reconvertir ces structures C vers des types RPG.
- Positifs
o Avec un programme court (170 lignes dans l’exemple dont beaucoup de commentaires) donc un effort de développement limité, il est possible d’appeler un service web depuis un programme RPG. L’intégration dans l’existant est donc simple.
o Les temps de réponse sont bons : bien meilleurs qu’avec un client Java que l’on invoque depuis un programme RPG. Le produit Axis utilisé est un standard dans le monde des services web.
Pour nous demander des informations complémentaires,
Adressez un mail à : contact@gaia.fr
Ou
Téléphonez nous au 04.72.53.00.12