This sample program passes an integer back and forth between Java and PL/I. Refer to Figure 84 for the complete listing of the jPassInt.java program. The Java portion has one Java class, jPassInt.java. The native method, written in PL/I, is contained in passInt.pli. Much of the information from the first sample program applies to this sample program as well. Only new or different aspects will be discussed for this sample program.
The native method for this sample program looks like this:
public native void pliShowInt();
The Java statement that loads the native library for this sample program looks like this:
static {
System.loadLibrary("passInt");
}
The jPassInt class also includes a main method to instantiate the class and call the native method. The main method instantiates jPassInt and calls the pliShowInt() native method.
This sample program prompts the user for an integer and reads that value in from the command line. This is done within a try/catch statement as shown in Figure 84.
// Read an integer, call PL/I, display new integer upon return
import java.io.*;
import java.lang.*;
public class jPassInt{
/* Fields to hold Java string and int */
int myInt;
String myString;
/* Load the PL/I native library */
static {
System.loadLibrary("passInt");
}
/* Declare the PL/I native method */
public native void pliShowInt();
/* Main Java class */
public static void main(String[] arg) {
System.out.println(" ");
/* Instantiate Java class and initialize string */
jPassInt pInt = new jPassInt();
pInt.myInt = 1024;
pInt.myString = " ";
/* Prompt user for an integer */
try {
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
/* Process until 'quit' received */
while (!pInt.myString.equalsIgnoreCase("quit")) {
System.out.println
("From Java: Enter an Integer or 'quit' to quit.");
System.out.print("Java Prompt > ");
/* Get string from command line */
pInt.myString = in.readLine();
if (!pInt.myString.equalsIgnoreCase("quit"))
{
/* Set int to integer value of String */
pInt.myInt = Integer.parseInt( pInt.myString );
/* Call PL/I native method */
pInt.pliShowInt();
/* Return from PL/I and display new string */
System.out.println(" ");
System.out.println
("From Java: Integer set by PL/I is: " + pInt.myInt );
}
}
} catch (IOException e) {
}
}
}The command to compile the Java code would look like this:
javac jPassInt.java
All of the information about writing the PL/I "Hello World" sample program applies to this program as well.
The PL/I procedure name for this program would be Java_jPassInt_pliShowInt.
The complete procedure statement for the sample program looks like this:
Java_passNum_pliShowInt:
Proc( JNIEnv , myjobject )
external( "Java_jPassInt_pliShowInt" )
Options( FromAlien NoDescriptor ByValue );
The two PL/I include files which contain the PL/I definitions of the Java Native interface are ibmzjni.inc which in turn includes ibmzjnim.inc. These include files are included with this statement:
%include ibmzjni;
The ibmzjni and ibmzjnim include files are provided in the PL/I SIBMZSAM data set.
The complete PL/I program is shown in Figure 85. This sample PL/I program makes several calls through the JNI.
Upon entry, a reference to the calling Java object, myObject, is passed into the PL/I procedure. The PL/I program will use this reference to get information from the calling object. The first piece of information is the Class of the calling object which is retrieved using the GetObjectClass JNI function. This Class value is then used by the GetFieldID JNI function to get the identity of the Java integer field in the Java object that we are interested in. This Java field is further identified by providing the name of the field, myInt, and the JNI field descriptor, I, which identifies the field as an integer field. The value of the Java integer field is then retrieved using the GetIntField JNI function which is then displayed by the PL/I program.
After displaying the retrieved Java integer, the PL/I program prompts the user for a PL/I integer to be used to update the integer field in the calling Java object. The PL/I integer value is then used to update the integer field in the calling Java object using the SetIntField JNI function.
When the PL/I program ends, control is returned to Java, where the newly updated Java integer is displayed by the Java program.
*Process Limits( Extname( 100 ) ) Margins( 1, 100 ) ;
*Process Display(Std) Dllinit Extrn(Short);
*Process Rent Default( ASCII IEEE );
plijava_demo: package exports(*);
Java_passNum_pliShowInt:
Proc( JNIEnv , myjobject )
external( "Java_jPassInt_pliShowInt" )
Options( FromAlien NoDescriptor ByValue );
%include ibmzjni;
Dcl myClazz Type jClass;
Dcl myFID Type jFieldID;
Dcl myJInt Type jInt;
dcl rtnJInt Type jInt;
Dcl myJObject Type jObject;
Dcl pliReply Char(132) Varz;
Dcl nullPtr Pointer;
Display(' ');
/* Get information about the calling Class */
myClazz = GetObjectClass(JNIEnv, myJObject);
/* Get Field ID for int field from Java */
myFID = GetFieldID(JNIEnv, myClazz, "myInt", "I");
/* Get Integer value from Java */
myJInt = GetIntField(JNIEnv, myJObject, myFID);
display('From PLI: Integer retrieved from Java is: ' || trim(myJInt) );
display('From PLI: Enter an integer to be returned to Java:' )
reply(pliReply);
rtnJInt = pliReply;
/* Set Integer value in Java from PL/I */
nullPtr = SetIntField(JNIEnv, myJObject, myFID, rtnJInt);
End;
end;Compile the PL/I sample program with the following command:
pli -c passInt.pli
Link the resulting PL/I object deck into a shared library with this command:
c89 -o libpassInt.so passInt.o
Be sure to include the lib prefix on the name or the PL/I shared library or the Java class loader will not find it.