General Page
Enterprise COBOL
Enterprise COBOL introduced the concept of Object-Oriented (OO) COBOL that simplifies the interactions between Java and COBOL. Using OO COBOL is a convenient way to create OO applications, in particular when crossing the boundary between Java and COBOL is required.
NEW! Enterprise COBOL 6.4 and later compilers support a COBOL/Java interoperability framework that does not depend on OO COBOL. The goals of the new framework include making existing COBOL programs easily callable from Java with minimal changes, supporting calls to static Java methods from COBOL using simple CALL statements, making COBOL data items easily accessible for read/write access from Java, and providing comprehensive support for automatic conversions between Java and COBOL data formats, which helps to reduce, and often eliminate, the need to make any JNI calls directly from COBOL code.
For more details on the non-OO COBOL/Java interoperability features of Enterprise COBOL 6.4 and later compilers, please refer to the following resources:
-
COBOL/Java interoperability outside of the object-oriented (OO) COBOL framework
-
Compiling, linking, and running non-OO COBOL applications that interoperate with Java
JNI provides the solution for two-way communications.
- It defines a method for Java to invoke native methods.
- It also defines a method, via a defined API, for native code to invoke Java code. With the defined API, the native code can manipulate Java objects, call Java methods, and share data with Java.
How JNI works
JNI provides a means for Java code to call native code. This interaction is useful in cases when native capabilities are more efficient than Java or when the specific code is already available in native and you want to use it. JNI provides JNI services (also referred as functions) via the JNI API to act on the Java data and use Java features.
The JNI also provides the native code with means to embed a JVM in the native code and to access Java features without having to link with the JVM.
JNI services and API
JNI provides many services for the native code to access Java features, such as class operations, calling methods, string and array operations, etc. It also provides services via the Invocation API to embed a JVM in the native application.
The JNI APIs are defined under a language-specific file that holds all API functions and the type mapping for the Java JNI types. For COBOL, the APIs are defined in the JNI copybook called JNI.cpy, which is typically located under the /usr/lpp/cobol/include
directory. To use the JNI services, the JNI copybook needs to be included.
There are two main JNI structures defined in the JNI APIs that are key to the JNI execution:
Figure 1. JNI environment pointer
The JavaVM structure is accessed via an interface pointer, JavaVMPtr. This pointer points to a pointer that points to an array of JNI function pointers (a function table named JNIInvokeInterface) for accessing callable “invocation interface” functions.
Java for the z/OS platform provides an extended API to deal with strings due to the encoding differences. It defines the following extensions: NewStringPlatform, GetStringPlatformLength, GetStringPlatform.
These EBCDIC services are packaged as a dynamic link library (DLL) file that is part of the IBM® Java SDK. They are called directly and not dereferenced from the JNIEnv pointer (the JNIEnvPtr). This extended API is resolved through the libjvm.x DLL side file, provided with your IBM Java SDK, which needs to be included in the link-edit step.
Hello World: Making a simple connection
When an application starts with native code and requires to call Java features via JNI APIs, it first needs to load a JVM using the JNI API, unless it is using OO COBOL. With OO COBOL invoking Java, COBOL will start the JVM for you.
When an application starts with Java, it calls the native language via native methods.
The native methods called from Java are declared in the Java code and implemented in the native language. The name of the native method follows the JNI naming rules. In the simple case, the method would be in the format of Java_classname_methodname
. See the JNI Specification for more detailed information regarding native method names and arguments.
As part of the JNI calling convention, the native method has two hidden arguments that are not seen on the Java declaration. Those arguments are predefined by the JNI:JNIEnv interface pointer and jobject. In COBOL, the JNIEnv interface pointer is the JNIEnvPtr and it is used to dereference the JNI service. The jobject is a pointer to the class in case the class is static, or to the instance of the class if it is not static.
You can use the javah tool to generate .h header files that can be inspected for the signature of the native method generated. These header files are used by C and C++ compilers, not by the COBOL compiler, but you might find them useful for checking the naming of native methods. Although generating the .h files is optional, it has great value in providing the expected signature.
Once the native code is compiled and linked, the native methods are accessed via an executable DLL module that is loaded on the Java side. There are two ways for Java to load the executable DLL module:
- Using
System.loadLibrary(“Name”)
In this case the DLL name needs to be in the format of
libName.so
. - Using
System.load("<absolutePath>/Name")
In this case there is no restriction on the name of the library.
For proper loading and binding, the executable DLL needs to reside on the z/OS UNIX side, have the right attributes (executable) and follow naming rules.
Example 1: “Hello world” from COBOL
This Java sample code demonstrates how to invoke a native COBOL method that prints “Hello from COBOL”. The example has no parameters passed to nor no return data from the native method.
- Declare the native method in the Java code.
- Compile the Java code using
javac
to generate a.class
file. - Generate the native code.
There are two main parts that need special attention: the program-id and the procedure division’s parameters and return value. The program-id should follow the JNI rules and match the native method name as declared on the Java side. In this case, following the
Java_classname_methodname
convention, the program-id isJava_HelloTest_printHello
. The native method declared has no arguments but the COBOL procedure division declares the two ‘hidden’ arguments required for JNI, even though they are not used in the procedure (as we do not facilitate the JNI services). Note that there is no use of JNI services. Therefore the JNI copybook is not included. - Compile the COBOL code with the required options given in the example. These compilation options are described in the “Compiling and linking for COBOL” section.
- Link-edit step to generate the executable DLL module (following naming rules to allow proper loading). The required options are described in the “Compiling and linking for COBOL” section.
- Run the Java program.
If the
System.loadLibrary(“Name”)
method is used, the Java will search a file of the typelibName.so
in the library path provided via the-Djava.library.path
option. If you use theSystem.load(...)
method, the path points to the library file.
The following is a simple COBOL program that prints “Hello from COBOL “.
helloTest.cbl
helloTest.cbl
Process pgmname(longmixed),lib,dll,thread
IDENTIFICATION DIVISION.
PROGRAM-ID. "Java_HelloTest_printHello" is recursive.
ENVIRONMENT DIVISION.
DATA DIVISION.
LINKAGE SECTION.
01 ENV-PTR USAGE POINTER.
01 OBJECT-REF PIC S9(9) BINARY.
PROCEDURE DIVISION USING BY VALUE ENV-PTR
OBJECT-REF.
Display " >> Hello from COBOL ".
GOBACK.
This COBOL program is compiled and linked as follows, where a typical installation path for COBOL is /usr/lpp/cobol
and a typical installation path for Java is /usr/lpp/java
. Replace with your own paths for your environment.
/usr/lpp/cobol/bin/cob2 -c -qdll,thread helloTest.cbl
/usr/lpp/cobol/bin/cob2 -bdll -o libHello.so helloTest.o /usr/lpp/java/IBM/J7.1/bin/j9vm/libjvm.x /usr/lpp/cobol/lib/igzcjava.x helloTest.cbl
The following HelloTest.java program is compiled and run using the following USS commands:
/usr/lpp/java/IBM/J7.1/bin/javac HelloTest.java
/usr/lpp/java/IBM/J7.1/bin/java -Djava.library.path=. HelloTest
HelloTest.java
public class HelloTest
{
public native void printHello();
public static void main(String argv[]) throws Exception
{
System.loadLibrary("Hello");
HelloTest newHelloTest = new HelloTest();
newHelloTest.printHello();
return;
}
}
Connecting Java and COBOL
Enterprise COBOL provides Java-oriented capabilities in addition to the basic OO capabilities available directly in the COBOL language. For example, it allows creation of Java and COBOL classes and invocation of methods on Java and COBOL objects using the INVOKE statement. For basic Java-object capabilities, using the OO capabilities is sufficient for the Java-COBOL interoperability. For additional Java-object capabilities you need the JNI services.
To start with Java, there needs to be a ‘main’ method written. It can be written in Java or as a compiled COBOL class definition that contains a factory method called ‘main’ with the appropriate arguments.
Typically, when using OO COBOL, the easiest way for Java to invoke COBOL is via an OO COBOL ‘wrapper’ class, which calls the procedural COBOL logic and thus “wraps” it.
Since Java resides on the z/OS UNIX side, if you start with Java, all the application components (classes and executable DLL modules) must reside on the HFS. To launch Java, you can use the shell command prompt (running the java command) or with the BPXBATCH utility from JCL or TSO/E.
Working with ‘wrapper’ OO COBOL classes
A COBOL source file that contains a class definition is often the gateway between Java and COBOL
Once this COBOL source file is compiled, a Java file is generated on the USS side. This Java file contains the native method declaration based on the JNI rules. If, for example, the class had a method foo
, then the generated Java code will have a declaration of a native method named Java_classname_foo
. The generated Java code (.java
file) needs to be compiled on the USS side by using the javac
compiler to produce the .class
file.
When using OO COBOL with class definition, there are these naming rules:
- The name of the resulting DLL module needs to match the expected class name. If
ClassName
is the external class name, then the name of the DLL module must belibClassName.so
, as this is the name expected in the generated Java file (as it usesSystem.loadLibrary
method to load the DLL). - If the class is part of a package and thus there are periods in the external class name, the periods should be changed to underscores in the DLL module name (based on JNI naming rules).
Accessing JNI services
In COBOL, the JNI API is defined in the JNI copybook called JNI.cpy
. The JNI copybook contains the definition of JNINativeInterface, the COBOL group structure that maps the JNI environment structure, which contains an array of function pointers for the JNI callable services. To facilitate access to JNI services, the JNI.cpy
file needs be defined in the COBOL program under the LINKAGE SECTION. For example, if the file is named JNI:
Linkage section.
COPY “JNI”
Before you reference the contents of the JNI environment structure, you must code the following statements to establish its addressability:
Procedure division.
Set address of JNIEnv to JNIEnvPtr
Set address of JNINativeInterface to JNIEnv
The code sets the address of JNIEnv, a pointer data item that JNI.cpy provides, and JNIEnvPtr, the COBOL special register that contains the environment pointer. The JNIEnvPtr is implicitly defined as USAGE POINTER and should not be used as a receiving data item. Use this special register JNIEnvPtr to reference the JNI environment pointer to obtain the address for the JNI environment structure.
After the pointers are set, the JNI callable services can be accessed with CALL statements that reference the function pointers. The JNIEnvPtr special register is the first argument to the services that require the environment pointer, as shown in the following example:
01 InputArrayObj usage object reference jlongArray.
01 ArrayLen pic S9(9) comp-5.
. . .
Call GetArrayLength using by value JNIEnvPtr InputArrayObj
returning ArrayLen
Compiling and linking for COBOL
To compile COBOL source code that uses JNI services or contains OO syntax such as INVOKE statements or class definitions (that is, COBOL code that directly communicates with Java):
- Use the following compiler options: RENT, DLL, THREAD, and DBCS.
The RENT and DBCS options are IBM-supplied defaults. - Set PGMNAME(LONGMIXED) for long name support.
- Set the RECURSIVE attribute on COBOL classes and methods or on COBOL programs that invoke Java methods.
Compiling the COBOL with DLL affects the overall COBOL program structure. In general, DLL-linkage-built COBOL programs can only call out to other external DLL-linkage-built programs. Similarly, dynamic call built COBOL programs can only call out to other external dynamic call built programs. However, static linking of objects with either two of these external program call mechanisms is allowed. This provides the bridging between the DLL linkage that Java requires and the traditional COBOL dynamic call.
The link step creates an executable DLL module. It is required to link the object file with the following two DLL side files:
libjvm.x
, which is provided with your IBM Java SDKigzcjava.x
, which is provided in the lib/ subdirectory of the COBOL directory in the HFS. The typical complete path is/usr/lpp/cobol/lib/igzcjava.x
.
This DLL side file is also available as the member IGZCJAVA in the SCEELIB PDS (part of Language Environment).
If the application starts with a Java program or the main factory method of a COBOL class, the XPLINK environment is automatically started by the java command that starts the JVM and runs the application.
If an application starts with a COBOL program that invokes methods on COBOL or Java classes, you must specify the XPLINK(ON) runtime option so that the XPLINK environment is initialized. XPLINK(ON) is not recommended as a default setting. Use XPLINK(ON) only for applications that specifically require it.
In older versions of COBOL, using the COPY statement required the compiler option ‘lib’. This option is not required in Enterprise COBOL v5 and up, and it is always in effect.
For more information, see “Compiling, linking, and running OO applications” in the Enterprise COBOL for z/OS Programming Guide.
Java and COBOL under z/OS UNIX
When you compile, link, and run OO applications in a z/OS UNIX environment, application components reside in the HFS. The compilation and linking is done using z/OS UNIX shell commands, and application is launched via a shell command prompt or with the BPXBATCH utility from JCL or TSO/E.
For compilation use: cob2 -c -qdll,thread
For linking use: cob2 -bdll
The -bdll
option specifies that the executable module is to be a DLL. In addition:
- The COBOL compiler uses the compiler options DLL, EXPORTALL, and RENT, which are required for DLLs.
- The link step produces a DLL definition side file that contains IMPORT control statements for each of the names exported by the DLL.
You need to specify the include subdirectory of the JNI.cpy
by using the -I
option of the cob2 command or by setting the SYSLIB environment variable. The JNI.cpy
resides under the include
subdirectory of the COBOL installation directory (typically, /usr/lpp/cobol/include
).
Example: Java calling procedural COBOL
This example demonstrates Java calling procedural COBOL with JNI service calls.
The COBOL program is compiled and linked as follows, where a typical installation path for COBOL is /usr/lpp/cobol
and a typical installation path for Java is /usr/lpp/java
. Replace with your own paths for your environment.
/usr/lpp/cobol/bin/cob2 -c -qdll,thread -I /usr/lpp/cobol/include stringTest.cbl
/usr/lpp/cobol/bin/cob2 -bdll -o libStringTest.so stringTest.o /usr/lpp/java/IBM/J7.1/bin/j9vm/libjvm.x /usr/lpp/cobol/lib/igzcjava.x -I /usr/lpp/cobol/include stringTest.cbl
stringTest.cbl
Process pgmname(longmixed),lib,dll,thread
IDENTIFICATION DIVISION.
PROGRAM-ID. "Java_StringTest_printStrings" is recursive.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
INPUT-OUTPUT SECTION.
DATA DIVISION.
Local-storage section.
01 I pic s9(9) binary.
01 P pointer.
01 SAelement pic s9(9) binary.
01 SAelementlen pic s9(9) binary.
01 Sbuffer pic X(50) .
01 rc Pic s9(9) Comp-5.
LINKAGE SECTION.
01 SA PIC S9(9) BINARY.
01 SAlen pic s9(9) binary.
01 ENV-PTR USAGE POINTER.
01 OBJECT-REF PIC S9(9) BINARY.
COPY JNI SUPPRESS.
PROCEDURE DIVISION USING BY VALUE ENV-PTR //two JNI 'hidden' parms
OBJECT-REF
SA
RETURNING SAlen.
Set address of JNIEnv to ENV-PTR
Set address of JNINativeInterface to JNIEnv
Call GetArrayLength using by value ENV-PTR SA
returning SAlen
Display " >> COBOL method entered array len: " SAlen
Perform varying I from 0 by 1 until I = SAlen
Call GetObjectArrayElement
using by value ENV-PTR SA I
returning SAelement
Call "GetStringPlatformLength"
using by value ENV-PTR
SAelement
address of SAelementlen
0
returning rc
Display "Returned from GetStringPlatformLength"
If rc Not = zero Then
Display "Error occurred retrieving len of jstring object"
Stop run
Else
Display "The length of returned string is:"
SAelementlen
End-if
Call "GetStringPlatform"
using by value ENV-PTR
SAelement
address of Sbuffer
length of Sbuffer
0
Display Sbuffer(1:SAelementlen)
End-perform
.
GOBACK.
The following Java program StringTest.java
is compiled and run with the following commands:
/usr/lpp/java/IBM/J7.1/bin/javac StringTest.java
/usr/lpp/java/IBM/J7.1/bin/java -Djava.library.path=. StringTest
StringTest.java
class StringTest
{
static {
System.loadLibrary("StringTest");
}
static native int printStrings(java.lang.String[] SA);
public static void main(String argv[]) throws Exception
{
int i;
String[] a = new String[3];
a[0] = "John";
a[1] = "White";
a[2] = "1234567890";
StringTest st = new StringTest();
i = StringTest.printStrings(a);
System.out.println("Number of elements printStrings read:" +i);
return;
}
}
Example: OO COBOL invoking Java using INVOKE
This example demonstrates how an object-oriented COBOL application invokes a Java program on UNIX System Services (USS).
For COBOL applications calling Java, you need the LIBPATH to point to the path for the Java libraries.
LIBPATH=/usr/lpp/java/IBM/J7.1/bin/classic:$LIBPATH
Also, use the _CEE_RUNOPTS environment variable to set the XPLINK(ON) option :
_CEE_RUNOPTS="XPLINK(ON)"
Exporting _CEE_RUNOPTS=”XPLINK(ON)” so that it is in effect for the entire z/OS UNIX shell session is not recommended, however. Suppose for example that an OO COBOL application starts with a COBOL program called App1. One way to limit the effect of the XPLINK option to the execution of the App1 application is to set the _CEE_RUNOPTS variable on the command-line invocation of App1Driver as follows:
_CEE_RUNOPTS="XPLINK(ON)" App1
The following example demonstrates how an OO COBOL application invokes a Java program by using INVOKE.
The COBOL program is compiled and linked as follows, where a typical installation path for COBOL is /usr/lpp/cobol
and a typical installation path for Java is /usr/lpp/java
. Replace with your own paths for your environment.
/usr/lpp/cobol/bin/cob2 -c -qthread,dll helloTest.cbl
/usr/lpp/cobol/bin/cob2 -bdll helloTest.cbl -o hello /usr/lpp/java/IBM/J7.1/bin/j9vm/libjvm.x /usr/lpp/cobol/lib/igzcjava.x -I /usr/lpp/cobol/include
helloTest.cbl
Process thread,pgmname(longmixed)
IDENTIFICATION DIVISION.
PROGRAM-ID. "HELLOWORLD" is recursive.
*
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SOURCE-COMPUTER. RM-COBOL.
OBJECT-COMPUTER. RM-COBOL.
Repository.
Class HelloJ is "HelloJ".
DATA DIVISION.
FILE SECTION.
PROCEDURE DIVISION.
MAIN-LOGIC SECTION.
BEGIN.
DISPLAY " " .
INVOKE HelloJ "sayHello".
DISPLAY "Hello world!".
STOP RUN.
MAIN-LOGIC-EXIT.
EXIT.
The following HelloJ.java
program is compiled and exported by using the following commands in USS:
/usr/lpp/java/IBM/J7.1/bin/javac HelloJ.java
export _CEE_RUNOPTS="XPLINK(ON)"
export LIBPATH=/usr/lpp/java/IBM/J7.1/bin:/usr/lpp/java/IBM/J7.1/bin/classic:$LIBPATH
export CLASSPATH=:$CLASSPATH
HelloJ.java
class HelloJ {
public static void sayHello() {
System.out.println("Hello World, from Java!");
}
}
Was this topic helpful?
Document Information
Modified date:
22 February 2023
UID
ibm16320801