, Les programmes de contrôle de validité sur IBM i

Il est possible d’effectuer un contrôle sur les paramètres passés dans une commande avant que le programme de traitement ne soit exécuté et d’envoyer un message de diagnostic au sein même de la commande en cas d’erreur.

Documentation IBM sur le sujet : https://www.ibm.com/docs/fr/i/7.5?topic=commands-validity-checking-program-cl-command

Introduction

Pour ajouter des contrôles sur les paramètres d’une commande (en plus des contrôles inclus dans celle-ci), on peut lui affecter un programme de contrôle de validité créé en amont.

Ce programme recevra tous les paramètres de la commande et on pourra y réaliser divers contrôles/tests avant l’exécution du programme de traitement. Il permet également d’envoyer des messages de diagnostic pour que l’utilisateur puisse ajuster la saisie de ses paramètres.

Pour assigner le programme de contrôle de validité à la commande, on indique son nom dans le paramètre VLDCKR de la commande CRTCMD (lors de la compilation de la commande).

Cas d’exemple

Prenons le cas où nous souhaitons créer une commande simple qui permettrait de récupérer une extraction CSV des ventes réalisées par un utilisateur sur une année donnée.

On souhaitera donc vérifier deux choses :

  • L’utilisateur doit exister sur la machine
  • L’année choisie doit être comprise dans une période de 10 ans avant l’année en cours

On commence donc par créer la commande GETUSRVEN qui recevra ces deux paramètres :

Une fois la commande prête on peut préparer le programme de contrôle de validité.
Pour cet exemple on créera un programme VGETUSRVEN (CLLE) :

Dans ce programme, on récupère les différents paramètres de la commande GETUSRVEN et la date actuelle en décimal.

On procède ensuite aux contrôles :

  • De l’utilisateur

Ici on utilise une suite de requêtes SQL pour vérifier que l’utilisateur existe sur la machine.

En cas d’absence d’utilisateur correspondant au paramètre de notre commande, on utilise la commande SNDPGMMSG (MSGTYPE *DIAG) avec le code message CPD0006 (conçu pour être utilisé dans des programmes de contrôle de validité).

On peut indiquer le message de notre choix dans le paramètre MSGDATA, mais attention, les quatre premiers caractères étant réservés il faut commencer son message par ‘0000’.

Une fois le message de diagnostic indiqué on réutilise la commande SNDPGMMSG (MSGTYPE *ESCAPE) avec le code message CPF0002 ce qui permettra d’indiquer à l’appelant que des erreurs ont été trouvées et de suspendre l’exécution de la commande.

  • De l’année choisie

On applique ici la même méthode que précédemment, en vérifiant que l’année n’est pas antérieure de 10 ans par rapport à l’année en cours, et qu’elle n’est pas supérieure.

On peut maintenant compiler le programme VGETUSRVEN (commande CRTBNDCL).

Enfin on compile la commande GETUSRVEN en spécifiant VGETUSRVEN dans le paramètre VLDCKR de la commande CRTCMD.

On peut maintenant essayer la commande, et constater les messages de diagnostic en cas de mauvaise saisie :

Il est également possible de voir quel programme de contrôle de validité est utilisé pour une commande (s’il y en a un) avec la commande DSPCMD CMD(nom de la commande) :

, , , SQL – appel de webservice

Depuis la V7R1 (SF99701 – DB2 – niveau 23), on peut invoquer des web service via SQL. Les fonctions se trouvent dans SYSTOOLS.

En V7R4 TR5, sont sorties de nouvelles fonctions, elles se trouvent dans QSYS2.

Outre les fonctions HTTP, celles pour encoder / décoder en base64 et pour encoder / décoder L’URL, ont aussi été implémentées dans QSYS2.

Rappel des différences entre ces fonctions

Tout d’abord les performances. Les fonctions de QSYS2 permettent un gain non négligeable, elles sont basé sur les fonctions AXIS en C natif, contrairement à celles de SYSTOOLS qui sont basées sur des classes java.

