Chapter 23. Interfacing with Java. IBM Version 8.5
Реклама
Реклама
Chapter 23. Interfacing with Java
This chapter gives a brief description of Java and the Java Native Interface (JNI) and explains why you might be interested in using it with PL/I. A simple Java -
PL/I application will be described and information on compatibility between the two languages will also be discussed.
Before you can communicate with Java from PL/I you need to have Java installed on your system. There are many places to download a free version of the latest
Java Development Kit (JDK).
What is the Java Native Interface (JNI)?
Java is an object-oriented programming language invented by Sun Microsystems and provides a powerful way to make Internet documents interactive.
The Java Native Interface (JNI) is the Java interface to native programming languages and is part of the Java Development Kits. By writing programs that use the JNI, you ensure that your code is portable across many platforms.
The JNI allows Java code that runs within a Java Virtual Machine (JVM) to operate with applications and libraries written in other languages, such as PL/I. In addition, the
Invocation API
allows you to embed a Java Virtual Machine into your native PL/I applications.
Java is a fairly complete programming language; however, there are situations in which you want to call a program written in another programming language. You would do this from Java with a method call to a native language, known as a
native method
.
Some reasons to use native methods may include the following: v The native language has a special capability that your application needs and that the standard Java class libraries lack.
v
You already have many existing applications in your native language and you wish to make them accessible to a Java application.
v
You wish to implement a intensive series of complicated calculations in your native language and have your Java applications call these functions.
v
You or your programmers have a broader skill set in your native language and you do not wish to loose this advantage.
Programming through the JNI lets you use native methods to do many different operations. A native method can: v utilize Java objects in the same way that a Java method uses these objects.
v create Java objects, including arrays and strings, and then inspect and use these objects to perform its tasks.
v inspect and use objects created by Java application code.
v update Java objects that it created or were passed to it, and these updated objects can then be made available to the Java application.
Finally, native methods can also easily call already existing Java methods, capitalizing on the functionality already incorporated in the Java programming
© Copyright IBM Corp. 1998, 2012
419
framework. In these ways, both the native language side and the Java side of an application can create, update, and access Java objects and then share these objects between them.
JNI Sample Program #1 - 'Hello World'
The first sample program we will write is yet another variation of the "Hello
World!" program.
Our "Hello World!" program has one Java class,
callingPLI.java
. Our native method, written in PL/I, is contained in
hiFromPLI.pli
. Here is a brief overview of the steps for creating this sample program:
1.
Write a Java program that defines a class containing a native method, loads the native load library, and calls the native method.
2.
Compile the Java program to create a Java class.
3.
Write a PL/I program that implements the native method and displays the
"Hello!" text.
4.
Compile and link the PL/I program.
5.
Run the Java program which calls the native method in the PL/I program.
Step 1: Writing the Java Program
Declare the Native Method
All methods, whether Java methods or native methods, must be declared within a
Java class. The only difference in the declaration of a Java method and a native method is the keyword
native
. The
native
keyword tells Java that the implementation of this method will be found in a native library that will be loaded during the execution of the program. The declaration of our native method looks like this: public native void callToPLI();
In the above statement, the
void
means that there is no return value expected from this native method call. The empty parentheses in the method name
callToPLI( )
, means that there are no parameters being passed on the call to the native method.
Load the Native Library
A step that loads the native library must be included so the native library will be loaded at execution time. The Java statement that loads the native library looks like this: static {
System.loadLibrary("hiFromPLI");
}
In the above statement, the Java System method
System.loadLibrary(...)
is called to find and load the dynamic link library (DLL). The PL/I dynamic link library,
hiFromPLI.dll
, will be created during the step that compiles and links the PL/I program.
Write the Java Main Method
The
callingPLI
class also includes a
main
method to instantiate the class and call the native method. The
main
method instantiates
callingPLI
and calls the
callToPLI()
native method.
The complete definition of the
callingPLI
class, including all the points addressed above in this section, looks like this:
420
PL/I for Windows Programming Guide
public class callingPLI { public native void callToPLI(); static {
System.loadLibrary("hiFromPLI");
} public static void main(String[] argv) { callingPLI callPLI = new callingPLI(); callPLI.callToPLI();
System.out.println("And Hello from Java, too!");
}
}
Step 2: Compiling the Java Program
Use the Java compiler to compile the
callingPLI
class into an executable form. The command would look like this: javac callingPLI.java
Step 3: Writing the PL/I Program
The PL/I implementation of the native method looks much like any other PL/I subroutine.
Useful PL/I Compiler Options
The sample program contains a series of
*PROCESS
statements that define the important compiler options.
*Process Limits( Extname( 31 ) ) Margins( 1, 100 ) ;
*Process Dllinit xinfo(def);
*Process Default( IEEE );
Here is a brief description of them and why they are useful:
Extname(31)
Allows for longer, Java style, external names.
Margins(1,100)
Extending the margins gives you more room for Java style names and identifiers.
Dllinit
Includes the initilization coded needed for creating a DLL.
xinfo(def)
Instructs the compiler to build a *.DEF file to be used in the creation of the
DLL.
Default( IEEE );
IEEE
specifies that FLOAT data is held in IEEE format - the form in which it is held by JAVA
Correct Form of PL/I Procedure Name and Procedure Statement
The PL/I procedure name must conform to the Java naming convention in order to be located by the Java Class Loader at execution time. The Java naming scheme consists of three parts. The first part identifies the routine to the Java environment, the second part is the name of the Java class that defines the native method, and the third part is the name of the native method itself.
Here is a breakdown of the external PL/I procedure name
_Java_callingPLI_callToPLI
in the sample program:
_Java
All native methods resident in dynamic libraries must begin with
_Java
Chapter 23. Interfacing with Java
421
_callingPLI
The name of the Java class that declares the native method
_callToPLI
The name of the native method itself.
Note:
There is an important difference between coding a native method in PL/I and in C. The
javah
tool, which is shipped with the JDK, generates the form of the external references required for C programs. When you write your native methods in PL/I and follow the rules above for naming your PL/I external references, performing the
javah
step is not necessary for PL/I native methods.
The complete procedure statement for the sample program looks like this:
Java_callingPLI_callToPLI:
Proc( JNIEnv , MyJObject )
External( "_Java_callingPLI_callToPLI" )
Options( NoDescriptor ByValue linkage(stdcall) );
JNI Include File
The PL/I include file which contains the PL/I definition of the Java interfaces is contained in two include files,
jni.cpy
which in turn includes
jni_md.cpy
. These include files are included with this statement:
%include jni;
For a complete listing of the
jni.cpy
file look in the
\ibmpliw\include
directory
The Complete PL/I Procedure
For completeness, here is the entire PL/I program that defines the native method:
*Process Limits( Extname( 31 ) ) Margins( 1, 100 ) ;
*Process Dllinit xinfo(def);
*Process Default( IEEE );
PliJava_Demo: Package Exports(*);
Java_callingPLI_callToPLI:
Proc( JNIEnv , MyJObject )
External( "Java_callingPLI_callToPLI" )
Options( NoDescriptor ByValue linkage(stdcall) );
%include jni;
Display(’Hello from PL/I for Windows!’);
End;
Step 4: Compiling and Linking the PL/I Program
Compiling the PL/I Program
Compile the PL/I sample program with the following command: pli hiFromPLI.pli
Linking the Dynamic Link Library
Link the resulting PL/I object deck into a DLL with these commands: ilib /nologo /geni hiFromPLI.def
ilink /dll hiFromPLI.obj hiFromPLI.exp
422
PL/I for Windows Programming Guide
Step 5: Running the Sample Program
Run the Java - PL/I sample program with this command: java callingPLI
The output of the sample program will look like this:
Hello from PL/I for Windows!
And Hello from Java, too!
The first line written from the PL/I native method. The second line is from the calling Java class after returning from the PL/I native method call.
JNI Sample Program #2 - Passing a String
This sample program passes a string back and forth between Java and PL/I. Refer
to Figure 30 on page 424 for the complete listing of the
jPassString.java
program.
The Java portion has one Java class,
jPassString.java
. Our native method, written in
PL/I, is contained in
passString.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.
Step 1: Writing the Java Program
Declare the Native Method
The native method for this sample program looks like this: public native void pliShowString();
Load the Native Library
The Java statement that loads the native library for this sample program looks like this: static {
System.loadLibrary("passString");
}
Write the Java Main Method
The
jPassString
class also includes a
main
method to instantiate the class and call the native method. The
main
method instantiates
jPassString
and calls the
pliShowString()
native method.
This sample program prompts the user for a string and reads that value in from the command line. This is done within a
try/catch
statement as shown in Figure 30 on page 424.
Chapter 23. Interfacing with Java
423
// Read a string, call PL/I, display new string upon return import java.io.*; public class jPassString{
*/ /* Field to hold Java string
String myString;
/* Load the PL/I native library static {
System.loadLibrary("passString");
}
/* Declare the PL/I native method public native void pliShowString();
*/
*/
}
}
/* Main Java class public static void main(String[] arg) {
System.out.println(" ");
/* Instantiate Java class and initilize string jPassString myPassString = new jPassString(); myPassString.myString = " ";
/* Prompt user for a string try {
BufferedReader in = new BufferedReader( new InputStreamReader(System.in));
*/
*/
*/
/* Process until ’quit’ received */ while (!myPassString.myString.equalsIgnoreCase("quit")) {
System.out.println(
"From Java: Enter a string or ’quit’ to quit.");
System.out.print("Java Prompt > ");
/* Get string from command line */ myPassString.myString = in.readLine(); if (!myPassString.myString.equalsIgnoreCase("quit"))
{
/* Call PL/I native method */ myPassString.pliShowString();
/* Return from PL/I and display new string */
System.out.println(" ");
System.out.println(
"From Java: String set by PL/I is: "
+ myPassString.myString );
}
}
} catch (IOException e) {
}
Figure 30. Java Sample Program #2 - Passing a String
Step 2: Compiling the Java Program
The command to compile the Java code would look like this: javac jPassString.java
424
PL/I for Windows Programming Guide
Step 3: Writing the PL/I Program
All of the information about writing the PL/I "Hello World" sample program applies to this program as well.
Correct Form of PL/I Procedure Name and Procedure Statement
The external PL/I procedure name for this program would be
_Java_jPassString_pliShowString
.
The complete procedure statement for the sample program looks like this:
Java_jPassString_pliShowString:
Proc( JNIEnv , myjobject ) external( "_Java_jPassString_pliShowString" ) options( byvalue nodescriptor linkage(stdcall) );
JNI Include File
The PL/I include file which contains the PL/I definition of the Java interfaces is contained in two include files,
jni.cpy
which in turn includes
jni_md.cpy
. These include files are included with this statement:
%include jni;
For a complete listing of the
jni.cpy
file look in the
\ibmpliw\include
directory
The Complete PL/I Procedure
The complete PL/I program is shown in Figure 31 on page 426. 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 string field in the Java object that we are interested in. This Java field is further identified by providing the name of the field,
myString
, and the JNI field descriptor,
Ljava/lang/String;
, which identifies the field as a Java String field. The value of the Java string field is then retrieved using the
GetObjectField
JNI function. Before PL/I can use the Java string value, it must be unpacked into a form that PL/I can understand. The
GetStringUTFChars
JNI function is used to convert the Java string into a PL/I varyingz string which is then displayed by the PL/I program.
After displaying the retrieved Java string, the PL/I program prompts the user for a
PL/I string to be used to update the string field in the calling Java object. The
PL/I string value is converted to a Java string using the
NewString
JNI function.
This new Java string is then used to update the string field in the calling Java object using the
SetObjectField
JNI function.
When the PL/I program ends control is returned to Java, where the newly updated
Java string is displayed by the Java program.
Chapter 23. Interfacing with Java
425
*Process Limits( Extname( 31 ) ) Margins( 1, 100 ) ;
*Process Dllinit xinfo(def);
*Process Default( IEEE ); plijava_demo: package exports(*);
Java_passString_pliShowString:
Proc( JNIEnv , myJObject ) external( "_Java_jPassString_pliShowString" ) options( byvalue nodescriptor linkage(stdcall) );
%include jni;
Dcl myBool
Dcl myClazz
Dcl myFID
Dcl myJObject
Dcl myJString
Dcl newJString
Dcl myID
Dcl mySig
Dcl pliStr
Dcl pliReply
Dcl pliStrPtr
Dcl nullPtr
Type jBoolean;
Type jClass;
Type jFieldID;
Type jObject;
Type jString;
Type jString;
Char(9) Varz static init( ’myString’ );
Char(18) Varz static init( ’Ljava/lang/String;’ );
Char(132) Varz Based(pliStrPtr);
Char(132) Varz;
Pointer;
Pointer;
Display(’ ’);
/* Get information about the calling Class myClazz = GetObjectClass(JNIEnv, myJObject);
*/
/* Get Field ID for String field from Java myFID = GetFieldID(JNIEnv, myClazz, myID, mySig );
*/
/* Get the Java String in the string field myJString = GetObjectField(JNIEnv, myJObject, myFID );
*/
/* Convert the Java String to a PL/I string */ pliStrPtr = GetStringUTFChars(JNIEnv, myJString, myBool );
Display(’From PLI: String retrieved from Java is: ’ || pliStr );
Display(’From PLI: Enter a string to be returned to Java:’ ) reply(pliReply);
/* Convert the new PL/I string to a Java String */ newJString = NewString(JNIEnv, trim(pliReply), length(pliReply) );
/* Change the Java String field to the new string value */ nullPtr = SetObjectField(JNIEnv, myJObject, myFID, newJString);
End; end;
Figure 31. PL/I Sample Program #2 - Passing a String
Step 4: Compiling and Linking the PL/I Program
Compiling the PL/I Program
Compile the PL/I sample program with the following command: pli passString.pli
426
PL/I for Windows Programming Guide
Linking the Dynamic Link Library
Link the resulting PL/I object deck into a DLL with these commands: ilib /nologo /geni passString.def
ilink /dll passString.obj passString.exp
Step 5: Running the Sample Program
Run the Java - PL/I sample program with this command: java jPassString
The output of the sample program, complete with the prompts for user input from both Java and PL/I, will look like this:
>java jPassString
From Java: Enter a string or ’quit’ to quit.
Java Prompt >
A string entered in Java
From PLI: String retrieved from Java is: A string entered in Java
From PLI: Enter a string to be returned to Java:
A string entered in PL/I
From Java: String set by PL/I is: A string entered in PL/I
From Java: Enter a string or ’quit’ to quit.
Java Prompt > quit
>
JNI Sample Program #3 - Passing an Integer
This sample program passes an integer back and forth between Java and PL/I.
Refer to Figure 32 on page 428 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.
Step 1: Writing the Java Program
Declare the Native Method
The native method for this sample program looks like this: public native void pliShowInt();
Load the Native Library
The Java statement that loads the native library for this sample program looks like this: static {
System.loadLibrary("passInt");
}
Write the Java Main Method
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 32 on page 428.
Chapter 23. Interfacing with Java
427
// 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 initilize 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) {
/* Say something bad happened */
System.out.println("Something bad happened... ");
}
Figure 32. Java Sample Program #3 - Passing an Integer
428
PL/I for Windows Programming Guide
Step 2: Compiling the Java Program
The command to compile the Java code would look like this: javac jPassInt.java
Step 3: Writing the PL/I Program
All of the information about writing the PL/I "Hello World" sample program applies to this program as well.
Correct Form of PL/I Procedure Name and Procedure Statement
The external 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( byvalue nodescriptor linkage(stdcall) );
JNI Include File
The PL/I include file which contains the PL/I definition of the Java interfaces is contained in two include files,
jni.cpy
which in turn includes
jni_md.cpy
. These include files are included with this statement:
%include jni;
For a complete listing of the
jni.cpy
file look in the
\ibmpliw\include
directory
The Complete PL/I Procedure
The complete PL/I program is shown in Figure 33 on page 430. 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.
Chapter 23. Interfacing with Java
429
*Process Limits( Extname( 31 ) ) Margins( 1, 100 ) ;
*Process Dllinit xinfo(def);
*Process Default( IEEE ); plijava_demo: package exports(*);
Java_passNum_pliShowInt:
Proc( JNIEnv , myjobject ) external( "_Java_jPassInt_pliShowInt" ) options( byvalue nodescriptor linkage(stdcall) );
%include jni;
Dcl myClazz
Dcl myFID
Dcl myJInt dcl rtnJInt
Dcl myJObject
Dcl pliReply
Dcl nullPtr
Display(’ ’);
Type jClass;
Type jFieldID;
Type jInt;
Type jInt;
Type jObject;
Char(132) Varz;
Pointer;
/* 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;
Figure 33. PL/I Sample Program #3 - Passing an Integer
Step 4: Compiling and Linking the PL/I Program
Compiling the PL/I Program
Compile the PL/I sample program with the following command: pli passInt.pli
Linking the Dynamic Link Library
Link the resulting PL/I object deck into a DLL with these commands: ilib /nologo /geni passInt.def
ilink /dll passInt.obj passInt.exp
430
PL/I for Windows Programming Guide
Step 5: Running the Sample Program
Run the Java - PL/I sample program with this command: java jPassInt
The output of the sample program, complete with the prompts for user input from both Java and PL/I, will look like this:
>java jPassInt
From Java: Enter an Integer or ’quit’ to quit.
Java Prompt > 12345
From PLI: Integer retrieved from Java is: 12345
From PLI: Enter an integer to be returned to Java:
54321
From Java: Integer set by PL/I is: 54321
From Java: Enter an Integer or ’quit’ to quit.
Java Prompt > quit
>
Determining equivalent Java and PL/I data types
When you communicate with Java from PL/I you will need to match the data types between the two programming languages. This table shows Java primitive types and their PL/I equivalents:
Table 30. Java Primitive Types and PL/I Native Equivalents
Java Type
boolean byte char short int long float double void
PL/I Type
jboolean jbyte jchar jshort jint jlong jfloat jdouble jvoid
Size in Bits
32
64
21
53 n/a
8, unsigned
8
16, unsigned
16
Chapter 23. Interfacing with Java
431
432
PL/I for Windows Programming Guide
Скачать
Реклама