Setting up JNI for calling Java from COBOL on z/OS
Setting up JNI for calling Java from COBOL on z/OS
I have been looking at the following IBM sample program:
https://www.ibm.com/docs/en/cobol-zos/6 ... ol-program
To compile the sample program there is a required COPY named JNI.
JNI.cpy is in the z/OS® UNIX file system in the include subdirectory of the COBOL install directory (typically /usr/lpp/cobol/include).
What USS file system should be mounted to have access to this JNI source file ?
https://www.ibm.com/docs/en/cobol-zos/6 ... ol-program
To compile the sample program there is a required COPY named JNI.
JNI.cpy is in the z/OS® UNIX file system in the include subdirectory of the COBOL install directory (typically /usr/lpp/cobol/include).
What USS file system should be mounted to have access to this JNI source file ?
Re: Setting up JNI for calling Java from COBOL on z/OS
Hello.
I believe the IBM suggested default is "IGYvrm.HFS", but that may not necessarily be where it is on your local installation. You'll need your friendly local sysprogs to mount it if it's not already there, plus I'd suggest that it also needs to be added to the "BPXPRMxx" member in the parmlib so that it's automatically mounted after an IPL.
I believe the IBM suggested default is "IGYvrm.HFS", but that may not necessarily be where it is on your local installation. You'll need your friendly local sysprogs to mount it if it's not already there, plus I'd suggest that it also needs to be added to the "BPXPRMxx" member in the parmlib so that it's automatically mounted after an IPL.
Re: Setting up JNI for calling Java from COBOL on z/OS
To have access to the JNI source file located in the z/OS UNIX System Services (USS) file system at /usr/lpp/cobol/include, you need to mount the USS file system that corresponds to the path /usr/lpp/cobol. In z/OS, USS file systems are typically mounted under the /u directory.
Therefore, you should mount the USS file system for /usr/lpp/cobol to the appropriate directory under /u. The specific mount point depends on your system configuration, but it could be something like /u/lpp/cobol or a similar path. Once the file system is mounted, you should be able to access the JNI source file at the specified path.
Here's a general example of how you might mount the file system:
Replace <your_username> and <your_password> with your actual credentials, and adjust the mount point (/u/lpp/cobol) based on your system's configuration.
After the mount is successful, you should be able to navigate to /u/lpp/cobol/include and access the JNI source file (JNI.cpy)
Therefore, you should mount the USS file system for /usr/lpp/cobol to the appropriate directory under /u. The specific mount point depends on your system configuration, but it could be something like /u/lpp/cobol or a similar path. Once the file system is mounted, you should be able to access the JNI source file at the specified path.
Here's a general example of how you might mount the file system:
Code: Select all
mount -V cifs -o username=<your_username>,password=<your_password> //your_zos_system/usr/lpp/cobol /u/lpp/cobol
After the mount is successful, you should be able to navigate to /u/lpp/cobol/include and access the JNI source file (JNI.cpy)
Re: Setting up JNI for calling Java from COBOL on z/OS
Thanks. I found the relevant ZFS file at "IGY630.ZFS" and mounted it as /usr/lpp/cobol (read-only)
- Anuj Dhawan
- Founder
- Posts: 2816
- Joined: Sun Apr 21, 2013 7:40 pm
- Location: Mumbai, India
- Contact:
Re: Setting up JNI for calling Java from COBOL on z/OS
Thanks for sharing what worked for you, appreciate it.
Thanks,
Anuj
Disclaimer: My comments on this website are my own and do not represent the opinions or suggestions of any other person or business entity, in any way.
Anuj
Disclaimer: My comments on this website are my own and do not represent the opinions or suggestions of any other person or business entity, in any way.
Re: Setting up JNI for calling Java from COBOL on z/OS
One more question related to using JNI with native COBOL on z/OS.
The IBM COBOL version 6.3 doc states that a 64-bit COBOL program can only call Java using JNI and not via INVOKE.
Can someone point me at some example for using JNI to call Java from a COBOL batch program compiled with LP(64) option ?
The IBM COBOL version 6.3 doc states that a 64-bit COBOL program can only call Java using JNI and not via INVOKE.
Can someone point me at some example for using JNI to call Java from a COBOL batch program compiled with LP(64) option ?
Re: Setting up JNI for calling Java from COBOL on z/OS
I'll admit that the last time I dabbled with COBOL and Java together, the COBOL compiler hadn't been updated to support 64 bits! It appears that the COBOL to JNI interface has yet to receive an update.
I've not seen any examples of how to call Java methods directly using the JNI services from COBOL, but there shouldn't be a problem finding in C/C++ examples which show how it's done (they don't have to be mainframe-specific). For instance, this page has an example in section 4.2 which shows the technique for making a method call:
https://www.baeldung.com/jni
There's also the JNI specification which lists the API functions including a number concerned with the calling of Java methods all of which appear to be listed in the JNI.cpy file. It should just be a matter of adjusting the calling syntax for COBOL.
https://docs.oracle.com/en/java/javase/ ... ce-methods
I've not seen any examples of how to call Java methods directly using the JNI services from COBOL, but there shouldn't be a problem finding in C/C++ examples which show how it's done (they don't have to be mainframe-specific). For instance, this page has an example in section 4.2 which shows the technique for making a method call:
https://www.baeldung.com/jni
There's also the JNI specification which lists the API functions including a number concerned with the calling of Java methods all of which appear to be listed in the JNI.cpy file. It should just be a matter of adjusting the calling syntax for COBOL.
https://docs.oracle.com/en/java/javase/ ... ce-methods
Re: Setting up JNI for calling Java from COBOL on z/OS
Calling Java from COBOL on z/OS using JNI involves several steps. Below is a high-level outline of the process, and I'll also provide a simple example:
- Write the Java Class:
Create a simple Java class that you want to call from COBOL. Save it as a .java file. For example:
Code: Select all
// HelloWorld.java public class HelloWorld { public static void sayHello() { System.out.println("Hello from Java!"); } }
- Compile the Java Class:
Compile the Java class using the javac command:
This will generate a HelloWorld.class file.Code: Select all
javac HelloWorld.java
- Generate Header File:
Use the javah command to generate the header file for the Java class:
This will generate a HelloWorld.h file.Code: Select all
javah HelloWorld
- Write COBOL Program:
Write a COBOL program that includes the generated header file and calls the Java method using JNI. Here is a simple example:
Code: Select all
IDENTIFICATION DIVISION. PROGRAM-ID. HelloWorldCOBOL. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. 01 JAVA-ENVIRONMENT POINTER. 01 JAVA-CLASS POINTER. 01 METHOD-ID POINTER. LINKAGE SECTION. 01 RETURN-CODE PIC S9(9) COMP. PROCEDURE DIVISION USING RETURN-CODE. CALL 'JNI_CreateJavaVM' USING BY REFERENCE JAVA-ENVIRONMENT BY VALUE 0 BY REFERENCE 0. CALL 'JNI_FindClass' USING BY REFERENCE JAVA-ENVIRONMENT BY DESCRIPTOR 'HelloWorld' RETURNING JAVA-CLASS. CALL 'JNI_GetStaticMethodID' USING BY REFERENCE JAVA-ENVIRONMENT BY REFERENCE METHOD-ID BY REFERENCE JAVA-CLASS BY DESCRIPTOR 'sayHello()V'. CALL 'JNI_CallStaticVoidMethod' USING BY REFERENCE JAVA-ENVIRONMENT BY REFERENCE JAVA-CLASS BY REFERENCE METHOD-ID. CALL 'JNI_DestroyJavaVM' USING BY REFERENCE JAVA-ENVIRONMENT. EXIT PROGRAM. END PROGRAM HelloWorldCOBOL.
This example assumes that the JVM is initialized, the Java class is found, and the method is called using JNI. - Compile COBOL Program:
Compile the COBOL program using the 64-bit compiler options:
Code: Select all
cob2 -x -C LP(64) HelloWorldCOBOL.cbl
- Run COBOL Program:
Run the compiled COBOL program. Ensure that the Java class (HelloWorld.class) is in the classpath.
Code: Select all
./HelloWorldCOBOL
Re: Setting up JNI for calling Java from COBOL on z/OS
Thanks for the detailed response.
One question relating to binding the COBOL program with the required JNI callable services.
What should be included in the BIND step so that external names like 'JNI_CreateJavaVM' would get resolved ?
One question relating to binding the COBOL program with the required JNI callable services.
What should be included in the BIND step so that external names like 'JNI_CreateJavaVM' would get resolved ?
Re: Setting up JNI for calling Java from COBOL on z/OS
When you are binding a COBOL program that calls external functions like JNI_CreateJavaVM (Java Native Interface) from a shared library or DLL (Dynamic Link Library), you need to provide the necessary information for the linker to resolve these external names. This typically involves specifying the library or DLL that contains the implementation of the JNI functions.
Here is an example of what the BIND step might look like in a typical scenario. Note that the exact details can depend on your platform and toolchain:
Explanation:
-o YourProgram: Specifies the output executable name.
-L/path/to/java/library: Informs the linker where to find the Java library or DLL. You should replace /path/to/java/library with the actual path on your system.
-ljvm: Specifies the name of the library to link against. In this case, it's assumed that libjvm.so (on Unix-like systems) or jvm.dll (on Windows) is the library containing JNI functions.
Keep in mind that the specifics can vary based on your COBOL compiler and the platform you are working on. The above example assumes a Unix-like environment; for Windows, you might need to use a different syntax and possibly different libraries.
Also, make sure that the Java library containing the JNI functions is in the system library path or provide the full path to the library. Additionally, if there are other dependencies, you might need to include them in the BIND step.
Consult your COBOL compiler documentation for platform-specific details on linking external libraries.
Here is an example of what the BIND step might look like in a typical scenario. Note that the exact details can depend on your platform and toolchain:
Code: Select all
cobc -o YourProgram -L/path/to/java/library -ljvm YourProgram.cbl
-o YourProgram: Specifies the output executable name.
-L/path/to/java/library: Informs the linker where to find the Java library or DLL. You should replace /path/to/java/library with the actual path on your system.
-ljvm: Specifies the name of the library to link against. In this case, it's assumed that libjvm.so (on Unix-like systems) or jvm.dll (on Windows) is the library containing JNI functions.
Keep in mind that the specifics can vary based on your COBOL compiler and the platform you are working on. The above example assumes a Unix-like environment; for Windows, you might need to use a different syntax and possibly different libraries.
Also, make sure that the Java library containing the JNI functions is in the system library path or provide the full path to the library. Additionally, if there are other dependencies, you might need to include them in the BIND step.
Consult your COBOL compiler documentation for platform-specific details on linking external libraries.
Re: Setting up JNI for calling Java from COBOL on z/OS
"When you are binding a COBOL program that calls external functions like JNI_CreateJavaVM (Java Native Interface) from a shared library or DLL (Dynamic Link Library), you need to provide the necessary information for the linker to resolve these external names. This typically involves specifying the library or DLL that contains the implementation of the JNI functions."
This is exactly what I am trying to understand. On z/OS (not USS) when linking a COBOL program that is using JNI functions, where are these JNI extearnal names resolved from ?
This is exactly what I am trying to understand. On z/OS (not USS) when linking a COBOL program that is using JNI functions, where are these JNI extearnal names resolved from ?
Re: Setting up JNI for calling Java from COBOL on z/OS
The linkage editor can read from USS, it's just a matter of providing the appropriate "INCLUDE" statements. I've managed to dig out a rather old example of linking a JNI program from my brief period of tinkering with it several years ago:
According to the docs, "igzcjava.x" should still be where it's specified above. The location of "libjvm.x" will depend upon which version of Java you are using.
Code: Select all
INCLUDE NCAL(TESTPROG)
INCLUDE '/usr/lpp/java/IBM/J1.3/bin/classic/libjvm.x'
INCLUDE '/usr/lpp/cobol/lib/igzcjava.x'
NAME TESTPROG(R)
- Anuj Dhawan
- Founder
- Posts: 2816
- Joined: Sun Apr 21, 2013 7:40 pm
- Location: Mumbai, India
- Contact:
Re: Setting up JNI for calling Java from COBOL on z/OS
On z/OS, when linking a COBOL program that calls external functions like JNI_CreateJavaVM from a shared library or DLL, the resolution of these JNI external names is typically handled through the linkage editor, which is responsible for combining object modules and resolving external references.
In z/OS, the linkage editor resolves external names by searching specified libraries or explicitly provided modules in the link-edit JCL (Job Control Language). When you bind a COBOL program that uses JNI functions, you need to ensure that the JNI library or DLL containing the implementation of the JNI functions is included in the link-edit process.
As zum13 said, You specify the necessary information for the linker in the link-edit JCL by providing a library or DLL as input to the linkage editor. This can be done using statements like INCLUDE or LIB in the JCL to specify the libraries to be searched for unresolved external references.
Here's a simplified example of what the link-edit JCL might look like:
In the above example, COBOL_PROGRAM is the entry point of your COBOL program, and JNI_LIBRARY is the library or DLL that contains the implementation of the JNI functions. The INCLUDE statement ensures that the JNI functions are resolved during the link-edit process.
Make sure to replace placeholders like COBOL_PROGRAM and JNI_LIBRARY with the actual names used in your environment.
In z/OS, the linkage editor resolves external names by searching specified libraries or explicitly provided modules in the link-edit JCL (Job Control Language). When you bind a COBOL program that uses JNI functions, you need to ensure that the JNI library or DLL containing the implementation of the JNI functions is included in the link-edit process.
As zum13 said, You specify the necessary information for the linker in the link-edit JCL by providing a library or DLL as input to the linkage editor. This can be done using statements like INCLUDE or LIB in the JCL to specify the libraries to be searched for unresolved external references.
Here's a simplified example of what the link-edit JCL might look like:
Code: Select all
//LINKJOB JOB ...
//STEP1 EXEC PGM=IEWL
//SYSLST DD SYSOUT=A
//SYSUT1 DD *
//COBOL OBJECT MODULES
//SYSUT2 DD *
//ADDITIONAL OBJECT MODULES
//SYSUT3 DD *
//JNI LIBRARY OR DLL
//SYSIN DD *
ENTRY COBOL_PROGRAM
INCLUDE JNI_LIBRARY
...
/*
Make sure to replace placeholders like COBOL_PROGRAM and JNI_LIBRARY with the actual names used in your environment.
Thanks,
Anuj
Disclaimer: My comments on this website are my own and do not represent the opinions or suggestions of any other person or business entity, in any way.
Anuj
Disclaimer: My comments on this website are my own and do not represent the opinions or suggestions of any other person or business entity, in any way.
Re: Setting up JNI for calling Java from COBOL on z/OS
Here is the JCL we have used to compile & bind a COBOL program that invokes JNI services:
//RUN EXEC IGYQCB,LIBPRFX=CEE,LIBPRF1=CEE,
// PGMLIB='YOSI.TEST.LIB',GOPGM=HLWRLD64
//COBOL.SYSIN DD DSN=Z2V10.SAMP.LIB(CBLB#JNI),DISP=SHR
//COBOL.SYSLIB DD DSN=Z2V10.SAMP.LIB,DISP=SHR
// DD DSN=DANI.SOURCE.LIB,DISP=SHR
//COBOL.SYSLIN DD DSNAME=&&OBJECT(HLWRLD64),
// DISP=(NEW,PASS),SPACE=(CYL,(1,1,1)),DCB=(LRECL=80,RECFM=FB)
//BIND.OBJMOD DD DSN=&&OBJECT,DISP=(OLD,DELETE)
//BIND.SYSLIN DD *
INCLUDE OBJMOD(HLWRLD64)
INCLUDE '/usr/lpp/java/J8.08.15/J8.0_64/bin/j9vm/libjvm.x'
INCLUDE '/usr/lpp/IBM/cobol/igyv6r3/lib/igzcjava.x'
//
The result:
-STEPNAME PROCSTEP RC
-RUN COBOL 00
-RUN BIND 00
Compiler options used: cbl dll,lp(64),rent,pgmname(longmixed)
First JNI call is successfull:
CALL "JNI_CreateJavaVM"
USING JVM-PTR ENV-PTR VM-INIT-ARGS
RETURNING INTO RC2.
RETURNING RC2.
DISPLAY "rc2 " RC2 " " JVM-PTR " " ENV-PTR
IF RC2 NOT = 0
GOBACK
END-IF
The problem we have is related to the 2ed JNI call:
CALL FindClass USING BY VALUE ENV-PTR
CLASS-NAME-PTR
RETURNING MY-CLASS-REF.
DISPLAY "PNT1B"
DISPLAY "1." MY-CLASS-REF.
IF MY-CLASS-REF = 0
GOBACK
END-IF
This call returns null value although the requested java class exists as a jar file in the folder pointed by env
variable CLASSPATH.
There is nothing in STDOUT & STDERR datasets.
My question is how to turn on some tracing options so we can see why the FindClass JNI call is failing.
//RUN EXEC IGYQCB,LIBPRFX=CEE,LIBPRF1=CEE,
// PGMLIB='YOSI.TEST.LIB',GOPGM=HLWRLD64
//COBOL.SYSIN DD DSN=Z2V10.SAMP.LIB(CBLB#JNI),DISP=SHR
//COBOL.SYSLIB DD DSN=Z2V10.SAMP.LIB,DISP=SHR
// DD DSN=DANI.SOURCE.LIB,DISP=SHR
//COBOL.SYSLIN DD DSNAME=&&OBJECT(HLWRLD64),
// DISP=(NEW,PASS),SPACE=(CYL,(1,1,1)),DCB=(LRECL=80,RECFM=FB)
//BIND.OBJMOD DD DSN=&&OBJECT,DISP=(OLD,DELETE)
//BIND.SYSLIN DD *
INCLUDE OBJMOD(HLWRLD64)
INCLUDE '/usr/lpp/java/J8.08.15/J8.0_64/bin/j9vm/libjvm.x'
INCLUDE '/usr/lpp/IBM/cobol/igyv6r3/lib/igzcjava.x'
//
The result:
-STEPNAME PROCSTEP RC
-RUN COBOL 00
-RUN BIND 00
Compiler options used: cbl dll,lp(64),rent,pgmname(longmixed)
First JNI call is successfull:
CALL "JNI_CreateJavaVM"
USING JVM-PTR ENV-PTR VM-INIT-ARGS
RETURNING INTO RC2.
RETURNING RC2.
DISPLAY "rc2 " RC2 " " JVM-PTR " " ENV-PTR
IF RC2 NOT = 0
GOBACK
END-IF
The problem we have is related to the 2ed JNI call:
CALL FindClass USING BY VALUE ENV-PTR
CLASS-NAME-PTR
RETURNING MY-CLASS-REF.
DISPLAY "PNT1B"
DISPLAY "1." MY-CLASS-REF.
IF MY-CLASS-REF = 0
GOBACK
END-IF
This call returns null value although the requested java class exists as a jar file in the folder pointed by env
variable CLASSPATH.
There is nothing in STDOUT & STDERR datasets.
My question is how to turn on some tracing options so we can see why the FindClass JNI call is failing.
Re: Setting up JNI for calling Java from COBOL on z/OS
The "FindClass" function does return an exception, but you need to explicitly call the exception's "printStackTrace" method in order to get the output for it. However, first things first; what does your working storage look like?
Create an account or sign in to join the discussion
You need to be a member in order to post a reply
Create an account
Not a member? register to join our community
Members can start their own topics & subscribe to topics
It’s free and only takes a minute