Pause-Café Volubis

pause-café

rendez-vous technique
Pause-Café est une réunion technique
destinée aux informaticiens sur plateforme IBM i.
Elle a lieu 3 à 4 fois par an : en Bretagne et sur internet.

Pause-café #32

Septembre 2003


 

JNI : Java et RPG4



Procédures RPG4


  L'appel d'un programme peut-être écrit en format libre (V3.60)
  cela ce réalise avec un protoype (modèle) puis l'ordre CALLP.
     il faut pour cela déclarer le programme et ses paramètres avant,       en spécif D, cela s'appelle un PROTOTYPE.
  DEXEC             PR                  EXTPGM(QCMDEXC)   D cmd                          250   D cmdlen                        15P 5 CONST
    PR indique qu'il s'agit d'un prototype (même positions que DS)
    EXTPGM le nom du pgm externe
    CONST sur un paramètre indique qu'il s'agit d'un paramètre non           modifiable, car copié en mémoire, ce qui autorise les expressions.
ce qui permet      C                   callp     exec(commande:%size(commande))



  Le même ordre peut être utilisé pour l'appel à des procédures liées      (liage par copie[module] ou par référence[programme de service].)
     il faut alors déclarer la procédure et ses paramètres, avant, en       spécif D avec le mot-clé EXTPROC
  Dinviteclient     PR                  EXTPROC('F4Client')   D nocli                          6  0   D fenetre                        1    CONST
    EXTPROC le nom de la procédure
CONST (idem EXTPGM), ici VALUE aurait permis un passage de paramètre par valeur
ce qui permet
     /free                  inviteclient(nocli:'O')) ; /end-free

Exemples d'utilisation de fonctions destinées au C

  • sleep (identique à DLYJOB)

         h bnddir('QC2LE') DFTACTGRP(*NO) ACTGRP(*CALLER)
          ***************************************************************
          * exécution d'une commande système                            *
          ***************************************************************
         D sleep           pr            10U 0 extproc('sleep')
         D  secondes                     10U 0  value
          /free
    
            sleep(500);
    
             sleep(30);
    
            return;       /end-free

  • system (pour passer des commandes)
         h bnddir('QC2LE') DFTACTGRP(*NO) ACTGRP(*CALLER)
          ***************************************************************
          * exécution d'une commande système                            *
          ***************************************************************
         D system          pr            10i 0 extproc('system')
         D  cmd                            *   options(*string) value
    
         D MSGID           S              7A   IMPORT('_EXCP_MSGID')       /free         system('ADDLIBLE FORMATIONX');         if MSGID <> ' ';            dsply MSGID;         endif;         return;       /end-free

Enfin, JNI


Intégration des langages ILE/RPG4 et JAVA.

 Il est possible de déclarer et d'utiliser depuis RPG4 :
   - des méthodes Java    - des objets (retournés par Java ou destinés à être retournés)
 Il est aussi possible de déclarer en RPG4 :
   - des fonctions RPG4 devant être utilisées depuis java



 Quelques rappels :
 - java est un langage orienté objet
 - en java un objet est matérialisé par une Classe (CLASS en anglais)
   cette classe encapsule (contient et protège)
   + des variables, souvent privées, c.a.d dire non visibles de l'exterieur
        - ces variables peuvent être des données élémentaires           (octet, entier, numérique à virgule flottante, ..)
        - ou bien elles même des objets (String par exemple est un objet)
   + des méthodes (ou fonctions) chargée de traiter et de retourner       les variables sus nommées.
    Une de ces méthodes peut porter le même nom que la classe (on parle     alors de constructeur) elle est chargée de réaliser l'initialisation      lors de la création d'une instance de l'objet en mémoire.



 Déclaration d'un objet/java en RPG4
 D javaChaine      S               O   CLASS(*JAVA : 'java.lang.string')
 cette définition peut être placée
  en tant que variable   en tant que paramètre d'une procédure   en tant que valeur retournée par une procédure
  Ici, l'objet javaChaine va probablement être chargé par l'appel à une    méthode sous la forme javaChaine = maMethode()
 Déclaration d'une méthode
 D maMehtode       PR          ->  ?   EXTPROC(*JAVA : 'nom de la classe' :                               /                        'méthode' ou                              /                                *CONSTRUCTOR)                             /   vous devez indiquer le type de donnée retourné



 par exemple, la methode suivante transforme l'objet String en suite   d'octets :
 D StringversChainePR          32767   VARYING                                        EXTPROC(*JAVA : 'java.lang.String'                                                        'getBytes')
 et celle ci transforme l'objet Date en Objet String
 D DateversString  PR              O   CLASS(*JAVA : 'java.lang.String')                                        EXTPROC(*JAVA : 'java.lang.Date'                                                        'toString')  bien sur vous pourrez écrire :
      var1 = StringversChaine( DateversString(obj1) ) ;
  où obj1 et var1 sont déclarés :
 D obj1            S               O   CLASS(*JAVA : 'java.lang.Date')  D var1            S             10A



 Appel et passage de paramètres :
  il existe deux types de méthodes en Java.
  1/ les méthodes statiques ou méthodes de classe, elles sont déclarées
     Static  typeretour nomMethode() {      }
     elle ne s'appuient pas sur une instance pour réaliser le traitement
     VOUS DEVREZ AJOUTER STATIC, lors du prototypage RPG

  2/ les méthodes qui s'appuient sur une instance (un objet en mémoire)
     VOUS DEVREZ AJOUTER un paramètre aux paramètre(s) déclaré(s) dans le       prototype: le nom de l'objet instancié.
        en java dat1.toString         en RPG4 DateversString(dat1)