Les paramètres dans l’entête ou le corps du message sont transmis en JSON pour les fonctions de QSYS2, à la place de XML pour celle de SYSTOOLS.

La gestion des certificats est simplifiée par l’utilisation de DCM, alors qu’avec les fonctions de SYSTOOLS, il fallait pousser le certificat dans le magasin du runtime java utilisé par les fonctions HTTP. En cas de multiple versions de java installées, il fallait s’assurer de laquelle servait pour les fonctions HTTP. L’ajout du certificat, se faisait via des commandes shell.

Les types et tailles des paramètres des fonctions ont été adaptés pour ne plus être des facteurs limitants de l’utilisation des fonctions SQL, voici quelques exemples :

Certaines utilisations ont aussi été simplifiées en automatisant des tâches.

Prenons l’exemple d’un appel à un web service avec une authentification basique. Le couple profil / mot de passe doit être séparé par « : » et l’ensemble encoder en base64. C’est la norme HTTP.

Dans le cas des fonctions de SYSTOOLS, il fallait effectuer l’ensemble des opérations, alors qu’avec les fonctions de QSYS2, il suffit de passer le profil et le mot de passe dans la propriété BasicAuth. La mise en forme et l’encodage étant faits directement par les fonctions AXIS :

Il y a par contre un cas limitatif des fonctions QSYS2, que IBM a rajouté, alors que la norme HTTP autorise ce type d’appel.

Il s’agit d’avoir une authentification basique sur un appel en http.

Ce cas n’est pas trop contraignant, aujourd’hui le https est la norme et le http quasiment disparu…. quasiment !
Nous rencontrons encore chez nos clients des web services « interne » en http. La migration en https n’étant pas vendeur auprès des directions qui n’y voit aucun gain pour le métier. C’est l’éternel problème des changements structurels en IT.

Dans ces cas, la fonction de QSYS2, renverra une erreur, assez claire !

Le premier réflexe est de voir avec le fournisseur du service s’il ne dispose pas d’une version en https.

Maintenant, si vous n’avez pas d’autre choix que d’appeler un web service en http avec authentification basique, il faudra continuer d’utiliser les fonctions de SYSTOOLS. Dans tous les autres cas, aucune hésitation, utilisez les fonctions de QSYS2.

Mais mettons nous d’accord, de l’authentification basique en http, ce n’est pas de la sécurité, c’est une absurdité.

En http, le message passe en clair sur la trame réseau, avec votre profil / mot de passe, encodé en base 64, et non encrypté, donc en clair eux aussi.

Edit : Précision apportée par Gautier Dumas de CFD-innovation. Merci à lui.
On peut contourner le problème avec les fonctions de QSYS2. Il ne faut pas utiliser la propriété BASICAUTH, mais construire l’authentification basique comme on le faisait avec celle de SYSTOOLS.
VALUES QSYS2.HTTP_GET(
‘http://hostname/wscommon/api/contacts’,
‘{« header »: »Authorization, BASIC dGVzdHVzZXI6dGVzdHB3ZA== »}’);
Il n’y a donc vraiment plus de raison de continuer avec les fonctions de SYSTOOLS !

Pour se repérer dans un écran DSPF

Vous voulez savoir ou vous êtes positionné dans votre écran , pour appeler un programme liste par exemple.

Vous avez plusieurs solutions on va en présenter 4 ici

1) INFDS sur le fichier écran (DSPF)


Permet d’avoir la ligne et la position du curseur sur votre écran
dans votre programme
Dcl-F votre-ecran WORKSTN INFDS(FICHIERDS)

dcl-ds fichierDS;
ligne INT(3) POS(370); // curseur : ligne
colonne INT(3) POS(371); // curseur : colonne
end-ds;
..
if ligne = 4 and colonne = 22;

endif;

