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