Exemple avec la méthode equalsIgnoreCase de l'objet String.
 Cette méthode compare deux objets String et indique (par un booléen)   que leur contenu est identique (true) ou non (false)
 en java :
 public class Equals {      public static void main(String[] args) {
          String maChaine1 = new String("test1");           String maChaine2 = new String("test2");
          if (maChaine1.equalsIgnoreCase(maChaine2)) {
           System.out.println("identique");           } else {            System.out.println("différents");           }      } }


 en RPG4 :
 H DFTACTGRP(*NO) ACTGRP(*CALLER) THREAD(*SERIALIZE)

 D newString       PR              O   EXTPROC(*JAVA : 'java.lang.String')  D                                                     *CONSTRUCTOR)  D                               30A   CONST VARYING
 D maChaine1       S               O   CLASS(*JAVA : 'java.lang.String')  D maChaine2       S               O   CLASS(*JAVA : 'java.lang.String')
 D StrEquals       PR              N   EXTPROC(*JAVA : 'java.lang.String' :                                                         'equalsIgnoreCase')  D                                 O   CLASS(*JAVA : 'java.lang.String')
/free   maChaine1 = newstring('test1');   maChaine2 = newstring('test2');   if StrEquals(maChaine1 : maChaine2) ;      dsply 'identique' ;   endif;   *inlr = *on; /end-free



