Services WEB


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 (SOAP) fourni par IBM est basé sur le service ConvertTemp automatiquement créé lors de la création du serveur d'application

 

Allez sur la page

 

Si vous le testez, vous voyez (remarquez le paramètre param0, qui est une structure composée d'une seule zone _TEMPIN) :

ATTENTION, sur les dernières versions du serveur de web services les noms des variables ne sont plus précédés de "_", sauf à indiquer enabled ici :




(en cas de doute, vérifiez le fichier .wsdl)

 

Utilisation en PHP


Débug :

<?php

  $client = new SoapClient("http://AS400S:10030/web/services/ConvertTemp?wsdl");

  $param = array("param0" => array("TEMPIN" => 100));

  $result = $client->converttemp($param);


  echo "<br>resultat ";

   var_dump($result);


?>

Résultat :

>

Pour accéder à la valeur

<?php

  $client = new SoapClient("http://AS400S:10030/web/services/ConvertTemp?wsdl");

  $param = array("param0" => array("TEMPIN" => 100));

  $result = $client->converttemp($param);

  echo $result->return->TEMPOUT;

?>



 

Si vous retournez un DS à occurrences -> DIM(xx) , tenez en compte dans votre code

Démo avec notre exemple retournant une DS INFOCENTRE à NBPROD occurrences



affiche



en .NET

Après avoir ajouté une référence web dont l'URL est "http://AS400:10030/web/services/ConvertTemp?wsdl"

Dim wsTemp As New AS400_Temperature.ConvertTemp
Dim input As New AS400_Temperature.CONVERTTEMPInput

   input._TEMPIN = txtF.text
   Response.Write(wsTemp.converttemp_XML(input))

Par exemple sur l'événement "click" d'un bouton cmdOK (ici libellé Go)

Protected Sub cmdOK_Click(ByVal sender As Object, ByVal e As System.EventArgs)
 Dim wsTemp As New AS400_Temperature.ConvertTemp
 Dim input As New AS400_Temperature.CONVERTTEMPInput

  If txtF.text <> "" Then
     input._TEMPIN = txtF.text
     lblC.Text = wsTemp.converttemp_XML(input)
  End If
End Sub

Résultat

 

Enfin, en RPG :

1/ 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)

2 / il faut générer le "stub" soit le programme "proxy" faisant l'interface entre Axis et notre RPG.

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.
$

Si vous passez la commande ls, vous devez voir :

$
> ls /myconverttemp
ConvertTempPortType.c CONVERTTEMPInput.c CONVERTTEMPResult.c
ConvertTempPortType.h CONVERTTEMPInput.h CONVERTTEMPResult.h
$

L'utilisation de ces sources C en RPG était assez complexe.


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 trouve 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
   http://as400:10041/web/services/ConvertTempService/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 -s 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 service (Avant ConvertTempPortType, maintenant ConvertTempServices)

ConvertTempServices.CL le CL de création du *SRVPGM
ConvertTempServices.rpgleinc fichier à inclure (dans votre programme)
ConvertTempServices.rpgle le code d'invoquation du web service (*SRVPGM)
ConvertTempServices_util.rpgleinc fichier à inclure (dans le source suivant)
ConvertTempServices_util.rpgle divers utilitaires
ConvertTempServices__xsdtypes.rpgleinc différents types de données standards

le fichier de référence est le xxxxxxxx.Services.rpgleinc (ConvertTempServices.rpgleinc)
où xxxxxxxx représentant le nom du service tel que défini dans "http://AS400S:10030/web/services/xxxxxxxx?wsdl"

qui contient les définitions dont vous avez besoin, et qu'il faut inclure dans votre code :

 

Pour faire en RPG l'équivalent du test suivant (sur ConvertTemp) :


Ecrivez



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

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)

  1. Allez chercher le certificat sur le serveur concerné
  2. Installez le certificat sous Digital Certificat Manager
  3. Dans votre code, utilisez l'API axiscStubSetSecure(), après avoir ajouté le /copy
  4. vous pouvez aussi utiliser le 9ème paramètre à "true" avec les PTF HTTP, level 46 (7.1) , 20 (7.2) et 7 (7.3)
  /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 + OK certificat absent

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

 

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;

RPG toujours, pour les web services REST, IBM propose (Mai 2016) d'utiliser directement les API Axis (alternative aux fonctions httpgetblob/clob)


il vous faut :

7.3: SI60805, SI60808
7.2: SI60806, SI60809
7.1: SI60807, SI60810

Avec,

7.3 : SI63730, SI63759
7.2 : SI63729, SI63760
7.1 : SI63727, SI63761

Exemple général

**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

 



Voyez nos différentes solutions pour lire du JSON : http://www.volubis.fr/freeware/READJSON.html


