Sign in

docs RPG Guide

Obtaining the JNI environment pointer

Obtaining the JNI environment pointer

If you need to call any JNI functions, use the /COPY file JNI from QSYSINC/QRPGLESRC. Most of the JNI functions are called through a procedure pointer. The procedure pointers are part of a data structure that it itself based on a pointer called the “JNI environment pointer”. This pointer is called JNIEnv_P in the JNI /COPY file. To obtain this pointer, call the JNI wrapper procedure getJniEnv.

EVAL   JNIEnv_P = getJniEnv();

Figure 1 contains sample source code for getJniEnv.

Figure 1. Source Code for getJniEnv

 *----------------------------------------------------------------
 * getJniEnv - get the JNI environment pointer
 * Note: This procedure will cause the JVM to be created if
 *       it was not already created.
 *----------------------------------------------------------------
P getJniEnv       b                   export
D getJniEnv       pi              *

D attachArgs      ds                  likeds(JavaVMAttachArgs)
D env             s               *   inz(*null)
D jvm             s                   like(JavaVM_p) dim(1)
D nVms            s                   like(jsize)
D rc              s             10i 0
D obj             s               o   class(*java
D                                         : 'java.lang.Integer')
D newInteger      pr              o   extproc(*java
D                                           : 'java.lang.Integer'
D                                           : *constructor)
D   value                       10i 0 value
 /free
    monitor;
       // Get the current JVM
       rc = JNI_GetCreatedJavaVMs(jvm : 1 : nVms);
       if (rc <> 0);
          // Some error occurred
          return *null;
       endif;  if (nVms = 0);
          // The JVM is not created yet.  Call a Java
          // method to get the RPG runtime to start the JVM
          obj = newInteger(5);

          // Try again to get the current JVM
          rc = JNI_GetCreatedJavaVMs(jvm : 1 : nVms);
          if (rc <> 0
          or  nVms = 0);
             // Some error occurred
             return *null;
          endif;
       endif;
       // Attach to the JVM
       JavaVM_P = jvm(1);
       attachArgs = *allx'00';
       attachArgs.version = JNI_VERSION_1_2;
       rc = AttachCurrentThread (jvm(1) : env
                               : %addr(attachArgs));
       if (rc <> 0);
          return *null;
       endif;

       // Free the object if we created it above while
       // getting the RPG runtime to start the JVM
       if obj <> *null;
          freeLocalRef (env : obj);
       endif;
    on-error;
       return *null;
    endmon;
    return env;
 /end-free
P getJniEnv       e

Figure 2. Copy-file JAVAUTIL

 *----------------------------------------------------------------
 * Copy file JAVAUTIL
 *----------------------------------------------------------------
 /if defined(JAVAUTIL_COPIED)
 /eof
 /endif
 /define JAVAUTIL_COPIED
D JNI_GROUP_ADDED...
D                 c                   0
D JNI_GROUP_NOT_ADDED...
D                 c                   -1
D JNI_GROUP_ENDED...
D                 c                   0
D beginObjGroup   pr            10i 0 extproc('beginObjGroup')
D   env                           *   const
D   capacityParm                10i 0 value options(*nopass)
D endObjGroup     pr            10i 0 extproc('endObjGroup')
D   env                           *   const
D   refObjectP                    o   class(*java:'java.lang.Object')
D                                     const
D                                     options(*nopass)
D freeLocalRef...
D                 pr                  extproc('freeLocalRef')
D   env                           *   value
D   localRef                      o   CLASS(*JAVA
D                                         : 'java.lang.Object')
D                                     value
D getNewGlobalRef...
D                 pr              o   class(*JAVA
D                                         : 'java.lang.Object')
D                                     extproc('getnewGlobalRef')
D   env                           *   value
D   localRef                      o   class(*JAVA
D                                         : 'java.lang.Object')
D                                     value
D freeGlobalRef...
D                 pr                  extproc('freeGlobalRef')
D   env                           *   value
D   globalRef                     O   class(*JAVA
D                                         : 'java.lang.Object')
D                                     value
D getJniEnv       pr              *   extproc('getJniEnv')

Figure 3. Using the wrappers for the JNI functions

Java class

class TestClass{
   String name = "name not set";

   TestClass (byte name[]) {
      this.name = new String(name);
   }

   void setName (byte name[]) {
      this.name = new String(name);
   }

   String getName () {
      return this.name;
   }
}
RPG program

H THREAD(*SERIALIZE)
H BNDDIR('JAVAUTIL')
 // (JAVAUTIL is assumed to the binding directory that lists
 // the service program containing the procedures described
 // below)

 /copy JAVAUTIL
 // (JAVAUTIL is assumed to be the source member containing the
 // prototypes for the procedures described below)

D TestClass       C                   'TestClass'
D StringClass     C                   'java.lang.String'
D newTest         PR              O   EXTPROC(*JAVA : TestClass
D                                           : *CONSTRUCTOR)
D   name                        25A   VARYING CONST

D getName         PR              O   CLASS(*JAVA : StringClass)

D                                     extproc(*JAVA : TestClass
D                                           : 'getName')

D setName         PR                  extproc(*JAVA : TestClass
D                                           : 'setName')
D   newName                     25A   VARYING CONST

D newString       PR              O   EXTPROC(*JAVA : StringClass
D                                           : *CONSTRUCTOR)
D   value                    65535A   VARYING CONST

D nameValue       PR            25A   VARYING
D                                     extproc(*JAVA : StringClass
D                                           : 'getBytes')

D myTestObj       S                   LIKE(newTest)
D myString        S                   LIKE(newString)
D env             S                   LIKE(getJniEnv)
 /free

    // Get the JNI environment pointer so that JNI functions
    // can be called.
    env = getJniEnv();
   

    // Set the beginning marker for an "object group"
    // so that any objects created between now and the
    // "end object group" can be freed all at once.

    beginObjGroup (env);

    // Create a Test object to work with
    // We do not want this object to be freed with the
    // other objects in the object group, so we make it
    // a permanent object

    myTestObj = newTest ('RPG Dept');
    myTestObj = getNewGlobalRef (env : myTestObj);

    // Get the current "name" from the Test object
    // This creates a local reference to the Name object

    myString = getName (myTestObj);
    dsply (nameValue(myString));

    // Change the name

    setName (myTestObj : 'RPG Department');

    // Get the current "name" again.  This will cause
    // access to the previous local reference to the old name
    // to be lost, making it impossible for this RPG
    // program to explicitly free the object.  If the object
    // is never freed by this RPG program, Java could never
    // do garbage-collection on it, even though the old String
    // object is not needed any more.  However, endObjGroup
    // will free the old reference, allowing garbage collection

    myString = getName (myTestObj);
    dsply (nameValue(myString));

    // End the object group.  This will free all local
    // references created since the previous beginObjGroup call.
    // This includes the two references created by the calls
    // to getName.

    endObjGroup (env);

    // Since the original Test object was made global, it can
    // still be used.

    setName (myTestObj : 'RPG Compiler Dept');

    // The original Test object must be freed explicitly
    // Note: An alternative way to handle this situation
    //       would be to use nested object groups, removing
    //       the need to create a global reference
    //         beginObjGroup ------------.
    //         create myTestObj          |
    //         beginObjGroup  ---------. |
    //         ...                     | |
    //         endObjGroup    ---------' |
    //         use myTestObj again       |
    //         endObjGroup   ------------'

    freeGlobalRef (env : myTestObj);

    return;

 /end-free