Equivalence des différents type de données :  +-----------------+------------------+----------------------------------+  +  Java           +  RPG4            + commentaires                     +  +-----------------+------------------+----------------------------------+  +   Boolean       +     N            +  indicateur                      +  +-----------------+------------------+----------------------------------+  +   Byte          +    3I 0          +  un octet binaire                +  +                 +                  +   (pas de conversion)            +  +                 +    1A            +  un caractère                    +  +                 +                  +   (conversion ASCII/EBCDIC)      +  +-----------------+------------------+----------------------------------+  +   Byte[]        +    1A     DIM(x) +  tableau d'octets                +  +-----------------+------------------+----------------------------------+  +   Short         +    5I 0          +  entier court (deux octets)      +  +-----------------+------------------+----------------------------------+  +   Int           +   10I 0          +  entier (quatre octets)          +  +-----------------+------------------+----------------------------------+  +   Long          +   20I 0          +  entier long (8 octets)          +  +-----------------+------------------+----------------------------------+  +   float         +    4F            +  flottant (4 octets)             +  +-----------------+------------------+----------------------------------+



 +-----------------+------------------+----------------------------------+  +  Java           +  RPG4            + commentaires                     +  +-----------------+------------------+----------------------------------+  +   double        +    8F            +  flottant (8 octets)             +  +-----------------+------------------+----------------------------------+  +   Char          +    1C            +  1 octets en UCS-2 (unicode)     +  +-----------------+------------------+----------------------------------+  +   Char[]        +    nC            +  n octets en UCS-2 (unicode)     +  +-----------------+------------------+----------------------------------+  +  un objet       +     O            +  CLASS(*JAVA : ..)               +  +-----------------+------------------+----------------------------------+  +  tableau        +     ?  DIM(x)    +  pour pouvez faire un tableau    +  +                 +                  +   de n'importe quelle définition +  +-----------------+------------------+----------------------------------+
 la plupart des chaines sont à taille variable :
   pour les variables caractères (UCS-2) indiquez VARYING
   Pour les tableaux de caractères indiquez OPTIONS(*VARSIZE)



 Pour appeller une méthode java depuis RPG4
 Nous l'avons vu, utiliser directement la méthode ou bien CALLP   si la méthode ne retourne pas de valeur (void).
 RPG va vérifier si la JVM (machine virtuelle Java, "run-time" java)   est démarrée, sinon, il la démarre.
  Vous pouvez la démarrer par pgm (et l'arreter) en utilisant les API JNI.    (voir plus loin, les exemples associés à ce cours)
  Java possède sont propre ramasse-miette (méchanisme qui permet à la JVM    de détruire les objets de la mémoire quand ils ne sont plus utilisés)   Dans notre cas, Java ne sait plus, et nous devons donc supprimer les    instances, nous même, toujours avec les API JNI.
  Enfin, si vous utilisez des classes non standard, précisez bien la    CLASSPATH par :                    ADDENVVAR ENVVAR(CLASSPATH)                            VALUE('/mesclasses/:classes/autresclasses.jar')



 A l'inverse, pour lancer une fonction RPG4 depuis une classe JAVA   vous devrez :
   1/ coder le prototype avec EXPORT (fonction publique, visible)
   2/ créér un programme de service et le placer dans *LIBL.
   2/ déclarer votre programme de service en JAVA par :       .............................................................       : static                                                    :       : {                                                         :       :       System.loadLibrary("MONSRVPGM");                    :       : }                                                         :       :                                                           :       : (static) native boolean verifClient(byte nomDuClient[]);  :       :...........................................................:
     bien sûr il faut ensuite envoyer des arguments compatibles       avec le type attendu, par exemple :
            if ( verifClient(str.getBytes() ) { // ne pas envoyer un String



 si vous souhaitez un code RPG4 simple, envoyez des types élémentaires     (byte, int , etc...)
 si vous souhaitez un code JAVA simple, envoyez des objets et faites   la conversion (par exemple String en Bytes) dans le programme RPG4.
Exemple 1:
 Fonction RPG retournant la longueur d'une variable d'environnement.
 DgetenvvarL       PR            10I 0 STATIC  D                                     EXTPROC(*JAVA : 'EnvClassL' :  D                                      'getEnvVarL')  D                              128A   VARYING CONST
 PgetEnvVarL       B                   EXPORT  D                 PI            10I 0 STATIC  D param1                       128A   VARYING CONST
 ../... (suivent d'autres déclarations, voir l'exemple complet)


  /free
      envname = param1 ;
      envnamelg = %len(%trim(envname)) ;
      getenv(env : envlg : envvallg :
             envname : envnamelg : APIERR) ;  // API de QTMHCGI
      retour = %len(%trim(env));
      return retour;
  /end-free
 PgetEnvVarL       E


La classe JAVA
 class EnvClassL  {     static     {       System.loadLibrary("GETENVVARL");     }
    native static int getEnvVarL (byte envname[] );



    public static void main(String[] args)
    {        String envvar = args[0] ;        int retour;        retour = getEnvVarL(envvar.getBytes() ) ;        System.out.println("variable " + envvar + " =" + retour );     } }
Vous remarquerez l'envoi de données simples à l'aide de .getButes

A l'inverse ce deuxième exemple utilsie des données String (objet)
le programme RPG4, doit donc transformer l'objet String en chaine simple (déclaration de la méthode getBytes), puis transformer la variable  contenant les données à retourner en String (*CONSTRUCTOR sur la classe  java.lang.string)



 DgetEnvVarO       PR              O    EXTPROC(*JAVA : 'EnvClassO' :
 D                                              'getEnvVarO')
 D                                       CLASS(*JAVA : 'java.lang.String'
 D                                       STATIC
 D                                 O   CLASS(*JAVA : 'java.lang.String')

  *  de transformation String -> Bytes  DgetBytes         PR           128A   EXTPROC(*JAVA : 'java.lang.String'  D                                             : 'getBytes') VARYING   *  de transformation Byte -> String  DnewString        PR              O   EXTPROC(*JAVA : 'java.lang.String'  D                                             : *CONSTRUCTOR)  D bytes                        128A    CONST VARYING
 PgetEnvVarO       B                   EXPORT  D                 PI              O   CLASS(*JAVA : 'java.lang.String')  D                                      STATIC  D String1                         O   CLASS(*JAVA : 'java.lang.String')
  * variables  D String2         S               O   CLASS(*JAVA : 'java.lang.String')   ...


  /free
      envname = getBytes(String1);
      envnamelg = %len(%trim(envname)) ;

      getenv(env : envlg : envvallg :              envname : envnamelg : APIERR)  //APi de QTMHCGI
      String2 = newString(env);       return String2;   /end-free  PgetEnvVarO       E
 L'utilisation en JAVA est beaucoup plus simple (déclaration identique)
    native static String getEnvVarO (String envname );
    public static void main(String[] args)     {        String envvar = args[0] ;        String retour = getEnvVarO(envvar) ;        System.out.println("variable " + envvar + " =" + retour );     }

 

Iseries Web Access 2

Il s'agit de la deuxième version WEB de Client Access ou autrement dit l'accès à un AS/400 depuis un navigateur WEB, comprenant :

  • un portail (page d'accueil paramétrable)
  • Operation navigator réécrit à base de pages JSP
  • une émulation 5250 de base
  • Vous devez obtenir cette version avec une licence Client Access V5R20

  • Ce produit fonctionne avec Tomcat, WAS 4.0 et 5.0 (il faut appliquer au moins la PTF SI05427)

    Nous montrerons une installation avec APACHE/TOMCAT, qui nécessite uniquement 300 CPW


il vous faut configurer une instance de TOMCAT en mode "out process"

  1. démarrer l'instance d'administration par STRTCPSVR SERVER(*HTTP) HTTPSVR(*ADMIN)

    puis lancer votre navigateur et saisissez comme URL ;http://votre-as400:2001/HTTPAdmin

    SIGNEZ VOUS AVEC UN PROFIL AVEC LES DROITS *IOSYSCFG et choisissez Create ASF Tomcat Server



    Indiquez un nom pour votre instance Tomcat.

    Confirmez cette page (les fichiers de config seront placés dans /ASFTomcat/le-nom-de-votre-instance)


    Indiquez ici :
     • que vous êtes à l'écoute sur toutes les adresses IP (obligatoire)
     • Le port serveur d'écoute de Tomcat (par défaut 8009, choisissez un port au dessus de 1024)
     • Le type de communication : mode texte (AJP12) ou binaire (AJP13, conseillé)

    Puis indiquez les contextes (localisation réelle d'une application à partir d'une URL)

    respectez parfaitement la saisie indiquée ici.

    le configurateur ne trouvent ni un répertoire webaccess dans webapps, ni un fichier .war, il doit vous signaler une erreur, que vous ignorerez


    Puis confirmer la création sur cette page récapitulative, par Finish.

  2. Configuration de Web access:

    Il s'agit ici de terminer la config du serveur Tomcat et de placer la directory webaccess manquante et particulièrement son fichier web.xml

    Dans une session 5250, saisissez QIWA2/CFGACCWEB2, puis F4

    Indiquez le type de serveur (ici *ASFTOMCAT) , le répertoire et le profil sous lequel tourne ce serveur.

    vous devez voir :
  3. dernier point : Apache

    Prenez un serveur Apache existant (ou créez en un) et choisissez ASF Tomcat setting


    cochez ici ENABLED OUT PROCESS ...

    Si votre serveur Apache est dédié à WebAccess, décochez "In Process",
    si vous traitez déja des pages JSP (développement, Webfacing) vous pouvez laisser cette option

    Complétez la ligne suivante :


    précisez
     • un nom de travail pour la liaison avec Tomcat (worker1 va très bien)
     • Le type de communication choisi précédement (AJP13)
     • Le port choisi, par défaut localhost:8009
     • et définissez le point de montage : /webaccess/*
    (chaine de caractères dans l'URL permettant à Apache de savoir qu'il faut passer la main à Tomcat)
  4. Testez, en saisissant comme URL http://votre-as400/webaccess/iWAHome

    (respectez la casse, les caractères W, A et H doivent être en majuscules)



    Pour ignorer cette page "portail" et aller directement à la page principale : http://votre-as400/webaccess/iWAMain


    Utilisez ensuite le menu de gauche pour accéder à toutes les fonctions de Web Access.

 

Principales fonctions disponibles :

Titre URL
(relatives à /<votre AS>/webaccess)
Commentaire
Mon Dossier /iWAMyFolder

contient les éléments placés par l'utilisateur
  (définitons de requête, ...)

Impression  

•Onglet (affiche un menu)

Sorties Imprimantes

//iWASpool WRKSPLF

Imprimantes

/iWAPrinters WRKWTR (ne montre pas les OUTQ remote)

Imprimantes Internet

/iWAInternetPrinters les imprimantes IPP

Partages imrpimantes

/iWAPrinterShares les partages imprimantes de Netserver

Files d'attente en sortie

/iWAOutputQueues WRKOUTQ
Messages  

•Onglet

Affichage des messages
/iWAMessages voir les messages de l'utilisateur (WRKMSG)
Envoi d'un message
/iWASendMessage envoi d'un message (SNDMSG)
Messages opérateur
/iWAMessages?msgq=QSYS/QSYSOPR DSPMSG *SYSOPR
Files d'attente messages
/iWAMessagesQueues WRKMSGQ *ALL
Travaux  

•Onglet

Travaux

/iWAJobList?jobtype=user WRKUSRJOB
Travaux de serveur
/iWAJobList?jobtype=server Les travaux de l'utilisateur de type serveur
5250  

•Onglet

Sessions Actives
/iWAActiveSessions Listes des sessions 5250 IWA actives
Sessions configurées
/iWAConfiguredSessions

Liste des sessions configurées

Démarrage de session
/iWAStartSession

Démarrage avec invite d'une session

  • /iWA5250?sessname=xx démarre la session xx
  • /iWA5250 démarre une session par défaut
Base de données  

•Onglet

Tables

/iWADbTables Liste des tables de *USRLIBL (par défaut)
Mes Demandes
/iWADbRequest

Liste des demandes de transfert de fichier mémorisées :

Exécution d'instructions  SQL
/iWADbRunSQL Assistant à la création d'une requête SQL et exécution   (affichage, transfert ou envoi par mail)
Copie de données dans une table
/iWADbUpload Transfert de fichier vers l'AS/400
Importation de demandes
/iWADbImport Iimportation de .tto/.rto (ou équivalents)
  de Client Access
Fichiers  

•Onglet

Recherche de fichiers
/iWABrowesFiles Navigation dans l'arborescence IFS (WRKLNK)
partages de fichiers
/iWAFileShares Gestion des partages NetServer
Commandes  

•Onglet

Mes commandes
/iWACommandList Liste des commandes mémorisées
Exécution de commandes
/iWACommand Exécute, affiche le(s) message(s) résultat
et possède un historique des commandes passées
Recherche
/iWACommandSearch SLTCMD en plus puissant (recherche sur le libellé)
Personnalisation  

•Onglet

Préférences

/iWACustomize

Gestion des paramètres de l'utilisateur en cours

Profils utilisateurs
/iWACustomizeList?action=users

Paramètres par utilisateur

Profils de groupe
/iWACustomizeList?action=groups

Paramètres par profil de groupe
  (*PUBLIC pour tout le monde)

Profil sélectionné
/iWACustomizeList?action=select

Paramètres d'un profil (à saisir)

Autre  

•Onglet

Modification du mot de passe
/iWAChangePassword CHGPWD
Pool de connexion
/iWAConnectionPool paramétrage des serveurs Host liés t à WebAccess
Trace
/iWATrace niveau de trace souhaité
A propos
/iWAInfo affiche des informations sur le produit et le serveur
Divers  

Non répertoriés dans un menu

Valeurs système

/iWASysValList
/iWASysValGroupList

listes des valeurs système
Liste des valeurs système par catégorie

liste des produits
/iWAProdList Liste des produits installés (DSPSFWRSC)
Informations sur un produit
/iWAProdInfo?prodid=xxx Affiche les informations sur le produit xxx
PTF du produit
/iWAPTFList?prodid=xxx Liste les PTF associées au produit xxx (DSPPTF)
Infos sur une PTF
/iWAPTFInfo?ptfid=SIxxxxx Informations sur la PTF SIxxxxx

Test de Webaccess

/iWAPing Affiche

 



©AF400

 

Copyright © 1995,2003 VOLUBIS