Intégration ILE/RPG4 et java

BoTTom |    Changer de couleur
 
Intégration des langages ILE/RPG4 et JAVA.
 
   .................................................................
   : Vous devez être familliers avec les concepts suivants :       :
   :                                                               :
   : ° ILE en général                                              :
   : ° Les programmes de services et les fonctions                 :
   : ° Les prototypes en RPG4                                      :
   : ° Les bases du langage java et de la programmation Objets     :
   :                                                               :
   :...............................................................:
 
 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
 


|    Changer de couleur
 
 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 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/ou 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.


|    Changer de couleur
 
 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 maMethode       PR          ->  ?   EXTPROC(*JAVA : 'nom de la classe' :
                              /                        'méthode' ou
                             /                                *CONSTRUCTOR)
                            /
  vous devez indiquer le type de donnée retourné
 


|    Changer de couleur
 
 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 :
 
      R = StringversChaine( DateversString(objDate) ) ;
 
  où objDate et R sont déclarés :
 
 D objDate         S               O   CLASS(*JAVA : 'java.lang.Date')
 D R               S             10A
 


|    Changer de couleur
 
 Appel et passage de paramètres :
 
  il existe deux types de méthode 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)


|    Changer de couleur
 
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("identiques");
          } else {
           System.out.println("différents");
          }
     }
}


|    Changer de couleur
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 'identiques' ;
  endif;
  *inlr = *on;
/end-free


|    Changer de couleur
 
Equivalence des différents types 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)             +
 +-----------------+------------------+----------------------------------+


|    Changer de couleur
 
 +-----------------+------------------+----------------------------------+
 +  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)
 
 Voyez ce superbe outil pour générer les prototypes RPG4 :
       http://www.foundation.be/webstart/generator/generator.jnlp


|    Changer de couleur
 
 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.
 
  Java possède sont propre ramasse-miettes (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 la
   CLASSPATH par :
 
                ADDENVVAR ENVVAR(CLASSPATH)
                          VALUE('/mesclasses/:classes/autresclasses.jar')
 


|    Changer de couleur
 
Vous pouvez fixer des options pour java, dans l'ordre suivant:
 
Dans le fichier indiqué par la variable d'env. QIBM_JAVA_PROPERTIES_FILE
 
Dans le fichier SystemDefault.properties de la HOMEDIR de l'utilisateur
 
Dans le fichier SystemDefault.properties de /QIBM/UserData/JAVA400
 
 
dont java.class.path et java.version, pour la liste complète voyez
http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/topic/rzaha/sysprop2.htm
 
 
java.version n'est utilisée que pour les versions du JDK "classic", c'est à
 dire I5/OS, pour celles tournant sous PASE: 32 bits en 5.4, 32 ou 64 en 6.1
 
  il faut renseigner JAVA_HOME (tjs variable d'environnement)
 
si vous n'indiquez pas de version particulière, le système regarde les
 versions de JDK installées et choisi dans cette ordre :
 


|    Changer de couleur
+--------------------------------------------------------------------------+
| Option de 57xxJV1       |java|  JAVA_HOME                                |
+--------------------------------------------------------------------------+
| 8 IBM tech. 5.0 32 bits | 1.5| /Qopensys/QIBM/ProdData/JavaVM/jdk50/32bit|
+--------------------------------------------------------------------------+
| 9 IBM tech. 5.0 64 bits | 1.5| /Qopensys/QIBM/ProdData/JavaVM/jdk50/64bit|
+--------------------------------------------------------------------------+
| 7 Classic 5.0           | 1.5| /QIBM/ProdData/Java400/jdk15              |
+--------------------------------------------------------------------------+
|11 IBM tech. 6.0 32 bits | 1.6| /Qopensys/QIBM/ProdData/JavaVM/jdk60/32bit|
+--------------------------------------------------------------------------+
|12 IBM tech. 6.0 64 bits | 1.6| /Qopensys/QIBM/ProdData/JavaVM/jdk60/64bit|
+--------------------------------------------------------------------------+
|10 Classic 6             | 1.6| /QIBM/ProdData/Java400/jdk6               |
+--------------------------------------------------------------------------+
| 6 Classic 1.4           | 1.4| /QIBM/ProdData/Java400/jdk14              |
+--------------------------------------------------------------------------+
bien sur, les options non installées sont ignorées lors de la recherche,
 et vous pouvez toujours "forcer" une version par:
 
  ADDENVVAR ENVVAR(JAVA_HOME)
             VALUE('/Qopensys/QIBM/ProdData/JavaVM/jdk60/64bit')


|    Changer de couleur
 
 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


|    Changer de couleur
 
 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éclaration, voir l'exemple complet)
 


|    Changer de couleur
  /free
      envname = param1 ;
      envnamelg = %len(%trim(envname)) ;
      getenv(env : envlg : envvallg :
             envname : envnamelg : APIERR); // API de QTMHCGI, renseigne env
      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[] );
 


|    Changer de couleur
 
    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 ".getBytes"
 
 
A l'inverse, ce deuxième exemple utilise 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)
 
 


|    Changer de couleur
 DgetEnvVarO       PR              O    EXTPROC(*JAVA : 'EnvClassO' :
 D                                              'getEnvVarO')
 D                                       CLASS(*JAVA : 'java.lang.String'
 D                                       STATIC
 D                                 O   CLASS(*JAVA : 'java.lang.String')
 
  *  transformation String -> Bytes
 DgetBytes         PR           128A   EXTPROC(*JAVA : 'java.lang.String'
 D                                             : 'getBytes') VARYING
  *  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')
  ...


|    Changer de couleur
  /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 );
    }





©AF400