Avantage, tout ce passe dans le programme rien à faire dans l’écran

Nous vous conseillons d’utiliser un include pour normaliser l’utilisation de cette data structure

2) Nom de la zone active


dans votre écran
A RTNCSRLOC(&W_FMT &W_ZON)
A CF04(04)
A CA12(12)
A CF10(10)
A W_FMT 10A H TEXT(‘Nom du format’)
A W_ZON 10A H TEXT(‘Nom de la Zone’)
dans votre programme

if W_FMT = ‘FMT01’ and C1 = W_ZON = ‘NUMCLI’;

endif;

Avantage, vous avez directement le nom de la zone dans la quelle vous vous trouvez

3) Positionnement du curseur sur souris

Vous devez déclarer dans les dspf les zones
qui contiendront les informations
dans votre écran

A RTNCSRLOC(MOUSE &L1 &C1 &L2 &C2) A RÉCUPÉRATION DU CURSEUR
A L1 3S 0H
A C1 3S 0H
A L2 3S 0H
A C2 3S 0H
dans votre programme
if C1 = 4 and C1 = 22;

endif;

Avantage, Vous avez un exemple ici https://www.gaia.fr/utilisation-de-la-souris-dans-un-dspf/

c’est la seule solution pour gérer la souris

4) Divers sur sous fichier

Il y a un mot clé méconnu qui permet de connaitre le rang du SFL sans faire de readc
dans l’écran
A SFLCSRRRN(&R1))
A* RÉCUPÉRATION DU CURSEUR
A R1 3S 0H
dans votre programme
R1 CHAIN SFL01 ;

Avantage , sur les sélections simples c’est une alternative au readc

Remarque :

Vous avez sans doute d’autres solutions, mais celles ci sont simples et efficaces
Vous avez des mots clés pour les zones liés au aide, qui ne sont pas traités ici,
regardez plutôt la, https://www.gaia.fr/ajouter-de-laide-a-vos-dspf/

Merci à Fawzia pour son aide

, , Générer un XLS avec SQL

La TR 3 de la V7R5 nous apporte un nouveau service qui va permettre de générer un fichier XLS à partir d’une requête SQL

Exemple :

VALUES SYSTOOLS.GENERATE_SPREADSHEET(
PATH_NAME => ‘LST_option.xls’,
SPREADSHEET_QUERY => ‘Select * from qgpl.qauoopt’ ,
COLUMN_HEADINGS => ‘COLUMN’ ,
SPREADSHEET_TYPE => ‘xlsx’)

Remarque:

ACS doit être installé sur votre partition et si possible à jour

Attention par défaut il génère du csv

Diminuer les indicateurs dans vos RPGLE

Pour les nouveaux développeur sur l’IBMi l’utilisation des indicateurs n’est pas naturel, voici comment on peut les diminuer


1) En utilisant l’INFDS pour tester les touches de fonction

2) En utilisant une zone attribut pour les DSPATR

Attention vous ne pourrez pas tous les remplacer


https://www.ibm.com/docs/fr/i/7.5?topic=80-dspatr-display-attribute-keyword-display-files

Voici un exemple

DDS

     A*                                                              
     A                                      DSPSIZ(24 80 *DS3)             
     A                                      CA03                           
     A          R FMT01                                                    
     A*        
     A                                      OVERLAY                        
     A                                  1 28'Test TOUCHES INFDS/ ATTRIBUT' 
     A                                  3  2'Text'                         
     A            ZONE          12A  B  3  9DSPATR(&ATTRIB)                
     A            ATTRIB         1A  P                                     
     A                                 22  3'F3=Exit'                      

RPGLE

**free                                 
// Exemple d'utilisation d'un écran    
// Sans indicateurs                    
//                                     
Dcl-F TOUCHE WORKSTN INFDS(FICHIERDS) ;
/INCLUDE INFDS_INC                     
/INCLUDE TOUCHE_INC                    
/INCLUDE ATTR_INC                      
// initialisation des attributs        
       Zone = 'Welcome';               
       ATTRIB  = P_HI;                 
