Comment faire afficher un écran à un traitement batch ?

Les traitements 5250 sont faits pour tourner en interactif, mais pour différentes raisons vous pouvez vouloir les faire tourner en batch :

Pas de login
sécurisation pas de attn request
etc …

Voici un exemple, dans une société ou j’ai travaillé, les unités de productions pouvaient demander un mot de passe à l’astreinte, par exemple la nuit.

La solution la plus simple qu’on avait trouvée était de lui afficher un programme de changement sur son unité écran.

On lui demandait donc son profil utilisateur et son unité écran et on lançait le programme sur celle ci, il pouvait changer son mot de passe directement.

C’est cet exemple que j’ai simplifié qui est ci dessous

le DSPF source

                                                                 
     A                                      DSPSIZ(24 80 *DS3)             
     A                                      CA03(03)                       
     A                                      INDARA                         
     A          R FMT01                                                    
     A*%%TS  SD  20240527  074541  PLB         REL-V7R4M0  5770-WDS        
     A                                  4 20'Réinitialiser un mot de passe'
     A                                  7  2'Utilisateur         :'        
     A                                  8  2'Nouveau mot de passe  :'        
     A                                 22  1'F3=Exit'                      
     A            USER          10A  O  7 26                               
     A            PWD           32A  B  8 26CHECK(LC)                      
     A            DEV           10A  O  4 54                               
     A            TEXTE         30   O 14  3                               

Le CLP source

