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 92 contains sample 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 *----------------------------------------------------------------
* 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')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