// Boucle su F3                        
   DOU Touche_Ecran = F3 ;             
       Exfmt FMT01 ;                   
   ENDDO ;                             
//                                     
   *inlr = *on ;                   

Remarque :

Vous retrouverez les inculde ici

https://github.com/Plberthoin/PLB/tree/master/INCLUDE

Réaffichage automatique d’un DSPF

Vous avez besoin d’avoir un écran qui se met à jour automatiquement voici un exemple qui fait ca.

Cette une barre d’avancement qui rafraichit également l’heure affichée.

DSPF

     A                                      DSPSIZ(24 80 *DS3)         
     A                                      CA03(03)                   
     A* Test écran en réaffichage auto                                 
     A*                                                                
     A          R FMT01                                                
     A*%%TS  SD  20231026  124638  PLB         REL-V7R4M0  5770-WDS    
     A                                      PUTOVR                     
     A                                      OVRDTA                     
     A                                      OVRATR                     
     A                                  5 27'Barre d''avancement'      
     A                                      DSPATR(HI)                 
     A            TEXTE         50A  O 11 15                           
     A                                 22  4'F3=Exit'                  
     A            STATUS        15A  O  9 27                           

CLLE

/* Ecran en mise à jour automatique   */                                 
PGM                                                                
DCLF reaf                                                          
dcl &i *int                                                        
dcl &wtime *char 6                                                 
             chgvar &lancer 'Appuyez sur <ENTER> pour démarrer'    
             chgvar &status 'Arrêté '                              
             rtvsysval qtime &wtime                                
             chgvar &time (%sst(&wtime 1 2) *tcat ':' *tcat +      
                           %sst(&wtime 3 2) *tcat ':' *tcat +      
                           %sst(&wtime 5 2))                       
             SNDRCVF    RCDFMT(FMT01) WAIT(*YES)                   
             DOUNTIL    COND(&IN03)                                
             if cond(&in03) then(leave)                            
             chgvar &lancer ' '                                    
             chgvar &status 'Démarré'                              
             DOFOR      VAR(&I) FROM(1) TO(50)                     
             DLYJOB     DLY(1)                                     
             rtvsysval qtime &wtime                                
             chgvar &time (%sst(&wtime 1 2) *tcat ':' *tcat + 
                           %sst(&wtime 3 2) *tcat ':' *tcat + 
                           %sst(&wtime 5 2))                  
             chgvar &texte (&texte *tcat '>')                 
             SNDRCVF    RCDFMT(FMT01) WAIT(*NO)               
             enddo                                            
             chgvar &texte ('Chargé        ')                 
             SNDRCVF    RCDFMT(FMT01) WAIT(*NO)               
             DLYJOB     DLY(2)                                
             chgvar &in03  '1'                                
             enddo                                            
ENDPGM                                                        

Remarque :

Votre écran doit être compiler avec l’option DFRWRT(*NO)

, Utilisation de la souris dans un DSPF

Vous voulez utiliser la souris dans un dspf sur dans un de vos programmes
voici un exemple en CLLE:

DSPF :

A                                      DSPSIZ(24 80 *DS3)               
A                                      CA03(03)                         
A* EVENNEMENT SOURIS                                                    
A*          UNSHIFT  / LEFT / PRESS                                     
A          R FMT01                                                      
A*%%TS  SD  20231025  171347  QSECOFR     REL-V7R4M0  5770-WDS          
A                                      MOUBTN(*ULP ENTER)               
A                                      RTNCSRLOC(*MOUSE &L1 &C1 &L2 &C2)
A* RÉCUPÉRATION DU CURSEUR                                              
A            L1             3S 0H                                       
A            C1             3S 0H                                       
A            L2             3S 0H                                       
A            C2             3S 0H                                       
A                                  3 13'Tester la position de la souris'
A                                  5 13'En faisant un clic Gauche.'     
A*  BOUTON BAS DE PAGE                                                  
A            F1B            2Y 0B 23  2PSHBTNFLD                        
A                                      PSHBTNCHC(1 'F3=>Exit' CA03)