pgm  (&dev &user)                                                
/*----------------------------------------------------------*/   
/* Ce programme permet de faire afficher un écran en batch  */   
/* vous devez acquérir l'unité écran                         */   
/* pour réinitialiser un mot de passe                        */   
/* sbmjob cmd(call initpwdr (&dev &user) job(QPADEV0001)    */   
/*----------------------------------------------------------*/   
dcl &dev  *char 10                                               
dcl &user *char 10                                               
/* Contrôles existence                      */                   
             CHKOBJ     OBJ(&DEV) OBJTYPE(*DEVD)                 
             MONMSG     MSGID(CPF9801) EXEC(DO)                  
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) +           
                          MSGDTA('L''unité écran doit exister') +
                          MSGTYPE(*ESCAPE)                       
             enddo 
            ALCOBJ     OBJ((&DEV *DEVD *EXCLRD)) WAIT(0)       
            monmsg CPF1002  exec(do)                           
            SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) +          
                         MSGDTA('Impossible d''allouer l''unité +
                         écran doit exister') MSGTYPE(*ESCAPE) 
            enddo                                                                                            
             CHKOBJ     OBJ(&user) OBJTYPE(*usrprf)              
             MONMSG     MSGID(CPF9801) EXEC(DO)                  
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('Le +
                          profil utilisateur doit exister') +         
                          MSGTYPE(*ESCAPE)                            
             enddo                                                    
 /* Lancement du programme sur l'écran remote  */                      
             SBMJOB     CMD(CALL PGM(INITPWDR) PARM((&DEV) (&USER))) +
                          JOB(&DEV) JOBQ(QSYSNOMAX)  
             SNDPGMMSG  MSGID(CPF9898) MSGF(QCPFMSG) +          
                          MSGDTA('Travail, ' *bcat &dev *bcat + 
                          'démarré') MSGTYPE(*comp)                              
endpgm                                                                

Le CLP cible

pgm  (&dev &user)                                                
/*----------------------------------------------------------*/   
/* Ce programme réinitiliase  un mot  de passe              */   
/* Peut être envoyé sur un écran remote qui est sur la      */   
/* Mire                                                     */   
/*----------------------------------------------------------*/   
dcl &dev *char 10                                                
dclf initpwdr                                                    
monmsg cpf0000 exec(goto erreur)                                 
/* controles fait dans le programme appelant */                  
             OVRDSPF    FILE(INITPWDR) DEV(&DEV) OVRSCOPE(*JOB)  
          chgvar &pwd     'ici mot de passe'                     
             dountil &in03                                       
             SNDRCVF    RCDFMT(FMT01)                            
             if cond(*not &in03) then(do)                        
             if (&pwd *ne 'ici mot de passe') then(do)           
             CHGUSRPRF  USRPRF(&USER) PASSWORD(&PWD) PWDEXP(*YES)
             Chgvar &texte ('Mot de passe réinitialisé')         
             enddo                                               
             enddo                                                   
             enddo                                                   
/* fin traitement */                                                 
             DLTOVR     FILE(INITPWD) LVL(*JOB)                      
             MONMSG     MSGID(CPF0000)                               
return                                                               
erreur:                                                              
             SNDUSRMSG  MSG('Réinitialisation de mot de passe pour' +
                          *BCAT &USER *BCAT ', actuellement +        
                          impossible') MSGTYPE(*INFO)                
             MONMSG     MSGID(CPF0000)                               
endpgm                                                               

La seule spécificité est de choisir l’unité écran d’affichage, pour qu’elle soit éligible elle doit être à la mire de connexion.

La commande pour habiller

             CMD        PROMPT('Réinitialisation de PWD')           
             PARM       KWD(UNITE) TYPE(*NAME) LEN(10) MIN(1) +     
                          PROMPT('Unité écran')                     
             PARM       KWD(PROFIL) TYPE(*NAME) LEN(10) MIN(1) +    
                          PROMPT('Profil utilisateur')              

le lancement job source:

La saisie sur le job cible :

Sur un changement de mot de passe, il peut être important d’avoir un suivi ?

Bien sur, vous pouvez ajouter des contrôles …

Le job cible qui tourne en batch !

Donc pas de possibilité d’ATTN Request , et messages d’erreurs dans QSYSOPR

Remarques :

Vous pouvez choisir l’utilisateur de lancement, mais QSECOFR est interdit dans un SBMJOB
Simple mais efficace, mais difficilement généralisable, on doit avoir un OVRDBF par DSPF

Intéressant pour des demandes ponctuelles

Dans les CLP vous pouvez indiquer directement l’unité sur la commande SNDRCVF

, Mettre un délai sur un programme 5250

Vous avez tous des enregistrements qui restent verrouillés dans vos traitements 5250, par exemple parce que la personne à quitter son poste.

Vous voulez donc qu’au bout d’un certain temps, votre programme déverrouille l’enregistrement

Vous avez une première solution qui est système

Elle se base sur les valeurs systèmes

QINACTITV qui indique un délai en seconde
QINACTMSGQ ou vous indiquez:
Une MSGQ, un message CPI1126 sera envoyé, à vous de mettre en place un watcher qui analyse et traite ces messages
*DSCJOB votre travail sera déconnecté et le système tentera de vous reconnecter (attention ca ne déverrouille pas toutes les ressources)
*ENDJOB votre travail sera arrêté, et donc tous sera libéré avec risques de déphasage dans votre base de données.

Mais vous pouvez être plus précis en le prévoyant dans les développements que vous ciblerez comme étant sensible, voici un exemple ci-dessous .

Notre exemple commenté

Dans le DSPF, vous devrez compiler votre écran avec un paramètre WAITRCD(délai en secondes), passer ce délai le système quittera le READ en attente.

Vous pouvez également indiquer ce paramètre temporairement par la commande OVRDSPF

Dans le programme RPGLE

Vous devrez indiquer l’option maxdev(*file) sur votre écran (c’est celle qui vous permet d’avoir plusieurs travails sur le même écran, pour faire une bataille navale par exemple)

Dans votre traitement vous ne pouvez pas utiliser l’instruction EXFMT (qui est un condensé d’un write et d’un read)

Vous devez explicitement indiquer les 2 instructions

WRITE du format ;
READ du fichier ;

Pour tester et savoir si vous avez dépassé le delai, vous pouvez tester la fonction %status qui vous renverra la valeur 01331 si vous avez débordé, vous pouvez également utiliser L’infds de votre écran.

Voici un exemple ou on a mis que ce qui est indispensable, à vous d’ajouter ce qui sera nécessaire à votre cas .

L’écran DSPF

A* OPTIONS DE COMPILE pour GDDS -------------------->          
A*<COMP>WAITRCD(60)</COMP>                                      
A* ------------------------------------------------->          
A*                                                         
A                                      DSPSIZ(24 80 *DS3)      
A                                      CA03(03)                
A                                      INDARA                  
A          R FMT01                                             
A* 
A                                      INVITE                  
A                                  5  3'Votre format de saisie'
A                                  7 12'Zone 1 :'              
A            ZONE1          4   B  7 23                        
A                                 22  2'F3=Exit'               

Dans notre exemple nous utilisons GDDS qui permet de mémoriser les options de compile pour les DSPF chez vous, vous devrez le mettre dans la commande de création de votre écran

==>CRTDSPF … WAITRCD(60) …

Le RPGLE

**free                                                    
// Ecran compiler avec WAITRCD(60)                          
dcl-f TESTDSPF workstn                                    
 maxdev(*file) ;                                          
 //                                                       
   dou     *in03        ;                                 
  // remplace un EXFMT insensible au Paramètre WAITRCD    
       write FMT01   ;                                    
       read(e) TESTDSPF ;                                 
  // 11331 indique que le temps est dépassé               
  select  ;                                               
  when  (%status  = 01331) ;                              
       dsply  'temps dépassé ...' ;                       
       *in03  = *on ;                                     
  // F3 activé                                            
  when *in03   ;                                          
       dsply  'sortie demandée .' ;                       
  // Touche entrée avec  lecture des zones                                      
  other    ;                                              
       dsply  'validation ok ...' ;
  endsl    ;                       
 enddo  ;                          
//                                 
*inlr = *on ;

Conclusion :

C’est simple et efficace et certains traitements devraient avoir cette option

Vous pouvez aussi utiliser facilement cette technique pour faire du rafraichissement auto, par exemple un tableau de bord toutes les 3 minutes …

Voir également cet exemple en CLP dans un article précédent ici : https://www.gaia.fr/reaffichage-automatique-dun-dspf/

, , , Convertir un SAVF en PF

il faut savoir qu’un fichier SAVF est un fichier PF de 528 de long.

Vous pouvez avoir besoin pour différentes raisons de convertir SAVF en PF pour manipuler plus simplement par SQL, pour contourner des restrictions d’utilisations etc ..

Vous trouverez ici 2 commandes qui vont vous permettent de réaliser cette opération : https://github.com/Plberthoin/PLB/tree/master/CPYSAVF

Copier un SAVF dans un PF

Voir le PF

Copier un PF dans un SAVF

Voir le Résultat

Pour voir ce résultat taper la commande DSPSAVF , Voir WRKSAVF si vous avez installez notre outil

Remarque :

Outil simple mais efficace qui peut rendre des services à des administrateurs

, , Plugin JCRCMDS pour RDI

Plugin open source peu connu de Craig Rutledge mais qui est bien utile pour convertir les spécifications H, F et D en RPG full free.

Il existe plusieurs outils pour convertir ces spécifications mais l’avantage de celui-ci est qu’on peut le faire directement dans RDI .

Lien pour le téléchargement :

https://sourceforge.net/projects/jcrcmds/

Installation

Extraire l’archive.

Comme pour le plugin isphere, il faut lancer RDI puis Aide > Installer un nouveau logiciel

Il suffit ensuite de sélectionner le dossier précédemment extrait.

Utilisation

1ère solution : Sélectionnez le code à convertir puis faites un clic droit JCRCMDS > convert selection(H,F,D).

Résultat :

2ème solution : Faites un clic droit directement dans le code puis JCRCMDS > Convert all(H,F,D)

Toutes les spécifications H, F ou D seront transformées.

, Utilisez un booléen dans une commande

Voici un exemple classique, vous devez définir dans vos commandes, un paramètre qui peut prendre comme valeur oui ou non par exemple

Généralement vous allez faire comme ceci

dans la commande

PARM KWD(CRTFILE) TYPE(CHAR) LEN(4) RSTD(YES) +
DFT(NO) VALUES(NO *YES) PROMPT('Création du +
fichier')


dans le programme

         PGM        PARM(.... &CRTFILE)
/* Paramètres */
//
DCL &CRTFILE *CHAR 4
//
IF COND(&CRTFILE = '*YES' ) THEN(DO)
//
ENDDO

Voici une solution en utilisant un booléen dans le programme

dans la commande

        PARM       KWD(CRTFILE) TYPE(*CHAR) LEN(4) RSTD(*YES) + 
                     DFT(*NO) VALUES(*NO *YES) SPCVAL(('*YES' + 
                     '1') ('*NO' '0')) PROMPT('Création du +    
                     fichier')                                  

dans le programme

         PGM        PARM(.... &CRTFILE)
/* Paramètres */
//
DCL &CRTFILE *LGL
//
IF COND(&CRTFILE) THEN(DO)
//
ENDDO

L’astuce consiste à indiquer une valeur à renvoyer dans la commande ici on se borne à ‘0’ et ‘1’ ce qui peut être interprété par votre programme comme un booléen

L’intérêt d’utiliser un booléen c’est d’avoir un code simplifier , un peu comme les indicateurs qui simplifient la lecture d’un code RPGLE ou CLLE

Vous voulez mettre à jour des informations dans une table sans faire de boucle de lecture ? Cet article est pour vous.

Prenons un exemple. Vous consommez un service web qui vous transmet une liste d’article que vous devez stocker en base de données.

L’ordre DB2 MERGE vous permettra d’ajouter les articles qui n’existent pas et de mettre à jour ceux qui existent.

Création de table ARTICLE

CREATE TABLE ARTICLE ( 
	CDART CHAR(10) CCSID 1147 DEFAULT ' ' , 
	DESART CHAR(30) CCSID 1147 DEFAULT ' ' )   
	  
	RCDFMT ARTICLE    ; 
  
LABEL ON TABLE ARTICLE 
	IS 'Base article' ; 
  
LABEL ON COLUMN ARTICLE 
( CDART IS 'Code article         ' , 
	DESART IS 'Désignation article  ' ) ;

Code RPG avec ajout ou mise à jour d’un article.

ctl-opt alwnull(*usrctl) option(*nodebugio:*srcstmt);

//Variables
dcl-s code_article        char(10);
dcl-s designation_article char(30);

exec sql SET OPTION commit = *none;

code_article        = 'AB123456';
designation_article = 'Ma désignation';

Exec Sql
   MERGE INTO ARTICLE as ARTICLE
   USING(VALUES (:code_article, :designation_article))
   AS SOURCE(CDART,DESART)
   ON ARTICLE.CDART = SOURCE.CDART
   -- Mise à jour de la désignation si code article trouvé
   WHEN MATCHED THEN UPDATE
         SET DESART  = SOURCE.DESART
   -- Ajout de l'article
   WHEN NOT MATCHED THEN INSERT VALUES (SOURCE.CDART,
                                        SOURCE.DESART)
   NOT ATOMIC CONTINUE ON SQLEXCEPTION;


*inLR=*ON;

Vous pouvez également supprimer l’article s’il est trouvé.

WHEN MATCHED THEN DELETE

On peut rajouter des conditions en plus du MATCHED. Dans la ligne ci-dessous je ne veux mettre à jour que l’article ‘TEST’. Pas grand intérêt mais c’était pour montrer un exemple.

WHEN MATCHED AND CDART='TEST' THEN UPDATE SET DESART  = SOURCE.DESART

Vous pouvez aussi tester la valeur pour la contrôler avant de faire la mise à jour.

WHEN MATCHED AND SOURCE.DESART IS NOT NULL THEN UPDATE SET DESART  = SOURCE.DESART

Il est également possible de prendre le résultat d’un select au lieu des deux variables

MERGE INTO ARTICLE as ARTICLE
   USING(VALUES (SELECT CDART, DESART FROM ARTICLE2))
   AS SOURCE(CDART,DESART)
   ON ARTICLE.CDART = SOURCE.CDART
   -- Mise à jour de la désignation si code article trouvé
   WHEN MATCHED THEN UPDATE
         SET DESART  = SOURCE.DESART
   -- Ajout de l'article
   WHEN NOT MATCHED THEN INSERT VALUES (SOURCE.CDART,
                                        SOURCE.DESART)
   NOT ATOMIC CONTINUE ON SQLEXCEPTION;

Je ne l’ai pas dit au début de l’article mais ça fonctionne aussi sur les PF.

, Plugin Isphere pour RDI

Isphere est un plugin open-source qui vous apportera quelques fonctionnalités intéressantes. Vous pourrez le télécharger grâce au lien ci-dessous :

https://isphere.sourceforge.io/

Pour l’installer, il faut tout d’abord télécharger et extraire l’archive en local puis lancer RDI. Cliquez ensuite sur l’onglet Aide > Installer un nouveau logiciel.

Cliquez sur local, sélectionnez le dossier que vous avez précédemment extrait puis faites OK.

Vous pouvez tout sélectionner et faire suivant jusqu’au bout.

Afficher les intitulés

Plus besoin de cliquer sur un objet / membre et de regarder la vue propriété pour avoir le texte.

Pour activer l’affichage des intitulés, cliquez sur Affichage > Préférences puis activez les deux rubriques isphere dans Général > Apparence > Décorations d’intitulés.

Résultat :

Recherche de chaine de caractères

Vous pouvez déjà le faire dans RDI en faisant un clic droit sur un fichier source / bibliothèque « Rechercher la chaine ». Mais cette option peut prendre du temps. Utilisez plutôt « Isphere source file search ».

Saisir la chaine à recherche et faites OK.

Si vous faites un double-clic sur la ligne ça ouvrira le source en édition.

Gestion des MSGF

Comme pour la recherche de chaine, on peut déjà modifier un fichier de message mais ce n’est pas très pratique. Il faut déplier le fichier de message, faire un clic droit modifier sur le message et modifier le texte.

Avec Isphere vous pouvez faire un clic droit « Isphere Message File Editor ».

Il va ouvrir le fichier de message et vous pourrez effectuer des recherches de texte, double cliquer sur un message pour l’éditer etc…

Gestion des postes d’un répertoire de liage

Clic droit sur le répertoire de liage puis « Isphere Binding Directory Editor ».

Dans l’onglet qui vient de s’ouvrir, vous pouvez ajouter un programme de service au répertoire de liage avec un simple clic droit / New (équivalent de la commande ADDBNDDIRE).

Vous avez également la possibilité d’en supprimer.

Copier un membre source

Très pratique si vous voulez copier un source d’un système à un autre (ou sur le même).

Clic droit sur un membre (ou plusieurs), puis « Copy Member’s to ».

Choisissez le système / fichier source / bibliothèque de destination et cliquez sur « Copy ».

Comparer des sources

Déjà disponible dans RDI mais Isphere permet de le faire plus facilement. Très pratique si l’on veut comparer deux sources sur deux systèmes (ou le même).

Faites un clic droit sur le source puis « Isphere compare Editor ».

, Simplifiez vous la gestion de vos SAVF

Vous avez tous trop de SAVF sur vos systèmes voici une commande qui va vous aider à les manager : WRKSAVFD.


Bibliothèque :

  • *ALL si vous souhaitez avoir la liste de tous les SAVF existants sur votre machine.
  • Nommez la bibliothèque si vous ne souhaitez afficher QUE les SAVF de cette dernière.

Confirmer si suppression :

  • *YES, par défaut, vous permettra de valider par « entrée » pour chaque fois ou vous aurez sélectionner l’option 4 : Supprimer dans l’écran suivant.
  • *NO, pour supprimer sans passer par un écran de validation de la suppression demandée lors de l’option 4 : Supprimer dans l’écran suivant.

Une option 5 : Gérer vous envoi sur la commande précédemment expliquée ici .

Vous trouverez les sources sur le GitHub Gaia-Mini-Systemes .

, , Savoir où un programme est utilisé

Vous voulez savoir où un programme est utilisé sur votre partition.

Généralement vous avez une cross référence de vos programmes basée sur des sorties de DSPPGMREF, et vous retrouvez assez facilement les programmes qui l’utilisent dans votre application.

Mais votre programme peut être tagué dans d’autres ressources, (Systèmes, SQL, etc …), voici une liste et comment les analyser

1) Table des travaux planifiés WRKJOBSCDE

SELECT * FROM QSYS2.SCHEDULED_JOB_INFO where command_string like(‘%VOTREPGM%’);

2) Table des travaux planifiés AJS (Advanced Job Scheduler)

SELECT * FROM QUSRIJS.QAIJS1CM where cmcmd like(‘%VOTREPGM%’)

Rappel, il est gratuit à partir de la version V7R5

3) Triggers, fonctions, procédure (catalogage SQL)

select * from qsys2.sysroutine where external_name like(‘%VOTREPGM%’)
and routine_body = ‘EXTERNAL’;

4) Webservices

echo "Recherche : VOTREPGM" > lst_webservices.txt ;
echo "/www/*/webservices/services/*/WEB-INF/classes/*.config" >> lst_webservices.txt ;  
echo "---------------" >> lst_webservices.txt ;       
/usr/bin/grep -i -n "VOTREPGM" /www/*/webservices/services/*/WEB-INF/classes/*.config  >> lst_webservices.txt

On suppose que vos configurations sont dans www ce qui est le défaut, et on écrit dans un fichier lst_webservices.txt de votre répertoire courant.

5) Menus SDA

SELECT *
FROM QSYS2.MESSAGE_FILE_DATA
where
MESSAGE_ID like(‘USR%’) and
MSG_TEXT like(‘%VOTREPGM%’)

6) Exit PGM

select *
from qsys2.exit_program_info where exit_program = ‘VOTREPGM‘ ;

7) Les watchers

select * from qsys2.watch_info where WATCH_PROGRAM = ‘VOTREPGM‘;

8) Les postes travaux à démarrage automatique des sous-systèmes

SELECT a.autostart_job_name, a.job_description_library, a.job_description, b.request_data
FROM QSYS2.AUTOSTART_JOB_INFO a
JOIN QSYS2.JOB_DESCRIPTION_INFO b
ON a.job_description_library = b.job_description_library
AND a.job_description = b.job_description
WHERE UPPER(b.request_data) Like(‘%VOTREPGM%’);

Remarques :

C’est sans doute pas exhaustif , mais c’est déjà ça

Pensez à regarder les planificateurs si vous en avez ?

Si vous avez une machine de PROD et de DEV, il peut être intéressant d’analyser les 2 partitions.

Voila, simple mais efficace

, , Contrôler l’existence d’un fichier stream (IFS)

Voici donc trois exemples de solutions pour tester l’existence d’un fichier dans l’IFS en CL et en SQLRPGLE.
(Il existe d’autres méthodes, mais celles-ci sont les plus simples).

La commande CHKOUT permet de verrouiller un objet, ainsi les autres utilisateurs et travaux ne peuvent plus que le lire ou le copier. Il suffit de monitorer cette commande en attendant le message CPFA0A9 qui indique que le fichier n’existe pas.

Cette méthode est donc utile lorsque l’on souhaite par la même occasion verrouiller l’objet recherché.

Il ne faut pas oublier de déverrouiller l’objet une fois votre opération terminée avec la commande CHKIN.

En SQL et SQLRPGLE, le plus simple reste d’utiliser la fonction table IFS_OBJECT_STATISTICS. Pour s’assurer ne pas tomber sur un répertoire portant le nom du fichier ou autre, il est préférable de renseigner les paramètres subtree_directories et object_type_list (bien entendu en renseignant *DIR si on cherche un répertoire).

Il suffit ensuite de tester le sqlCode, s’il est égal à 100 cela signifie que le fichier est inexistant.

Remarque

Il faut tout de même prendre en compte les droits de l’utilisateur qui réalise ces tests, en fonction de la méthode utilisée, un autre message pourrait être émit ou le fichier pourrait lui apparaitre comme inexistant.

Pour plus de détails

Documentation IBM – CHKOUT : https://www.ibm.com/docs/en/i/7.5?topic=ssw_ibm_i_75/cl/chkout.html
Documentation IBM – CHKIN : https://www.ibm.com/docs/en/i/7.5?topic=ssw_ibm_i_75/cl/chkin.html
Documentation IBM – MOV : https://www.ibm.com/docs/en/i/7.5?topic=ssw_ibm_i_75/cl/mov.html
Documentation IBM – IFS_OBJECT_STATISTICS : https://www.ibm.com/docs/en/i/7.5?topic=services-ifs-object-statistics-table-function