Page 1 of 1
Setting up JNI for calling Java from COBOL on z/OS
Posted: Wed Nov 15, 2023 9:57 pm
by danik1956
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 ?
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Thu Nov 16, 2023 5:28 am
by zum13
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.
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Thu Nov 16, 2023 10:52 pm
by DB2 Guy
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:
Code: Select all
mount -V cifs -o username=<your_username>,password=<your_password> //your_zos_system/usr/lpp/cobol /u/lpp/cobol
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)
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Thu Nov 16, 2023 10:55 pm
by danik1956
Thanks. I found the relevant ZFS file at "IGY630.ZFS" and mounted it as /usr/lpp/cobol (read-only)
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Sat Nov 18, 2023 12:33 am
by Anuj Dhawan
Thanks for sharing what worked for you, appreciate it.
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Mon Nov 20, 2023 9:00 pm
by danik1956
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 ?
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Tue Nov 21, 2023 8:58 am
by zum13
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
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Thu Nov 23, 2023 3:58 pm
by DB2 Guy
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.
- Generate Header File:
Use the javah command to generate the header file for the Java class:
This will generate a HelloWorld.h file.
- 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.
This is a basic example, and in a real-world scenario, you would need to handle errors, manage memory, and possibly pass parameters between COBOL and Java. Additionally, ensure that your COBOL environment is set up correctly for 64-bit execution and JNI usage.
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Thu Nov 23, 2023 4:26 pm
by danik1956
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 ?
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Thu Nov 23, 2023 5:25 pm
by DB2 Guy
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:
Code: Select all
cobc -o YourProgram -L/path/to/java/library -ljvm YourProgram.cbl
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.
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Sun Nov 26, 2023 1:16 pm
by danik1956
"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 ?
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Mon Nov 27, 2023 3:11 am
by zum13
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:
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)
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.
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Mon Nov 27, 2023 6:12 pm
by Anuj Dhawan
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:
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
...
/*
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.
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Fri Dec 29, 2023 12:24 pm
by danik1956
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.
Re: Setting up JNI for calling Java from COBOL on z/OS
Posted: Fri Dec 29, 2023 8:11 pm
by zum13
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?