
Consommer des Services WEB
- Architecture N tiers
- la couche présentation (html, wap, pda, ...)
- la logique applicative
- un serveur Web (Apache par ex.)
- un serveur d'application rendant possible
l'exécution de
servlets et de pages JSP (programmes JAVA tournant
derrière le serveur Web)
- les servlets allant consommer un(des)
service(s) sur n serveurs.
ce service pouvant être :
- un calcul effectué par un serveur
spécialisé.
- un information retournée :
- carte sous forme d'image pour aller d'un point
à un autre (voir MapPoint
de Microsoft)
- un prix retourné par chaque agence de
voyage pour une recherche de billet d'avion
- etc...(voyez http://www.webservicex.net,
pour une liste)
- un appel à un programme (utilisant ou non une
base de données), sur un serveur central.(Un service de traduction par exemple)
- cette philosophie offrant le grand avantage de :
- réutiliser au maximum (particulièrement les
applications lourdes et historiques),
- d'utiliser chaque système pour ce qu'il sait faire
au mieux (calcul intensif, stockage BD, gestion d'images)
- s'intégrer parfaitement à la notion de portail
Tout cela étant normalisé aujourd'hui sous le
vocable générique de "Web services"
Définitions
-
Les web
services sont des briques
logicielles "en ligne" et permettent de créer des
applications distribuées et accessibles depuis n'importe
quel navigateur xml. Ces briques sont
référencés dans l'annuaire UDDI,
décrite selon la norme WSDL (dérivée
de XML) et opérent avec d'autres briques selon le protocole
SOAP. |
- SOAP
Simple Object Access
Protocol. Protocole XML d'écriture des messages à
envoyer au serveur. technique conçue (par Microsoft) pour
faire passer du DOM sous forme de XML dans de l'HTTP. Cela permet de
contourner les firewalls. .
- WSDL
langage
normalisé (basé sur XML) décrivant un
service WEB, nous y trouverons :
- le
nombre et le type d'argument
- le
retour du service (la réponse)
- l'emplacement
URL de celui-ci
- UDDI
Universal
Description Recovery and Integration. Annuaire des services Web
disponibles.Tous les services, décrits en WDSL peuvent y
être affichés et consultés.
Présentation de l'architecture web-services
- Un web-service
: c'est un logiciel qui interagit avec d'autres au moyen de protocoles
universels (http, xml...)
- Il existe deux formes de services-web : SOAP
et XML-RPC. SOAP est
orienté objet et gère les états tandis que XML-RPC
est procédural et sans gestion des états.
- Les services web présentent les 2 caractéristiques
suivantes :
- enregistrement facultatif auprès d'un service de
recherche (UDDI)
- interface publique avec laquelle le client invoque le service
(WSDL)
- UDDI :
Universal Desciption, Discovery and Integration peut
être vu comme les pages blanches (ou jaunes) des services-web.
C'est un annuaire permettant à des fournisseurs de
présenter leurs services à des 'clients'.
- WSDL : Web
Service Description Language est un langage reposant sur XML dont
on se sert pour décrire les services-web. Il est indispensable
à UDDI pour permettre aux clients de trouver les méthodes
leur permettant d'invoquer les services web. Beaucoup d'outils comme
JBuilder, Delphi ou Office se servent de WSDL pour découvrir et
générer les mécanismes d'invocation des
services-web.
- SOAP : Simple
Object Access Protocol est un protocole basé sur XML et qui
définit les mécanismes d'échanges d'information
entre les clients et les fournisseurs de service-web. Les messages SOAP
sont succeptibles d'être transportés en HTTP, SMTP,
FTP...(souvent HTTP)
- XML-RPC :
protocole RPC (Remote Procedure Call) basé sur XML.
Permet donc l'invocation de procédure distante sur internet.
Précisions sur SOAP
- Une différence importante entre SOAP et XML-RPC est que
les procédures SOAP prennent des paramètres
nommés. L'ordre des paramètres lui n'a pas d'importance,
contrairement à XML-RPC.
- Structure d'un message SOAP :
- une enveloppe qui définit
le contenu du message,
- un en-tête
(optionnel) qui contient les informations d'en-tête
(autorisations et transactions par exemple),
- un corps
contenant les informations sur l'appel et la réponse
- une gestion d'erreur
qui identifie la condition d'erreur
- des attachements
(optionnel)
Exemples
- demande d'une température pour un code postal
donné
<?xml version="1.0"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <SOAP-ENV:Body> <m:getTemp xmlns:m="urn:xmethods-Temperature" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <zipcode xsi:type="xsd:string">44000</zipcode> </m:getTemp> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
|
- réponse
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <SOAP-ENV:Body> <ns1:getTempResponse xmlns:ns1="urn:xmethods-Temperature" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <return xsi:type="xsd:float">22</return> </ns1:getTempResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
|
- Les éléments SOAP peuvent prendre les attributs
suivants :
- actor :
indique le point d'arrivée d'un élément
d'en-tête. Ceci est lié au fait qu'un message SOAP peut
passer par un ensemble d'intermédiaires avant d'arriver à
sa destination finale. Il est donc possible de cibler un attribut vers
un de ces points intermédiaires via cet attribut.
- encodingStyle
: sert à définir les types de données contenu dans
le document.
- mustUnderstand
: sert à définir si le destinataire d'un message doit
traiter un élément d'en-tête (absence de cet
attribut = false).
- SOAP autorise deux modes de communication :
- SOAP RPC : appel synchrone de procédures distantes
où un noeud SOAP envoie un requête SOAP avec des
paramètres et reçoit une réponse en retour.
- messages SOAP : communication orientée message où des
noeuds SOAP envoient et recoivent des documents XML de manière
synchrone ou non.
Précisions sur WSDL
- Un fichier WSDL est un format de description des services web
fondé sur XML.
- Dans WSDL les services communiquent par échange de
messages entre des terminaisons, constituées d'un ou plusieurs
ports, chacun doté d'un type.
- WSDL définit donc :
- les Types
: un système de types applicable à des
données. Utilisation de XML
Schema pour définir les types de données.
- le Message :
décrit les données échangées entre services
web. Peut-être comparé aux paramètres d'un appel de
procédure.
- le Type de Port
(portType): définit les opérations du service
web et les messages impliqués (de type input, output
ou fault). Peut être comparé à une
interface Java.
- La Liaison (binding)
: définit le format des messages (par exemple soap:body
spécifie que le le message considéré sera transmis
dans la partie body du message soap) et le protocole utilisé par
chaque type de port (voir par exemple soap:binding et les
attributs style et transport). C'est
l'implémentation de l'interface.
- Le Port : un
point de terminaison identifié de manière unique par la
combinaison d'une adresse internet et d'une liaison
- Un Service Web
(service) : associe des liaisons à des process concrets
de mise en oeuvre des opérations qu'elles décrivent
(typiquement une URL dans le cas d'une liaison mettant en oeuvre SOAP
sur HTTP)
Il y a une imbriquation à tout cela, qui est toujours décrite à partir de l'élement
le plus fin (chaque élement doit être décrit avant de pouvoir être utilisé)
Un
service (1) c'est :
- un ou plusieurs port(s), comme des fonctions, chacun contenant :
-
une localisaiton (adresse réseau)
(2)
- un binding, soit
(3)
- un protocole (4)
- un type de port (5) , contenant
- une (des) opération(s) (6) ,
liste d'actions possibles, elle même composées de
:
- messages (data) (7) basés sur
- des données typées (ici,
string ou float)
- Une bonne connaissance des namespaces
XML et de XML Schema est un
pré-requis à la lecture d'un document WSDL.
Exemple : description du service web cité ci-dessus
<?xml version="1.0"?> <definitions xmlns:tns="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://www.xmethods.net/sd/TemperatureService.wsdl" name="TemperatureService">
<message name="getTempRequest"> (7a)
<part name="zipcode" type="xsd:string"/>
</message>
<message name="getTempResponse"> (7b)
<part name="return" type="xsd:float"/>
</message>
<portType name="TemperaturePortType"> (5)
<operation name="getTemp"> (6)
<input message="tns:getTempRequest"/> (7a)
<output message="tns:getTempResponse"/> (7b)
</operation>
</portType>
<binding name="TemperatureBinding" (3) type="tns:TemperaturePortType"> (5)
<soap:binding style="rpc" (4)
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getTemp"> (6)
<soap:operation/>
<input>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:xmethods-Temperature"/>
</input>
<output>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:xmethods-Temperature"/>
</output>
</operation>
</binding>
<service name="TemperatureService"> (1) <documentation>Returns current temperature in a given U.S. zipcode </documentation> <port name="TemperaturePort" binding="tns:TemperatureBinding"> (3) <soap:address location="http://services.xmethods.net:80/soap/servlet/rpcrouter"/> (2) </port> </service> </definitions>
|
Sur nos systèmes IBM i et
AS400 ?
L'OS propose aujourd'hui un nouveau serveur
d'application intégré, permettant
de déclarer extrèment facilement un programme RPG en tant que
service WEB.
et le contraire ?
En V6R1, et de manière intégrée au système d'exploitation, nous avons des
mécanismes pour accèder à un service web depuis le langage
RPG (entre autre).
on dit "consommer un service web"...
L'exemple fourni par IBM est basé sur le service ConvertTemp automatiquement
créé lors de la création du serveur d'application
Allez sur la page 
et récupérez le fichier de définition (WSDL) en cliquant sur View
definition
(sinon, pour celui-ci uniquement , il est déja présent dans /QIBM/ProdData/OS/WebServices/V1/client)
ensuite, il faut générer le "stub" soit
le programme "proxy"
pour cela nous utiliserons l'outil WSDL2WS.SH sous shell
(STRQSH)
> /QIBM/ProdData/OS/WebServices/V1/Client/bin/wsdl2ws.sh
-lc -o/myconverttemp
/QIBM/ProdData/OS/WebServices/V1/Client/samples/ConvertTemp/ConvertTemp.wsdl
Code generation completed.
$
|
- -lc demande à ce que l'on génère du C (par défaut wsdl2ws.sh génère du
C++, difficilement utilisable en RPG)
- -o/monrépertoire indique un répertoire de sortie
- /QIBM/...../ConvertTemp.wsld représente les coordonnées du fichier wsdl
Si vous passez la commande ls, vous devez voir :
$
> ls /myconverttemp
ConvertTempPortType.c CONVERTTEMPInput.c CONVERTTEMPResult.c
ConvertTempPortType.h CONVERTTEMPInput.h CONVERTTEMPResult.h
$
|
Détails du fichier wsdl
Extrait de la définition du service
---------------------------------------
<wsdl:portType name="ConvertTempPortType">
<wsdl:operation name="converttemp_XML">
<wsdl:input message="axis2:converttemp_XMLRequest" wsaw:Action="urn:converttemp_XML"/>
<wsdl:output message="axis2:converttemp_XMLResponse" wsaw:Action="urn:converttemp_XMLResponse"/>
</wsdl:operation>
<wsdl:operation name="converttemp">
<wsdl:input message="axis2:converttempRequest" wsaw:Action="urn:converttemp"/>
<wsdl:output message="axis2:converttempResponse" wsaw:Action="urn:converttempResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ConvertTempSOAP11Binding" type="axis2:ConvertTempPortType">
.../...
</wsdl:binding>
< wsdl:service name="ConvertTemp">
<wsdl:port name="ConvertTempSOAP11port_http" binding="axis2:ConvertTempSOAP11Binding">
<soap:address location="http://localhost:10022/web/services/ConvertTemp"/>
</wsdl:port>
</wsdl:service>
|
les fonctions C importantes et utilisables en RPG, sont liées au type
de port (proche de la notion d'interface en java)
l'outil a généré les fonctions de gestion du "stub" :
- get_ConvertTempPortType_stub : lancement du stub (initialisation)
- destroy_ConvertTempPortType_stub : destruction
- get_ConvertTempPortType_Status : status
- set_ConvertTempPortType_ExceptionHandler : hanlder (routine
de gestion d'erreur)
extern AXISCHANDLE get_ConvertTempPortType_stub(const char* pchEndPointUri);
extern void destroy_ConvertTempPortType_stub(AXISCHANDLE pStub);
extern int get_ConvertTempPortType_Status(AXISCHANDLE pStub);
extern void set_ConvertTempPortType_ExceptionHandler(AXISCHANDLE pStub,
AXIS_EXCEPTION_HANDLER_FUNCT fp);
|
puis les fonctions liées aux opérations il
faut passer en paramètre le pointeur recu lors de l'initialisation (de
type AXISCHANDLE)
- ConvertTemp : récupération des données sous forme d'une structure
- ConvertTemp_XML : récupération des données sous forme de flux XML
extern xsdc__string converttemp_XML(AXISCHANDLE pStub, CONVERTTEMPInput*
Value0);
extern CONVERTTEMPResult* converttemp(AXISCHANDLE pStub, CONVERTTEMPInput*
Value0);
|
La dernière fonction recoit un pointeur sur une structure de type CONVERTTEMPResult
typedef struct CONVERTTEMPResultTag {
xsdc__string _TEMPOUT;
} CONVERTTEMPResult;
|
dont la mémoire est allouée dynamiquement, il faut donc la libérer par Axis_Delete_CONVERTTEMPResult
(voir CONVERTEMPResult.h)
En résumé :
- Initialiser la connexion par get_ConvertTempPortType_stub
- Lancer le service par converttemp
- Libérer la mémoire par Axis_Delete_CONVERTTEMPResult
- libérer la connexion par destroy_ConvertTempPortType
Dans un programme RPG ou nous allons déclarer les fonctions en
prototype, puis linker tout ce petit monde...
h DFTNAME(CNVRTTEMP) ********************************************************************* * * * IBM Web Services Client for ILE * * * * FILE NAME: ConvertTempClient.RPGLE * * * * DESCRIPTION: Source for ConvertTemp Web service client * * * *-------------------------------------------------------------------- * Prototypes for the service interface and operations * obtained from ConvertTempPortType.h file. *-------------------------------------------------------------------- DgetStub PR * ExtProc('get_ConvertTempPortType_stub') D pEndpoint * Value * DConvertTemp PR * ExtProc('converttemp') D pWsStub * Value D pTempInF * Value * DdestroyStub PR ExtProc('destroy_ConvertTempPortType _stub') D pWsStub * Value *-------------------------------------------------------------------- * Prototype for function to free dynamic storage obtained from * CONVERTTEMPResult.h file. *-------------------------------------------------------------------- DdestroyResult PR ExtProc('Axis_Delete_CONVERTTEMPResult') D pResult * Value D size 9B 0 Value *-------------------------------------------------------------------- * Input data structure used by the converttemp operation. The structure * layout is obtained from CONVERTTEMPInput.h file. *-------------------------------------------------------------------- D Input DS D pTempInF * *-------------------------------------------------------------------- * Result returned by converttemp operation. The structure layout * is obtained from CONVERTTEMPResult.h file. *-------------------------------------------------------------------- D Result DS BASED(ResultP) D pTempOutC * *-------------------------------------------------------------------- * Miscellaneous declarations. *-------------------------------------------------------------------- D WsStubP S * D Endpoint S 100A D TempInF S 10A D ResultP S * D OutputText S 50A *-------------------------------------------------------------------- * Program entry point. The input parameter is a character field * representing the temperature in Fahrenheit. *-------------------------------------------------------------------- C *ENTRY PLIST C PARM TEMPIN 32 *-------------------------------------------------------------------- * Web service logic. The code will attempt to invoke a Web * service in order to convert temperature in Fahrenheit to Celsius * and then display the results. *-------------------------------------------------------------------- /FREE // Get a Web service stub. The host and port for the endpoint may need // to be changed to match host and port of Web service. You can pass // *NULL to getStub() if the endpoint in the WS DL file is correct. Endpoint = 'http://localhost:10022/web/services/ConvertTemp' + X'00'; WsStubP = getStub(%Addr(Endpoint));
// Initialize input values. TempInF = %trim(TEMPIN) + X'00'; pTempInF = %addr(TempInF);
// Invoke the ConvertTemp Web service operation. ResultP = ConvertTemp(WsStubP:%Addr(Input));
// Prepare output string depending on what was returned. if (ResultP <> *NULL); OutputText = %str(pTempInF) + ' Fahrenheit is ' + %str(pTempOutC) + ' Celsius.'; else; OutputText = 'No results returned...'; endif;
// Display results. dsply OutputText;
// Clean up storage for the result and the Web service stub. destroyResult(ResultP:0); destroyStub(WsStubP); /END-FREE *-------------------------------------------------------------------- * Done. *-------------------------------------------------------------------- C seton lr
|
Compilation
Placez vous dans votre répertoire (/myConvertTemp) par CD
Copier le fichier ConvertTempClient.RPGLE dans votre répertoire
et pensez à modifier
(en rouge) l'URL permettant d'accèder au service web
CRTRPGMOD QTEMP/CVTTEMPCL SRCSTMF(ConvertTempClient.rpgle)
(remarquez la nouveauté V6 permettant de compiler un fichier de l'IFS)
CRTCMOD QTEMP/CVTTEMPIN SRCSTMF(ConvertTempInput.c)
INCDIR('/qibm/proddata/os/webservices/v1/client/include') ENUM(*int)
CRTCMOD QTEMP/CVTTEMPRES SRCSTMF(ConvertTempResult.c)
INCDIR('/qibm/proddata/os/webservices/v1/client/include') ENUM(*int)
CRTCMOD QTEMP/CVTTEMPPT SRCSTMF(ConvertTempPortType.c)
INCDIR('/qibm/proddata/os/webservices/v1/client/include') ENUM(*int)
puis
CRTPGM PGM(MABIB/CVTTEMP) MODULE(QTEMP/CVTTEMPCL +
QTEMP/CVTTEMPIN QTEMP/CVTTEMPRES QTEMP/CVTTEMPPT°
BNDSRVPGM(QSYSDIR/QAXIS10CC)
test
CALL PGM(CVTTEMP) PARM('100')
DSPLY 100 Fahrenheit is 37.77 Celsius.
|
Ca marche !
En début 2011 les PTF suivantes
SI42234 (V5R40) , SI42236 (V6R10) ,
SI42235 (v7) apportent un nouvel utilitaire wsdl2rpg
comme le précédent, il se tourve dans QIBM/ProdData/OS/WebServices/V1/Client/bin/
> /QIBM/ProdData/OS/WebServices/V1/Client/bin/wsdl2rpg.sh
-o/myconvertRPG
-s/QSYS.LIB/MABIB.LIB/CONVERT.SRVPGM
/QIBM/ProdData/OS/WebServices/V1/Client/samples/ConvertTemp/ConvertTemp.wsdl
Code generation completed. Generated files in directory
'/myconvertRPG'.
Attempting to create service program...
Service program created. Service program is
'/QSYS.LIB/MABIB.LIB/CONVERT.SRVPGM'.
$ |
L'option -T demande la création d'un programme de service dans la bibliothèque MABIB.
Cette fois il génère aussi du RPG, soit 6
fichiers en plus, portant le nom du type de port (ConvertTempPortType
dans nos exemples)
ConvertTempPortType.CL |
le CL de création du *SRVPGM |
ConvertTempPortType.rpgleinc |
fichier à inclure (dans votre programme) |
ConvertTempPortType.rpgle |
le code d'invoquation du web service (*SRVPGM) |
ConvertTempPortType_util.rpgleinc |
fichier à inclure (dans le source suivant) |
ConvertTempPortType_util.rpgle |
divers utilitaires |
ConvertTempPortType__xsdtypes.rpgleinc |
différents types de données standards |
le fichier de référence est le ConvertTempPortType.rpgleinc qui contient les définitions dont vous avez besoin, et qu'il faut inclure dans votre code :
- stub_create_ConvertTempPortType
permettant d'initialiser la connexion
- stub_destroy_ConvertTempPortType
permettant de clore la connexion
- stub_op_ConvertTemp (un par "opération")
permettant de lancer le service.

Compilez ce source par CRTRPGMOD.
Attention, pour des problèmes de code page, vous devrez peut-être modifier légèrement le fichier à inclure
et remplacer les @ de fin par à, sur les trois fonctions vues plus haut ou bien recompiler le *SRVPGM.

Normalement, les dernière PTF corrigent ce bug, l'opération n'est plus utile.
Si vous devez travailler en HTTPS (avec un certificat)
- Allez chercher le certificat sur le serveur concerné
- Installez le certficat sous Digital Certificat Manager
- Dans votre code, utilisez l'API axiscStubSetSecure(), après avoir ajouté le /copy
/copy /QIBM/ProdData/OS/WebServices/V1/client/include/Axis.rpgleinc * qui contient D* axiscStubSetSecure... D* PR EXTPROC('axiscStubSetSecure') D* pStub * Value D* pKeyRingFile * Value OPTIONS(*STRING) D* pKeyRingSorP * Value OPTIONS(*STRING : *NOPASS) D* pKeyRingLabel * Value OPTIONS(*STRING : *NOPASS) D* pV2Cipher * Value OPTIONS(*STRING : *NOPASS) D* pV3Cipher * Value OPTIONS(*STRING : *NOPASS) D* pTLSCipher * Value OPTIONS(*STRING : *NOPASS) /free if stub_create_convertTempPortType; axiscStubSetSecure(WsStub.handle: '/QIBM/USERDATA/ICSS/CERT/SERVER/DEFAULT.KDB': 'motdepasse': 'label':'NONE':'05':'NONE'); |
Si vous recevez HTTPTransportException: HTTPS transport error.GSKit Error is 428 - No certificate is available for SSL processing.
ne mettez rien 3eme paramètre (remplacez motdepasse par une chaine vide)
Si vous rencontrez des problèmes, lancez une trace par axiscAxisStartTrace(’/tmp/axis.log’:*NULL) en début de pgm.
tous les détails sur ces API : http://www-03.ibm.com/systems/resources/systems_i_software_iws_pdf_WebServicesClient_new.pdf
Dernier point, vous pouvez linker tout ce petit monde, par :

Essayons
.
Cette nouvelle version, permet un code RPG nettement simplifié, tant mieux !
Attention.
avec le niveau 9 de SF99713 (printemps 2015) les fonctions sont renommées :
- stub_create_xxxxxxxxServices (et non stub_create_xxxxxxxxPortType)
pour initialiser la connexion
- stub_destroy_xxxxxxxxServices (et non stub_destroy_xxxxxxxxPortType)
pour clore la connexion
- stub_op_xxxxxxxx0 (le chiffre 0 en plus à chaque opération)
pour lancer le service correspondant.

cette version introduit un bug (en Français) : un paramètre est nommé #_return -> voir l'APAR SE62384
La PTF SI57437 corrige cela.
Remarquez dans la fenêtre structure, le prototype pour l'opération (suite au /copy)
les paramètres sont en fait des DS possédant deux sous-zones significatives
- isNil = booléen indiquant ou pas la nulité (val.nulle)
- value = la valeur elle même
Dernier point, vous devez linker tout ce petit monde, par :

.Essayons le pgm : 
Cette version de l'utilitaire, permet un code RPG relativement simple plus lisible que le source généré en C par wsdl2ws.
Mais Il faut vous adapter aux paramètres attendus par le Service.
Par exemple celui-ci attend des paramètres plus simples (voyez le .wsdl)

ce qui génère (par wsdl2rpg)

le code suivant est cohérent (et fonctionne) :

Enfin, si vous devez travailler en HTTPS (avec un certificat)
- Allez chercher le certificat sur le serveur concerné
- Installez le certificat sous Digital Certificat Manager
- Dans votre code, utilisez l'API axiscStubSetSecure(), après avoir ajouté le /copy
/copy /QIBM/ProdData/OS/WebServices/V1/client/include/Axis.rpgleinc * qui contient D* axiscStubSetSecure... D* PR EXTPROC('axiscStubSetSecure') D* pStub * Value D* pKeyRingFile * Value OPTIONS(*STRING) D* pKeyRingSorP * Value OPTIONS(*STRING : *NOPASS) D* pKeyRingLabel * Value OPTIONS(*STRING : *NOPASS) D* pV2Cipher * Value OPTIONS(*STRING : *NOPASS) D* pV3Cipher * Value OPTIONS(*STRING : *NOPASS) D* pTLSv1Cipher * Value OPTIONS(*STRING : *NOPASS) D* pTKSv11Cipher * Value OPTIONS(*STRING : *NOPASS) D* pTKSv12Cipher * Value OPTIONS(*STRING : *NOPASS) * ce dernier paramètre permet une tolérance (date dépassée par ex.) D* pTolerate * Value OPTIONS(*STRING : *NOPASS) /free
NONE = 'NONE' + x'00; TRUE = 'true' + x'00';
if stub_create_convertTempServices; axiscStubSetSecure(WsStub.handle: '/QIBM/USERDATA/ICSS/CERT/SERVER/DEFAULT.KDB': 'motdepasse': 'label':NONE:NONE:NONE:NONE:x'00':TRUE); // activation TLSv12 + tolérance |
Si vous recevez HTTPTransportException: HTTPS transport error.GSKit Error is 428 - No certificate is available for SSL processing.
ne mettez rien en 3eme paramètre (remplacez motdepasse par une chaine vide)
Si vous avez des temps de réponses particulièrement longs, utilisez axiscStubSetTransportConnectTimeout(handle, nb-de-secondes)
Si vous rencontrez des problèmes, lancez une trace par axiscAxisStartTrace(’/tmp/axis.log’:*NULL) en début de pgm.
( axiscAxisStopTrace permet d'arrêter la trace)
Pour vous sortir à l'aide d'un proxy
/copy /QIBM/ProdData/OS/WebServices/V1/client/include/Axis.rpgleinc if stub_create_convertTempServices; axiscStubSetProxy(WsStub.handle: 'adresse-proxy' : 'port'); axiscStubSetProxyUserName(WsStub.handle: 'proxy-user'); axiscStubSetProxyPassword(WsStub.handle: 'mot de passe');
|
Pour un accès avec authentification
/copy /QIBM/ProdData/OS/WebServices/V1/client/include/Axis.rpgleinc if stub_create_convertTempServices; axiscStubSetUserName(WsStub.handle: 'HTTP-user'); axiscStubSetPassword(WsStub.handle: 'mot de passe');
|
tous les détails sur ces API : http://www-03.ibm.com/systems/resources/systems_i_software_iws_pdf_WebServicesClient_new.pdf
Enfin, depuis SF99368 Level 52, SF99713 Level 26, SF99722 Level 13
(Décembre 2017), nos pouvons récupérer les erreurs SOAP générées par le
serveur
- axiscStubGetSOAPFault : retrouve un pointeur sur l’élément fault
- axiscSoapFaultGetFaultcode : retrouve faultcode
- axiscSoapFaultGetFaultstring : retrouve faultstring
- axiscSoapFaultGetFaultactor : retrouve faultactor
- axiscSoapFaultGetSimpleFaultDetail : retrouve faultdetail
- voir https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383507
extrait de /QIBM/ProdData/OS/WebService/V/client/Axi.rpgleinc sous RDI

Exemple
SoapFault = axiscStubGetSOAPFault(WsStub.handle) ; if SoapFault <> *NULL; ErrCode = %str(axiscSOAPFaultGetFaultCode(SoapFault)); ErrChaine = %str(axiscSOAPFaultGetFaultString(SoapFault)); ErrActeur = %str(axiscSOAPFaultGetFaultActor(SoapFault)); ErrDetail = %str(axiscSOAPFaultGetSimpleFaultDetail(SoapFault)); endif;
|
En Mai 2016, IBM propose aussi d'utiliser directement les API Axis pour consommer des web services REST
il vous faut :
7.3: SI60805, SI60808
7.2: SI60806, SI60809
7.1: SI60807, SI60810
- axiscTransportCreate créé le transport (la connexion)
- axiscTransportSetProperty permet d'indiquer des propriétés, comme
- le niveau de protocole Http
- la méthode (POST, GET, ...)
- axiscTransportFlush active (lance) la requête
- axiscTransportGetProperty récupère une propriété (comme le Statut HTTP)
- axiscTransportReceive lit la donnée
- axiscTransportDestroy clôt la connexion
Avec,
7.3 : SI63730,
SI63759
7.2 :
SI63729,
SI63760
7.1 : SI63727,
SI63761
- axiscStubSetProxySSL(WsStub.handle: 1); permet de se connecter en SSL à un proxy
- axiscTransportSetProperty permet alors d'indiquer comme propriété :
- AXISC_PROPERTY_HTTP_PROXYSSL
Exemple
**free Ctl-Opt ; // pour compiler CRTRPGMOD puis CRTPGM BNDSRVPGM((QSYSDIR/QAXIS10CC)) //puis // ADDLNK OBJ('/qsys.lib/af4test.lib/datanantes.pgm') NEWLNK('/home/CM/datanantes') // pour tester, sous QSH-> datanantes xml // ******************************************************************** dcl-pi *N; wformat char(4); END-PI; dcl-s format char(4);
/COPY /QIBM/ProdData/OS/WebServices/V1/client/include/Axis.rpgleinc
DCL-S rc INT(10); DCL-S tHandle POINTER;
DCL-S uri CHAR(200); DCL-S response CHAR(32768); DCL-S request CHAR(32768); DCL-S propBuf CHAR(100);
// -------------------------------------------------------------------- // Web service REST : liste des aires de co-voiturage à Nantes. // --------------------------------------------------------------------
// choix du format (xml,json,csv, ...) if %parms() <1; format = 'xml'; else; format = wformat; ENDIF;
// récupération des data (liste des aires de co-voiturage à Nantes) uri = 'http://data.nantes.fr/api/publication/24440040400129_NM_NM_00003/LOC_AIRES_COV_NM_STBL/content/?format=' + format; PRINT ('==Retourne les aires de co-voiturage sur '); PRINT (uri);
// Connexion. tHandle = axiscTransportCreate(uri:AXISC_PROTOCOL_HTTP11); if (tHandle = *NULL); PRINT ('TransportCreate() failed'); return; endif;
// méthode GET propBuf = 'GET' + X'00'; axiscTransportSetProperty(tHandle: AXISC_PROPERTY_HTTP_METHOD: %addr(propBuf));
// Exécution flushAndReceiveData();
// Déconnexion. axiscTransportDestroy(tHandle);
*INLR=*ON;
// code des procédures extrait de developerWorks // ============================================= // Print to standard out (under QSH) // ============================================= DCL-PROC PRINT ; dcl-pi *n; msg varchar(32767) const; end-pi;
dcl-pr printf extproc(*dclcase); template pointer value options(*string); dummy int(10) value options(*nopass); end-pr;
dcl-c NEWLINE CONST(x'15');
printf(%TRIM(msg) + NEWLINE); END-PROC;
// ========================================= // Handle error // ========================================= DCL-PROC checkError ; dcl-pi *n; msg varchar(5000) const; end-pi;
DCL-S axisCode INT(10); DCL-S statusCode POINTER; DCL-S rc INT(10);
axisCode = axiscTransportGetLastErrorCode(tHandle); PRINT (msg + ' call failed: ' + %CHAR(axisCode) + ':' + %STR(axiscTransportGetLastError(tHandle)));
if (axisCode = EXC_TRANSPORT_HTTP_EXCEPTION); rc = axiscTransportGetProperty(tHandle: AXISC_PROPERTY_HTTP_STATUS_CODE: %ADDR(statusCode)); PRINT ('HTTP Status code: ' + %STR(statusCode)); endif; END-PROC;
// ========================================= // Flush and Receive data // ========================================= DCL-PROC flushAndReceiveData; dcl-pi *n; end-pi;
DCL-S header POINTER; DCL-S property CHAR(100); DCL-S bytesRead INT(10) inz(0);
clear response; clear header;
// Flush data so request is sent rc = axiscTransportFlush(tHandle); if (rc = -1); checkError ('TransportFlush()'); return; endif;
// Receive data and print out data and response to stdout rc = axiscTransportReceive(tHandle: %ADDR(response): %SIZE(response): 0); if (rc = 0); PRINT ('No data to read'); else; dow rc > 0 AND bytesRead < %SIZE(response); bytesRead = bytesRead + rc; rc = axiscTransportReceive(tHandle: %ADDR(response)+bytesRead: %SIZE(response)-bytesRead: 0); enddo; endif;
if (rc = -1); checkError ('TransportReceive()'); elseif (bytesRead > 0); PRINT ('Bytes read: ' + %CHAR(bytesRead)); PRINT ('Data: ' + response); endif;
if (rc > -1); rc = axiscTransportGetProperty(tHandle: AXISC_PROPERTY_HTTP_STATUS_CODE: %addr(header)); if (rc = -1); checkError ('TransportGetProperty()'); else; PRINT ('HTTP status code: ' + %str(header)); endif; endif;
END-PROC; |
Testons

Copyright © 1995,2015 VOLUBIS