Si vous préférez utiliser SQL, ce dernier propose une consommation de web services (plutôt Rest) via des fonctions dans SYSTOOLS

Le but de ces fonctions est de consommer des services web plutôt orientés REST, revenant aux fondamentaux du protocole HTTP


Regardons à travers des exemples

Values SYSTOOLS.HTTPGETCLOB('http://www.volubis.fr' ,'') ;


Récupère dans une variable le contenu de notre page d'accueil




Pour les fonctions HTTPPOSTBLOB|CLOB et HTTPPUTBLOB|CLOB, il y un troisième paramètre: les données à transmettre
(avec GET les paramètres sont dans l'URL)

      

Pour une page web "classique" , par formulaire

->



Voyez cet extrait de code

(pensez simplement à indiquer le type de contenu formulaire : "x-www-form-urlencoded" pour simuler un formulaire)

-- Appel d'une page PHP (normalement un formulaire avec "prenom")
Values SYSTOOLS.HTTPPOSTCLOB('http://as400/php/exemples/tp/tp0.php' ,
CAST ('<httpHeader>
<header name="Content-Type" value="application/x-www-form-urlencoded"/>
</httpHeader>' AS CLOB(1K)),
CAST('prenom=christian' AS CLOB(10K)) )

 

Si le site retourne du XML, l'utilisation de la fonction XMLTABLE permettra de ne recevoir que les données utiles


Sur la base d'un web service ayant cette enveloppe SOAP

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://soapprd.wsbeans.iseries/">
  <soapenv:Header/>
     <soapenv:Body>
       <soap:getprd>
          <arg0>
                 <CODE>2</CODE>
          </arg0>
       </soap:getprd>
     </soapenv:Body>
</soapenv:Envelope>

ET retournant celle ci

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <ns2:getprdResponse xmlns:ns2="http://soapprd.wsbeans.iseries/">
      <return>
        <RETOUR>
           <PR_CODE>2</PR_CODE>
           <PR_NOM>Château Maucaillou</PR_NOM>
           <PR_ADRESSE>Quartier de la Gare</PR_ADRESSE>
           <PR_CDPST>33480</PR_CDPST>
           <PR_COMMUNE>Moulis-en-Médoc</PR_COMMUNE>
           <PR_TEL>05 56 58 01 23</PR_TEL>
           <PR_FAX>05 56 58 00 88</PR_FAX>
           <PR_VENTE>oui</PR_VENTE>
           <PR_VISITE>oui</PR_VISITE>
           <APPEL_CODE>182</APPEL_CODE>
         </RETOUR>
      </return>
    </ns2:getprdResponse>
  </soap:Body>
</soap:Envelope>



SELECT*
FROM XMLTABLE('$result/*:Envelope/*:Body/*:getprdResponse/*:return'
PASSING XMLPARSE(
DOCUMENT
SYSTOOLS.HTTPPOSTCLOB('http://as400:10025/web/services/SOAPPRDService/SOAPPRD', NULL,
CAST('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:soap="http://soapprd.wsbeans.iseries/">
<soapenv:Header/>
<soapenv:Body>
<soap:getprd>
<arg0>
<CODE>2</CODE>
</arg0>
</soap:getprd>
</soapenv:Body>
</soapenv:Envelope>' AS CLOB(10K)) )
) as "result"
COLUMNS
NOM CHAR(30) PATH '*:RETOUR/*:PR_NOM',
VILLE CHAR(50) PATH ' *:RETOUR/*:PR_COMMUNE',
TEL CHAR(20) PATH ' *:RETOUR/*:PR_TEL'
) AS TABLEXML;



Sur la base d'un service ( http://www.webservicex.net/stockquote.asmx?WSDL) plus complexe :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET/">
  <soapenv:Header/>
    <soapenv:Body>
       <web:GetQuote>
           <web:symbol>IBM</web:symbol>
      </web:GetQuote>
  </soapenv:Body>
</soapenv:Envelope>

Appel d'un Web service, utilisation du deuxième paramètre permettant de fournir les entêtes http,
le troisième contenant la demande(body), soit l'enveloppe SOAP.
(ici, nous demandons la valeur de l'action IBM à aujourd'hui dans une enveloppe SOAP)


-- Appel d'un web service , récupération de l'enveloppe SOAP réponse dans une variable
VALUES SYSTOOLS.HTTPPOSTCLOB('http://www.webservicex.net//stockquote.asmx',
CAST ('<httpHeader>
<header name="Content-Type" value="text/xml;charset=utf-8"/>
<header name="SOAPAction" value="&quot;http://www.webserviceX.NET/GetQuote&quot;"/>
</httpHeader>' AS CLOB(1K)),
CAST('<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetQuote xmlns="http://www.webserviceX.NET/">
<symbol>IBM</symbol>
</GetQuote>
</soap:Body>
</soap:Envelope>' AS CLOB(10K)) ) ;

SoapUI nous montre l'enveloppe Soap en sortie, comme ceci :

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <soap:Body>
  <GetQuoteResponse xmlns="http://www.webserviceX.NET/">
   <GetQuoteResult>

    <![CDATA[
      <StockQuotes><Stock> <Symbol>IBM</Symbol><Last>182.46</Last><Date>11/14/2013</Date>
      <Time>12:08pm</Time><Change>-1.09</Change><Open>180.63</Open><High>182.90</High><Low>179.66</Low>
     <Volume>3474990</Volume><MktCap>198.1B</MktCap><PreviousClose>183.55</PreviousClose>
     <PercentageChange>-0.59%</PercentageChange><AnnRange>172.57 - 215.90</AnnRange><Earns>14.439</Earns>
    <P-E>12.71</P-E><Name>International Bus</Name></Stock></StockQuotes>
    ]]>

   </GetQuoteResult>
  </GetQuoteResponse>
 </soap:Body>
</soap:Envelope>

-- Appel d'un web service , récupération de l'enveloppe SOAP, "parsée"
-- il y a des espaces de nommage (xmlns) SOAP et d'autres propres au web service, d'où -> *:
-- les données extraites sont elle-même au format XML (on voit que l'action est à 210 $ 55 )
SELECT*
FROM XMLTABLE('$result/*:Envelope/*:Body/*:GetQuoteResponse'
PASSING XMLPARSE(
DOCUMENT
SYSTOOLS.HTTPPOSTCLOB('http://www.webservicex.net//stockquote.asmx',
CAST ('<httpHeader>
<header name="Content-Type" value="text/xml;charset=utf-8"/>
<header name="SOAPAction" value="&quot;http://www.webserviceX.NET/GetQuote&quot;"/>
</httpHeader>' AS CLOB(1K)),
CAST('<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetQuote xmlns="http://www.webserviceX.NET/">
<symbol>IBM</symbol>
</GetQuote>
</soap:Body>
</soap:Envelope>' AS CLOB(10K)) )
) as "result"
COLUMNS
resultat VARCHAR(2000) PATH '*:GetQuoteResult'
) AS TABLEXML;
-- Appel d'un web service , récupération de l'enveloppe SOAP, "parsée" pour lire le montant de l'action
-- puis découpage du XML extrait (présent dans CDATA[ ] ) à nouveau par la fonction XMLTABLE
<![CDATA[
         <StockQuotes>
           <Stock><Symbol>IBM</Symbol><Last>182.46</Last><Date>11/14/2013</Date>
       <Time>12:08pm</Time><Change>-1.09</Change><Open>180.63</Open><High>182.90</High><Low>179.66</Low>
      <Volume>3474990</Volume><MktCap>198.1B</MktCap><PreviousClose>183.55</PreviousClose>
      <PercentageChange>-0.59%</PercentageChange><AnnRange>172.57 - 215.90</AnnRange><Earns>14.439</Earns>
     <P-E>12.71</P-E><Name>International Bus</Name></Stock>
</StockQuotes>
]]>
WITH temp as (SELECT resultat
FROM XMLTABLE('$result/*:Envelope/*:Body/*:GetQuoteResponse'
PASSING XMLPARSE(
DOCUMENT
SYSTOOLS.HTTPPOSTCLOB('http://www.webservicex.net//stockquote.asmx',
CAST ('<httpHeader>
<header name="Content-Type" value="text/xml;charset=utf-8"/>
<header name="SOAPAction" value="&quot;http://www.webserviceX.NET/GetQuote&quot;"/>
</httpHeader>' AS CLOB(1K)),
CAST('<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetQuote xmlns="http://www.webserviceX.NET/">
<symbol>IBM</symbol>
</GetQuote>
</soap:Body>
</soap:Envelope>' AS CLOB(10K)) )
) as "result"
COLUMNS
resultat VARCHAR(2000) PATH '*:GetQuoteResult'
) AS TABLEXML
)
select * from temp, 
XMLTABLE ('$c/StockQuotes/Stock' passing XMLPARSE(DOCUMENT RESULTAT) as "c"
COLUMNS
symbol CHAR(30) PATH 'Symbol',
prix dec(11, 2 ) PATH 'Last'
) AS X ;



Pour un service web REST retournant du XML, c'est plus simple


conjuguons à nouveau HTTPGETBLOB et XMLTABLE

SELECT*
FROM XMLTABLE('$result/lstprodResult/RETOUR'
PASSING XMLPARSE(
DOCUMENT
SYSTOOLS.HTTPGETBLOB('http://as400:10042/web/services/LSTPRODR/suivant/25', '')
) as "result"
COLUMNS 
nom VARCHAR(50) PATH 'PR_NOM' ,
tel varchar(20) PATH 'PR_TEL',
nbvins dec(3, 0) PATH'NBVIN',
cepage char(20) PATH 'CEPAGE'
) AS TABLEXML;

Si le service retourne du JSON


EN PHP




Résultat

AVANT TR1(7.3)/TR5(7.2), voyez l'utilitaire XML2JSON / JSON2XML

(http://www.mcpressonline.com/programming/techtip-json-and-xml-conversion-in-db2-for-i.html)



Depuis TR1 (7.3) TR5(7.2) une fonction JSON_TABLE est intégrée à SQL

JSON_TABLE(
JSON_SOURCE
JSON_PATH

COLUMNS
nom type PATH 'json_path',
...
) as X

    (le deuxième caractère, optionnel est un code page) 



httpGetBlobVerbose
httpGetClobVerbose
httpPutBlobVerbose
httpPutClobVerbose
httpPostBlobVerbose
httpPostClobVerbose
httpDeleteBlobVerbose
httpDeleteClobVerbose
httpBlobVerbose
httpClobVerbose
httpHeadVerbose


qui s'utilisent comme ça

with temp as (
select responsemsg as msg , responsehttpheader as header
from table( systools.httpgetclobverbose('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml' ,'')) as E)
select code, monnaie, taux from temp CROSS JOIN 

xmltable('$r/httpHeader' passing xmlparse(DOCUMENT header) as "r"
COLUMNS
code char(25) PATH '@responseCode',
message char(25) PATH 'responseMessage'
) as x
CROSS JOIN
xmltable('$m/*:Envelope/*:Cube/*:Cube/*:Cube' passing xmlparse(DOCUMENT msg) as "m"
COLUMNS
monnaie char(3) PATH '@currency',
taux dec(11, 7) PATH '@rate'
) as y


SI vous faites du https,

certains site imposent une version de SSL (Erreur : Received fatal alert: handshake_failure)

Créez la fonction suivante :

CREATE FUNCTION SYSTOOLS.setProperty(PROPERTY VARCHAR(80), VALUE VARCHAR(80))
RETURNS VARCHAR(80)
LANGUAGE JAVA
PARAMETER STYLE JAVA
EXTERNAL NAME 'java.lang.System.setProperty'

saisissez
VALUES SYSTOOLS.setproperty('com.ibm.jsse2.overrideDefaultProtocol','TLSv12')

Les certificats sont enregistrés dans un magasin de certificats (keystore)


le magasin pour java, par défaut, est lié à la JVM :

/QOpenSys/QIBM/ProdData/JavaVM/jdk70/32bit/jre/lib/security/cacerts par exemple

pour être certain, retrouver votre job par WRKJVMJOB (option 5)
puis 2. Display environment variables et cherchez JAVA_HOME


par exemple le site de la métropole de Nantes provoque SQL4302, certificat not trusted


regardons le détail pour ce certificat





affichez le certificat pour l'authorité de certification DST Root CA X3

Sauvegardez le au format DER, transferez le sur l'IBM i


il faut ensuite l'importer par keytool -import

saisissez le mot de passe du magasin (le mot de passe est normalement "changeit"), et acceptez par oui

ainsi que le certificat intermédiaire


Vérifions par keytool -list




pour ces dernières options, concernant l'accès HTTPS, voyez aussi notre cours SSL

Vous pouvez mettre des options à java, en créant un fichier d'options

-Xmx Mémoire pour java (par exemple -Xmx2g -> 2 Go)
http.proxyHost Coordonnées du Proxy
http.proxyPort port du proxy (80 par défaut)
http.proxyUser Utilisateur pour proxy
http.proxyPassword Mot de passe pour proxy
http.nonProxyHosts Liste des serveurs pour lesquels ne pas utiliser le proxy
javax.net.ssl.trustStore emplacement du fichier contenant la liste des certificats des sites de confiance
javax.net.ssl.trustStorePassword mot de passe pour ouvrir le fichier trustStore
javax.net.ssl.keyStore emplacement du fichier contenant la liste des certificats et des clés privées (keystore)
javax.net.ssl.keyStorePassword mot de passe pour ouvrir le fichier keyStore


Le fichier de propriétés java peut être indiqué comme suit :

  1. en créant une variable d'environnement indiquant sa localisation
    ADDENVVAR ENVVAR(QIBM_JAVA_PROPERTIES_FILE)
    VALUE(/QIBM/userdata/java400/mySystem.properties)
  2. en créant un fichier SystemDefault.properties dans la home directory de l'utilisateur
  3. en créant un fichier SystemDefault.properties dans /QIBM/userdata/java400/

 

Copyright © 2017 VOLUBIS