Step 3: Writing the PL/I program

Most of the information about writing the PL/I "Hello World" sample program, as described in Step 3: Writing the PL/I Program, applies to this program as well. However, because in this sample PL/I is calling Java™, there are some additional points to consider.

Correct form of PL/I procedure name and procedure statement

Because in this sample the PL/I program is calling Java, the PL/I program is MAIN. There is no need to be concerned about the external name of this PL/I program because it is not referenced.

The complete procedure statement for the sample program is as follows:

createJVM: Proc Options(Main);

JNI include file

The two PL/I include files that contain the PL/I definitions of the Java native interface are ibmzjni.inc, which in turn includes ibmzjnim.inc. Even though in this sample PL/I is calling Java, these include files are still necessary. 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.

Linking the PL/I program with the Java library

Because this PL/I sample program calls Java, the program must link to the Java library. The Java libraries are linked with XPLINK and the PL/I modules are not. PL/I can still link to and call XPLINK libraries but you must use the PLIXOPT variable to specify the XPLINK=ON runtime option. You can declare the PLIXOPT variable as follows:

  Dcl PLIXOPT     Char(40) Varying Ext Static Init( 'XPLINK(ON)'e );

For a description of PLIXOPT, see the z/OS Language Environment Programming Guide.

Using the Java invocation API

This PL/I sample program calls the Java invocation API JNI_CreateJavaVM to create its own embedded JVM. This API requires certain structures to be set up and initialized correctly as shown in Table 1.

  1. JNI_GetDefaultJavaVMInitArgs is called to get the default initilization options.
  2. These default options are modified with the addition of the java.class.path information.
  3. JNI_CreateJavaVM is called to create the embedded JVM.

The complete PL/I program

The complete PL/I program is shown in Table 1. This sample PL/I program makes several calls through the JNI.

In this sample, the reference to the Java object, a newly created JVM in this case, is not passed in but is instead returned from the call to the JNI_CreateJavaVM API. The PL/I program uses this reference to get information from the JVM. The first piece of information is the Class containing the Java method to call. This Class is found by the FindClass JNI function. The Class value is then used by the GetStaticMethodID JNI function to get the identity of the Java method that will be called.

Before calling this Java method, convert the PL/I string into a format that Java understands. The PL/I program holds the string in ASCII format. Java strings are stored in UTF format. In addition, Java strings are not really strings as PL/I programmers understand them but are themselves a Java class and can only be modified through methods. To create a Java string, use the NewStringUTF JNI function. This function returns a Java object called myJString that contains the PL/I string converted to UTF. Next create a Java object array by calling the NewObjectArray JNI function, passing to it the reference to the myJString object. This function returns a reference to a Java object array containing the string for the Java method to display.

Now the Java method can be called by the CallStaticVoidMethod JNI function and will then display the string passed to it. After displaying the string, the PL/I program destroys the embedded JVM by using the DestroyJavaVM JNI function and the PL/I program completes.

The complete source of the PL/I program is shown in Table 1.

Table 1. PL/I sample program #4 - Calling the Java invocation API
*Process Limits( Extname( 100 ) )  Margins( 1, 100 );
*Process Margins( 1, 100 ) ;
*Process Display(STD) Rent;
*Process Default( ASCII ) Or('|');
createJVM: Proc Options(Main);

  %include ibmzjni;

  Dcl myJObjArray Type jobjectArray;
  Dcl myClass     Type jclass;
  Dcl myMethodID  Type jmethodID;
  Dcl myJString   Type jstring;
  Dcl myRC        Fixed Bin(31)  Init(0);
  Dcl myPLIStr    Char(50) Varz
                  Init('... a PLI string in a Java Virtual Machine!');
  Dcl OptStr1 char(1024) varz;
  Dcl OptStr2 char(1024) varz;
  Dcl myNull      Pointer;
  Dcl VM_Args     Like JavaVMInitArgs;
  Dcl myOptions   Like JavaVMOption;
  Dcl PLIXOPT     Char(40) Varying Ext Static Init( 'XPLINK(ON)'e );

  Display('From PL/I  - Beginning execution of createJVM...');
  VM_Args.version = JNI_VERSION_1_6;

  myRC =  JNI_GetDefaultJavaVMInitArgs( addr(VM_Args) );
  OptStr1 = "-Djava.class.path=.:";
  OptStr2 = "-Djava.compiler=NONE";

  myOptions(1).theOptions = addr(OptStr1);
  myOptions(2).theOptions = addr(OptStr2);
  VM_Args.nOptions = 2;
  VM_Args.JavaVMOption = addr(myOptions);

  /* Create the Java VM                                       */
  myrc = JNI_CreateJavaVM(
             addr(jvm_ptr),
             addr(JNIEnv),
             addr(VM_Args) );

  /* Get the Java Class for the javaPart class                */
  myClass = FindClass(JNIEnv, "javaPart");
  /* Get static method ID                                     */
  myMethodID = GetStaticMethodID(JNIEnv, myClass,"main",
              "([Ljava/lang/String;)V" );
  /* Create a Java String Object from the PL/I string.        */
  myJString = NewStringUTF(JNIenv, myPLIStr);
  myJObjArray = NewObjectArray(JNIEnv, 1,
                FindClass(JNIEnv,"java/lang/String"), myJString);
  Display('From PL/I  - Calling Java method in new JVM from PL/I...');
  Display('  ');
  myNull = CallStaticVoidMethod(JNIEnv, myClass,
             myMethodID, myJObjArray );
  /* destroy the Java VM                                      */
  Display('  ');
  Display('From PL/I  - Destroying the new JVM from PL/I...');
  myRC = DestroyJavaVM( JavaVM );
end;