CLLE

pgm                                                               
dclf mouse                                                        
             DOUNTIL    COND(&IN03)                               
             SNDRCVF    RCDFMT(FMT01)                             
             if cond(*not &in03) then(do)                         
             SNDUSRMSG  MSG('Position du curseur ligne =' *BCAT + 
                          %CHAR(&L1) *BCAT 'et colonne =' *BCAT + 
                          %CHAR(&C1)) MSGTYPE(*INFO)              
             enddo                                                
             ENDDO                                                
endpgm                                                            

Remarque:

Vous devez compiler avec l’option ENHDSP(*YES)

Utiliser un menu barre dans vos DSPF

C’est la possibilité d’avoir un menu déroulant dans vos DSPF avec plusieurs onglets et de choisir une option, exactement comme dans windows.

Ci dessous un exemple avec son programme 2 menus déroulants ici PULLA et PULLB

DSPF

     A* Exemple de menu barre 
     A                                      DSPSIZ(27 132 *DS4)
     A                                      MNUCNL(CA12)
     A                                      CA03(03 'EXIT')
     A          R MB                        MNUBAR
     A            MNUFLD         2Y 0B  1  2
     A                                      MNUBARCHC(1 PULLA    +
     A                                                '>Pulla')
     A                                      MNUBARCHC(2 PULLB    +
     A                                                '>Pullb')
     A                                      MNUBARSEP(             +
     A                                             (*CHAR '_'))
     A
     A          R RECORD
     A*%%TS  SD  20231025  122354  PLB         REL-V7R4M0  5770-WDS
     A                                      MNUBARDSP(MB &MNUCHC &PULL)
     A                                 11  2'Nom      :'
     A            ZONE1         30A  B 11 14
     A                                 12  2'Prénom   :'
     A            ZONE2         20A  B 12 14
     A            MNUCHC         2Y 0H
     A            PULL           2S 0H
     A                                 13  2'Sexe     :'
     A            F1S            2Y 0B 13 14SNGCHCFLD(*AUTOSLT (*NUMCOL 3))
     A                                      CHOICE(1 '>Homme  ')
     A                                      CHOICE(2 '>Femme  ')
     A                                      CHOICE(3 '>Inconnu')
     A                                 14  2'Langue(s):'
     A            F1M            2Y 0B 14 14MLTCHCFLD((*NUMCOL 4))
     A                                      CHOICE(1 '>Anglais')
     A                                      CHCCTL(1 &CHOIX1)
     A                                      CHOICE(2 '>Espagnol')
     A                                      CHCCTL(2 &CHOIX2)
     A                                      CHOICE(3 'Alleman>d')
     A                                      CHCCTL(3 &CHOIX3)
     A                                      CHOICE(4 '>Italien ')
     A                                      CHCCTL(4 &CHOIX4)
     A*                                     CHOICE(5 'A>utre  ')
     A*                                     CHCCTL(5 &CHOIX5)
     A            CHOIX1         1Y 0H
     A            CHOIX2         1Y 0H
     A            CHOIX3         1Y 0H
     A            CHOIX4         1Y 0H
     A*           CHOIX5         1Y 0H
     A* Bas de page
     A            F1B            2Y 0B 23  2PSHBTNFLD
     A                                      PSHBTNCHC(1 'F3=>Exit' CA03)
     A                                      PSHBTNCHC(2 'E>nter')
     A                                  9  3'Renseignements'
     A          R PULLA                     PULLDOWN
     A            F1             2Y 0B  1 02SNGCHCFLD(*AUTOENT)
     A                                      CHOICE(1 '>UN ')
     A                                      CHCCTL(1 &C1)
     A                                      CHOICE(2 '>DEUX')
     A                                      CHCCTL(2 &C2)
     A                                      CHOICE(3 '>TROIS')
     A                                      CHCCTL(3 &C3)
     A            C1             1Y 0H
     A            C2             1Y 0H
     A            C3             1Y 0H
     A          R PULLB                     PULLDOWN
     A            F1             2Y 0B  1 02SNGCHCFLD
     A                                      CHOICE(1 '>UN')
     A                                      CHCCTL(1 &C21)
     A                                      CHOICE(2 '>DEUX')
     A                                      CHCCTL(2 &C22)
     A                                      CHOICE(3 '>TROIS')
     A                                      CHCCTL(3 &C23)
     A            C21            1Y 0H
     A            C22            1Y 0H
     A            C23            1Y 0H
     A

RPGLE

**FREE
// exemple de menu barre
Dcl-F MNUBAR         WORKSTN ;
       CLEAR RECORD ;
       DoW *IN03 = '0';
          Exfmt RECORD;
          If *IN03 = '0';
             If PULL > 0;
                Select ;
                When  PULL = 1;
                   DSPLY 'Un' ;
                When  PULL = 2;
                   DSPLY 'Deux' ;
                when  PULL = 3;
                   DSPLY 'Trois' ;
                Endsl;
             // ici traitement des zones du format
             EndIf;
          EndIf;
       EndDo;
       *INLR = *On;

Remarque :

Vous devez compiler avec l’option ENHDSP(*YES)

Pour la présentation, cet exemple comporte également
Un bouton poussoir pour les touches de fonctions
un exemple de case a cocher unique
un exemple de case à cocher multiple

Pour commencer c’est un peu compliqué, pour vous aider, vous pouvez utiliser notre générateur téléchargeable ici …

https://github.com/Plberthoin/PLB/tree/master/GENMNUBAR

Génère un menu barre (Source DDS et RPGLE) ci dessus le code RPGLE généré

Vous devez « juste » remplacer les dsply par vos actions …

, , Utiliser un SFL d’erreurs

C’est la possibilité d’avoir plusieurs messages d’erreur et de pouvoir paginer dessus

Vous pouvez programmer un sous fichier message, mais ca peut être un peu compliqué à réaliser.

Voici une solution simple, il suffit de mettre le mot clé ERRSFL au niveau fichier écran

Ci dessous un exemple avec son programme en CLLE

DSPF

     A* Exemple sous fichier d'erreurs
     A                                      DSPSIZ(24 80 *DS3)         
     A                                      ERRSFL                     
     A                                      CA03(03)                   
     A          R FMT01                                                
     A            ZONE1         10A  B 11 20                           
     A  41                                  ERRMSG('Erreur ZONE 1' 41) 
     A            ZONE2         10A  B 12 20                           
     A  42                                  ERRMSG('Erreur ZONE 2' 42) 
     A            ZONE3         10A  B 13 20                           
     A  43                                  ERRMSG('Erreur ZONE 3' 43) 
     A                                  6  8'Sous fichier d''erreur'   
     A                                      DSPATR(HI)                 
     A                                 11  8'Zone 1 :'                 
     A                                 12  8'Zone 2 :'                 
     A                                 13  8'Zone 3 :'                                                         

CLLE

/* Exemple sous fichier message d'erreur */       
PGM                                               
DCLF ERREUR                                       
dountil &in03                                     
             SNDRCVF    RCDFMT(FMT01)             
             IF         COND(*NOT &IN03) THEN(DO) 
 /* activation des indicateurs d'erreur */        
             CHGVAR &IN41 '1'                     
             CHGVAR &IN42 '1'                     
             CHGVAR &IN43 '1'                     
enddo                                             
enddo                                             
ENDPGM                                            

Remarque:

La seule limitation, c’est une seule erreur par zone, mais ca suffit dans 90 % des cas